diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/CREDITS linux-2.4.21-rc3/CREDITS
--- linux-2.4.20/CREDITS	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/CREDITS	2003-05-22 22:06:27.000000000 +0000
@@ -733,7 +733,7 @@
 D: Dell PowerEdge server, SCSI layer, misc drivers, and other patches
 S: Dell Computer Corporation
 S: One Dell Way
-S: Round Rock, TX  78681
+S: Round Rock, TX  78682
 S: USA
 
 N: Eddie C. Dost
@@ -1008,7 +1008,7 @@
 S: USA
 
 N: Jeff Garzik
-E: jgarzik@mandrakesoft.com
+E: jgarzik@pobox.com
 
 N: Jacques Gelinas
 E: jacques@solucorp.qc.ca
@@ -1065,6 +1065,11 @@
 D: Transformed old user space bdflush into 1st kernel thread - kflushd.
 D: Many other patches, documentation files, mini kernels, utilities, ...
 
+N: Masanori GOTO
+E: gotom@debian.or.jp
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: John E. Gotts
 E: jgotts@linuxsavvy.com
 D: kernel hacker
@@ -1169,6 +1174,10 @@
 S: Atlanta, Georgia 30332
 S: USA
 
+N: Brad Hards
+E: bradh@frogmouth.net
+D: Various USB bits, other minor patches
+
 N: Angelo Haritsis
 E: ah@computer.org
 D: kernel patches (serial, watchdog)
@@ -1231,16 +1240,18 @@
 
 N: Christoph Hellwig
 E: hch@infradead.org
-D: misc driver & makefile hacking
+E: hch@sgi.com
+D: all kinds of driver, filesystem & core kernel hacking
 D: freevxfs driver
 D: sysvfs maintainer
-S: Triftstraße 26
-S: 38644 Goslar
+D: chief codingstyle nitpicker
+S: Auweg 38
+S: 85748 Garching
 S: Germany
 
 N: Richard Henderson
 E: rth@twiddle.net
-E: rth@cygnus.com
+E: rth@redhat.com
 D: Alpha hacker, kernel and userland
 S: 1668 California St.
 S: Mountain View, California 94041
@@ -1488,7 +1499,7 @@
 S: United Kingdom
 
 N: Ani Joshi
-E: ajoshi@shell.unixbox.com
+E: ajoshi@kernel.crashing.org
 D: fbdev hacking
 
 N: Bernhard Kaindl
@@ -1888,7 +1899,8 @@
 E: pavel@ucw.cz
 E: pavel@suse.cz
 D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
-D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB
+D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB,
+D: x86-64 port, software suspend
 S: Volkova 1131
 S: 198 00 Praha 9
 S: Czech Republic
@@ -1920,6 +1932,11 @@
 E: Kai.Makisara@metla.fi
 D: SCSI Tape Driver
 
+N: Dan Malek
+E: dan@mvista.com
+D: PowerPC 8xx, 4xx work.
+S: USA
+
 N: Asit Mallick
 E: asit.k.mallick@intel.com
 D: Linux/IA-64
@@ -2210,11 +2227,12 @@
 S: United Kingdom
 
 N: Ian S. Nelson
-E: ian.nelson@echostar.com
+E: nelsonis@earthlink.net
 D: Minor mmap and ide hacks
 S: 1370 Atlantis Ave.
 S: Lafayette CO, 80026
 S: USA
+P: 1024D/DD478240 4073 9AF8 027F 278D CBBB  DA3C 9905 0415 DD47 8240
 
 N: Russell Nelson
 E: nelson@crynwr.com
@@ -2226,6 +2244,15 @@
 S: Potsdam, New York 13676
 S: USA
 
+N: Dave Neuer
+E: dneuer@innovation-charter.com
+E: mr_fred_smoothie@yahoo.com
+D: Helped implement support for Compaq's H31xx series iPAQs
+D: Other mostly minor tweaks & bugfixes
+S: 325 E. Main St., Suite 3
+S: Carnegie, PA 15105
+S: USA
+
 N: Michael Neuffer
 E: mike@i-Connect.Net
 E: neuffer@goofy.zdv.uni-mainz.de
@@ -2397,18 +2424,24 @@
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
 
 N: Stelian Pop
-E: stelian.pop@fr.alcove.com
+E: stelian@popies.net
 P: 1024D/EDBB6147 7B36 0E07 04BC 11DC A7A0  D3F7 7185 9E7A EDBB 6147
 D: sonypi, meye drivers, mct_u232 usb serial hacks
-S: Alcôve
-S: 153, bd. Anatole France 
-S: 93200 Saint Denis
-S: France
+S: Paris, France
 
 N: Frederic Potter 
 E: fpotter@cirpack.com
 D: Some PCI kernel support
 
+N: Matt Porter
+E: porter@cox.net
+E: mporter@mvista.com
+D: Motorola PowerPC PReP support
+D: cPCI PowerPC support
+D: Embedded PowerPC 440/6xx/7xx/74xx support
+S: Chandler, Arizona 85249
+S: USA
+
 N: Rui Prior
 E: rprior@inescn.pt
 D: ATM device driver for NICStAR based cards
@@ -2520,6 +2553,12 @@
 S: 70110 Kuopio
 S: Finland
 
+N: Tom Rini
+E: trini@kernel.crashing.org
+D: Lots of PowerPC cleanups, minor matroxfb work
+S: Tucson, Arizona
+S: USA
+
 N: William E. Roadcap
 E: roadcapw@cfw.com
 W: http://www.cfw.com/~roadcapw
@@ -3282,6 +3321,12 @@
 S: Socorro NM, 87801
 S: USA
 
+N: Hiroshi YOKOTA
+E: yokota@netlab.is.tsukuba.ac.jp
+D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: Eric Youngdale
 E: eric@andante.org
 W: http://www.andante.org
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/00-INDEX linux-2.4.21-rc3/Documentation/BK-usage/00-INDEX
--- linux-2.4.20/Documentation/BK-usage/00-INDEX	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/BK-usage/00-INDEX	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,38 @@
+bk-kernel-howto.txt: Description of kernel workflow under BitKeeper
+
+bk-make-sum: Create summary of changesets in one repository and not
+another, typically in preparation to be sent to an upstream maintainer.
+Typical usage:
+	cd my-updated-repo
+	bk-make-sum ~/repo/original-repo
+	mv /tmp/linus.txt ../original-repo.txt
+
+bksend: Create readable text output containing summary of changes, GNU
+patch of the changes, and BK metadata of changes (as needed for proper
+importing into BitKeeper by an upstream maintainer).  This output is
+suitable for emailing BitKeeper changes.  The recipient of this output
+may pipe it directly to 'bk receive'.
+
+bz64wrap: helper script. Uncompressed input is piped to this script,
+which compresses its input, and then outputs the uu-/base64-encoded
+version of the compressed input.
+
+csets-to-patches: Produces a delta of two BK repositories, in the form
+of individual files, each containing a single cset as a GNU patch.
+Output is several files, each with the filename "/tmp/rev-$REV.patch"
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl csets-to-patches
+
+cset-to-linus: Produces a delta of two BK repositories, in the form of
+changeset descriptions, with 'diffstat' output created for each
+individual changset.
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl cset-to-linus > summary.txt
+
+unbz64wrap: Reverse an encoded, compressed data stream created by
+bz64wrap into an uncompressed, typically text/plain output.
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt linux-2.4.21-rc3/Documentation/BK-usage/bk-kernel-howto.txt
--- linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/BK-usage/bk-kernel-howto.txt	2003-05-22 22:06:42.000000000 +0000
@@ -32,7 +32,7 @@
 
 Let's start with this progression:
 Each BitKeeper source tree on disk is a repository unto itself.
-Each repository has a parent.
+Each repository has a parent (except the root/original, of course).
 Each repository contains a set of a changesets ("csets").
 Each cset is one or more changed files, bundled together.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/Configure.help linux-2.4.21-rc3/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/Configure.help	2003-05-22 22:06:52.000000000 +0000
@@ -246,14 +246,22 @@
 
   If unsure, say N.
 
-Multiquad support for NUMA systems
-CONFIG_MULTIQUAD
+Multiquad support for NUMAQ systems
+CONFIG_X86_NUMAQ
   This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
   multiquad box. This changes the way that processors are bootstrapped,
   and uses Clustered Logical APIC addressing mode instead of Flat Logical.
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
+Support for IBM Summit (EXA) systems
+CONFIG_X86_SUMMIT
+  This option is needed for IBM systems that use the Summit/EXA chipset.
+  (EXA: Extendable Xseries Architecture)In particular, it is needed for 
+  the x440 (even for the 4-CPU model).
+
+  If you don't have this computer, you may safely say N.
+
 IO-APIC support on uniprocessors
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
@@ -1033,7 +1041,7 @@
 
 Pacific Digital A-DMA support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC_ADMA
-  Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
+  Please read the comments at the top of <file:drivers/ide/setup-pci.c>.
 
 3ware Hardware ATA-RAID support
 CONFIG_BLK_DEV_3W_XXXX_RAID
@@ -1063,13 +1071,13 @@
   The ATP860 is an UltraDMA 66 chipset base.
   The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
 
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/aec62xx.c>.
   If you say Y here, then say Y to "Use DMA by default when available"
   as well.
 
 AEC62XX Tuning support
 CONFIG_AEC62XX_TUNING
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/aec62xx.c>.
   If unsure, say N.
 
 ALI M15x3 chipset support
@@ -1080,7 +1088,7 @@
 
   If you say Y here, you also need to say Y to "Use DMA by default
   when available", above.  Please read the comments at the top of
-  <file:drivers/ide/alim15x3.c>.
+  <file:drivers/ide/pci/alim15x3.c>.
 
   If unsure, say N.
 
@@ -1097,14 +1105,16 @@
 
   SAY N!
 
-AMD Viper (7401/7409/7411) chipset support
+AMD and nVidia IDE support
 CONFIG_BLK_DEV_AMD74XX
-  This driver ensures (U)DMA support for the AMD756/760 Viper
-  chipsets.
+  This driver adds explicit support for AMD-7xx and AMD-8111 chips
+  and also for the nVidia nForce chip.  This allows the kernel to
+  change PIO, DMA and UDMA speeds and to configure the chip to
+  optimum performance.
 
   If you say Y here, you also need to say Y to "Use DMA by default
   when available", above.
-  Please read the comments at the top of <file:drivers/ide/amd74xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/amd74xx.c>.
 
   If unsure, say N.
 
@@ -1114,10 +1124,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X and CMD680 chipset support
+CMD64X/CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
+  chipsets: CMD643, CMD646 and CMD648.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1148,16 +1158,18 @@
 HPT34X AUTODMA support (WIP)
 CONFIG_HPT34X_AUTODMA
   This is a dangerous thing to attempt currently! Please read the
-  comments at the top of <file:drivers/ide/hpt34x.c>.  If you say Y
+  comments at the top of <file:drivers/ide/pci/hpt34x.c>.  If you say Y
   here, then say Y to "Use DMA by default when available" as well.
 
   If unsure, say N.
 
-HPT366/368/370 chipset support
+HPT36X/37X chipset support
 CONFIG_BLK_DEV_HPT366
   HPT366 is an Ultra DMA chipset for ATA-66.
   HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
   HPT370 is an Ultra DMA chipset for ATA-100.
+  HPT372 is an Ultra DMA chipset for ATA-133.
+  HPT374 is an Ultra DMA chipset for ATA-133.
 
   This driver adds up to 4 more EIDE devices sharing a single
   interrupt.
@@ -1179,12 +1191,12 @@
   This driver adds detection and support for the NS87415 chip
   (used in SPARC64, among others).
 
-  Please read the comments at the top of <file:drivers/ide/ns87415.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
 
 OPTi 82C621 chipset enhanced support (EXPERIMENTAL)
 CONFIG_BLK_DEV_OPTI621
   This is a driver for the OPTi 82C621 EIDE controller.
-  Please read the comments at the top of <file:drivers/ide/opti621.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
 
 ServerWorks OSB4/CSB5 chipset support
 CONFIG_BLK_DEV_SVWKS
@@ -1198,7 +1210,7 @@
   PIO 0-4 mode settings, this allows dynamic tuning of the chipset
   via the standard end-user tool 'hdparm'.
 
-  Please read the comments at the top of <file:drivers/ide/piix.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/piix.c>.
 
   If you say Y here, you should also say Y to "PIIXn Tuning support",
   below.
@@ -1218,7 +1230,7 @@
   If unsure, say N.
 
 PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support
-CONFIG_BLK_DEV_PDC202XX
+CONFIG_BLK_DEV_PDC202XX_OLD
   Promise Ultra33 or PDC20246
   Promise Ultra66 or PDC20262
   Promise Ultra100 or PDC20265/PDC20267/PDC20268
@@ -1236,7 +1248,7 @@
   available" as well.
 
   Please read the comments at the top of
-  <file:drivers/ide/pdc202xx.c>.
+  <file:drivers/ide/pci/pdc202xx_old.c>.
 
   If unsure, say N.
 
@@ -1251,7 +1263,7 @@
   when the PDC20265 BIOS has been disabled (for faster boot up).
 
   Please read the comments at the top of
-  <file:drivers/ide/pdc202xx.c>.
+  <file:drivers/ide/pci/pdc202xx_old.c>.
 
   If unsure, say N.
 
@@ -1274,7 +1286,12 @@
   If you say Y here, you need to say Y to "Use DMA by default when
   available" as well.
 
-  Please read the comments at the top of <file:drivers/ide/sis5513.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+
+Silicon Image chipset support
+CONFIG_BLK_DEV_SIIMAGE
+  This driver provides (U)DMA support for the SII3112 SATA controllers and
+  for the CMD/SI680 UDMA/DMA ATA controller.
 
 SLC90E66 chipset support
 CONFIG_BLK_DEV_SLC90E66
@@ -1288,7 +1305,7 @@
   available" as well.
 
   Please read the comments at the top of
-  <file:drivers/ide/slc90e66.c>.
+  <file:drivers/ide/pci/slc90e66.c>.
 
 Winbond SL82c105 support
 CONFIG_BLK_DEV_SL82C105
@@ -1301,7 +1318,7 @@
   This driver adds support for bus master DMA transfers
   using the Tekram TRM290 PCI IDE chip. Volunteers are
   needed for further tweaking and development.
-  Please read the comments at the top of <file:drivers/ide/trm290.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
 
 VIA82CXXX chipset support
 CONFIG_BLK_DEV_VIA82CXXX
@@ -1313,7 +1330,7 @@
   system" support.
 
   Please read the comments at the top of
-  <file:drivers/ide/via82cxxx.c>.
+  <file:drivers/ide/pci/via82cxxx.c>.
 
   If you say Y here, then say Y to "Use DMA by default when available"
   as well.
@@ -1353,7 +1370,7 @@
   boot parameter.  It enables support for the secondary IDE interface
   of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
   I/O speeds to be set as well.  See the files
-  <file:Documentation/ide.txt> and <file:drivers/ide/ali14xx.c> for
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for
   more info.
 
 DTC-2278 support
@@ -1362,7 +1379,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the DTC-2278 card, and permits faster I/O speeds to be set as
   well. See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/dtc2278.c> files for more info.
+  <file:drivers/ide/legacy/dtc2278.c> files for more info.
 
 Holtek HT6560B support
 CONFIG_BLK_DEV_HT6560B
@@ -1370,7 +1387,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the Holtek card, and permits faster I/O speeds to be set as well.
   See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/ht6560b.c> files for more info.
+  <file:drivers/ide/legacy/ht6560b.c> files for more info.
 
 PROMISE DC4030 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC4030
@@ -1380,14 +1397,14 @@
   attached to the secondary interface.  CD-ROM and TAPE devices are
   not supported yet.  This driver is enabled at runtime using the
   "ide0=dc4030" kernel boot parameter.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/pdc4030.c> files
   for more info.
 
 QDI QD65XX support
 CONFIG_BLK_DEV_QD65XX
   This driver is enabled at runtime using the "ide0=qd65xx" kernel
   boot parameter.  It permits faster I/O speeds to be set.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/qd65xx.c> for
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
   more info.
 
 UMC 8672 support
@@ -1396,7 +1413,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the UMC-8672, and permits faster I/O speeds to be set as well.
   See the files <file:Documentation/ide.txt> and
-  <file:drivers/ide/umc8672.c> for more info.
+  <file:drivers/ide/legacy/umc8672.c> for more info.
 
 Amiga Gayle IDE interface support
 CONFIG_BLK_DEV_GAYLE
@@ -2508,6 +2525,19 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Amanda protocol support
+CONFIG_IP_NF_AMANDA
+  If you are running the Amanda backup package (http://www.amanda.org/)
+  on this machine or machines that will be MASQUERADED through this
+  machine, then you may want to enable this feature.  This allows the
+  connection tracking and natting code to allow the sub-channels that
+  Amanda requires for communication of the backup data, messages and
+  index.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+
 IRC Send/Chat protocol support
 CONFIG_IP_NF_IRC
   There is a commonly-used extension to IRC called
@@ -2522,6 +2552,16 @@
   If you want to compile it as a module, say 'M' here and read
   Documentation/modules.txt.  If unsure, say 'N'.
 
+TFTP protocol support
+CONFIG_IP_NF_TFTP
+  TFTP connection tracking helper, this is required depending
+  on how restrictive your ruleset is.
+  If you are using a tftp client behind -j SNAT or -j MASQUERADING
+  you will need this.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `Y'.
+
 FTP protocol support
 CONFIG_IP_NF_FTP
   Tracking FTP connections is problematic: special helpers are
@@ -3543,6 +3583,13 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_AMD_8151
+  This option gives you AGP support for the GLX component of
+  XFree86 on AMD K8 with an AGP 8151 chipset.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
 Generic SiS support
 CONFIG_AGP_SIS
   This option gives you AGP support for the GLX component of the "soon
@@ -4155,6 +4202,7 @@
    - "Winchip-2" for IDT Winchip 2.
    - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
    - "CyrixIII" for VIA Cyrix III or VIA C3.
+   - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above).
 
   If you don't know what to do, choose "386".
 
@@ -4176,6 +4224,13 @@
   Select this for a Pentium Classic processor with the RDTSC (Read
   Time Stamp Counter) instruction for benchmarking.
 
+VIA C3-2 (Nehemiah)
+CONFIG_MVIAC3_2
+  Select this for a VIA C3 "Nehemiah". Selecting this enables usage of SSE
+  and tells gcc to treat the CPU as a 686.
+
+  Note, this kernel will not boot on older (pre model 9) C3s.
+
 32-bit PDC
 CONFIG_PDC_NARROW
   Saying Y here will allow developers with a C180, C200, C240, C360,
@@ -4416,7 +4471,7 @@
 
   The driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want). The
-  module will be called rivafb.o. If you want to compile it as a
+  module will be called tridentfb.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 ATI Mach64 display support
@@ -4563,14 +4618,11 @@
   BIOS routines contained in a ROM chip in HP PA-RISC based machines.
   Enabling this option will implement the linux framebuffer device and
   an fbcon color text console using calls to the STI BIOS routines.
-  The HP framebuffer device is usually planar, uses a strange memory
+  The HP framebuffer device is sometimes planar, using a strange memory
   layout, and changing the plane mask to create colored pixels
-  requires a call to the STI routines, so do not expect /dev/fb to
-  actually be useful.  However, it is the best we have as far as
-  graphics on the HP chipsets due to lack of hardware level
-  documentation for the various on-board HP chipsets used in these
-  systems.  It is sufficient for basic text console functions,
-  including fonts.
+  can require a call to the STI routines, so /dev/fb may not actually 
+  be useful.  However, on some systems packed pixel formats are supported.  
+  It is sufficient for basic text console functions, including fonts.
 
   You should probably enable this option, unless you are having
   trouble getting video when booting the kernel (make sure it isn't
@@ -7907,6 +7959,17 @@
 
   The common answer here is N, but answering Y is safe.
 
+Workbit NinjaSCSI-32Bi/UDE support
+CONFIG_SCSI_NSP32
+  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called nsp32.o.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   This is support for the IBM SCSI adapter found in many of the PS/2
@@ -10816,6 +10879,15 @@
   say M here and read <file:Documentation/modules.txt>.  This is
   recommended.  The module will be called yellowfin.o.
 
+Realtek 8169 Gigabit Ethernet support
+CONFIG_R8169
+  Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called r8169.o.
+
 General Instruments Surfboard 1000
 CONFIG_NET_SB1000
   This is a driver for the General Instrument (also known as
@@ -10875,31 +10947,41 @@
 
   The safe and default value for this is N.
 
-SysKonnect SK-98xx support
+SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter family support
 CONFIG_SK98LIN
-  Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server
-  Adapter. The following adapters are supported by this driver:
-  - SK-9841 (single link 1000Base-LX)
-  - SK-9842 (dual link   1000Base-LX)
-  - SK-9843 (single link 1000Base-SX)
-  - SK-9844 (dual link   1000Base-SX)
-  - SK-9821 (single link 1000Base-T)
-  - SK-9822 (dual link   1000Base-T)
-  - SK-9861 (single link Volition connector)
-  - SK-9862 (dual link   Volition connector)
-  The driver also supports the following adapters from Allied Telesyn:
-  - AT2970...
-
-  The dual link adapters support a link-failover feature.  Read
-  <file:Documentation/networking/sk98lin.txt> for information about
+  Say Y here if you have a SysKonnect SK-98xx or SK-95xx Gigabit 
+  Ethernet Server Adapter. The following adapters are supported by 
+  this driver:
+  - SK-9521 10/100/1000Base-T Adapter
+  - SK-9821 Gigabit Ethernet 1000Base-T Server Adapter
+  - SK-9822 Gigabit Ethernet 1000Base-T Dual Port Server Adapter
+  - SK-9841 Gigabit Ethernet 1000Base-LX Server Adapter
+  - SK-9842 Gigabit Ethernet 1000Base-LX Dual Port Server Adapter
+  - SK-9843 Gigabit Ethernet 1000Base-SX Server Adapter
+  - SK-9844 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+  - SK-9861 Gigabit Ethernet 1000Base-SX Server Adapter
+  - SK-9862 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+  - SK-9871 Gigabit Ethernet 1000Base-ZX Server Adapter
+  - SK-9872 Gigabit Ethernet 1000Base-ZX Dual Port Server Adapter
+  - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+  - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+  - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+
+  The adapters support Jumbo Frames.
+  The dual link adapters support link-failover and dual port features.
+  The V2.0 adapters support the scatter-gather functionality with
+  sendfile(). Read Documentation/networking/sk98lin.txt for information about
   optional driver parameters.
   Questions concerning this driver may be addressed to:
     linux@syskonnect.de
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called sk98lin.o.
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called sk98lin.o.
 
 Sun GEM support
 CONFIG_SUNGEM
@@ -11038,6 +11120,7 @@
      82544       PRO/1000 XF Server Adapter           A50484-xxx
      82544       PRO/1000 T Desktop Adapter           A62947-xxx
      82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+     82541       PRO/1000 MT Desktop Adapter          C91016-xxx
      82545       PRO/1000 MT Server Adapter           A92165-xxx
      82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
      82545       PRO/1000 MF Server Adapter           A91622-xxx
@@ -11227,6 +11310,24 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called 3c59x.o.
 
+3cr990 series "Typhoon" support
+CONFIG_TYPHOON
+  This option enables driver support for the 3cr990 series of cards:
+
+  3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
+  3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
+  3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
+
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called typhoon.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 Other ISA cards
 CONFIG_NET_ISA
   If your network (Ethernet) card hasn't been mentioned yet and its
@@ -11644,6 +11745,18 @@
   module, say M here and read <file:Documentation/modules.txt> as well
   as <file:Documentation/networking/net-modules.txt>.
 
+AMD 8111 (new PCI lance) support
+CONFIG_AMD8111_ETH
+  If you have an AMD 8111-based PCI lance ethernet card,
+  answer Y here and read the Ethernet-HOWTO, available from
+  <http://www.tldp.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called amd8111e.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
@@ -11771,6 +11884,13 @@
   a module, say M here and read <file:Documentation/modules.txt> as
   well as <file:Documentation/networking/net-modules.txt>.
 
+Use PIO instead of MMIO
+CONFIG_EEPRO100_PIO
+  This instructs the driver to use programmed I/O ports (PIO) instead
+  of PCI shared memory (MMIO).  This can possibly solve some problems
+  in case your mainboard has memory consistency issues.  If unsure,
+  say N.
+
 Enable Power Management
 CONFIG_EEPRO100_PM
   Many Intel EtherExpress PRO/100 PCI network cards are capable
@@ -13764,6 +13884,21 @@
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+Griffin Technology PowerMate support
+CONFIG_USB_POWERMATE
+  Say Y here if you want to use the Griffin Technology, Inc. USB
+  PowerMate device. This device is an aluminum dial which can
+  measure clockwise and anticlockwise rotation. The dial also
+  acts as a pushbutton. The base contains an LED which can be
+  instructed to pulse or to switch to a particular intensity.
+
+  You can download userspace tools from http://sowerbutts.com/powermate/
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called powermate.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 Aiptek 6000U/8000U tablet support
 CONFIG_USB_AIPTEK
   Say Y here if you want to use the USB version of the Aiptek 6000U/8000U
@@ -13858,8 +13993,8 @@
 USB Scanner support
 CONFIG_USB_SCANNER
   Say Y here if you want to connect a USB scanner to your computer's
-  USB port. Please read <file:Documentation/usb/scanner.txt> and
-  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
+  USB port. Please read <file:Documentation/usb/scanner.txt> for more
+  information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -13955,10 +14090,10 @@
   The module will be called visor.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-USB Compaq iPAQ Driver
+USB PocketPC PDA Driver
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada 548/568
-  or Casio EM500 running Windows CE 3.0 or PocketPC 2002 using a USB
+  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada,
+  or any other PDA running Windows CE 3.0 or PocketPC 2002 using a USB
   cradle/cable. For information on using the driver,
   read <file:Documentation/usb/usb-serial.txt>.
 
@@ -14145,6 +14280,17 @@
   The module will be called pl2303.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB KOBIL chipcard reader
+CONFIG_USB_SERIAL_KOBIL_SCT
+  Say Y here if you want to use one of the following KOBIL USB chipcard 
+  readers: TWIN, KAAN Standard Plus, SecOVID Reader Plus, B1 PRO, KAAN PRO
+
+  Note that you need a current CT-API.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kobil_sct.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB REINER SCT cyberJack pinpad/e-com chipcard reader
 CONFIG_USB_SERIAL_CYBERJACK
   Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
@@ -14235,6 +14381,21 @@
   you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
   learn more.
 
+CONFIG_USB_KONICAWC
+  Say Y here if you want support for webcams based on a Konica
+  chipset. This is known to work with the Intel YC76 webcam.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called konicawc.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB OV511 Camera support
 CONFIG_USB_OV511
   Say Y here if you want to connect this type of camera to your
@@ -14361,7 +14522,7 @@
   If in doubt then look at linux/drivers/usb/pegasus.h for the complete
   list of supported devices.
   If your particular adapter is not in the list and you are _sure_ it
-  is Pegasus or Pegasus-II based then send me (pmanolov@users.sourceforge.net)
+  is Pegasus or Pegasus-II based then send me (petkan@users.sourceforge.net)
   vendor and device IDs.
   
   This code is also available as a module ( = code which can be
@@ -14620,7 +14781,7 @@
   The module will be called rio500.o. If you want to compile it as
   a module, say M here and read <file:Documenatation/modules.txt>.
 
-USB Auerswald ISDN device support
+Auerswald device support
 CONFIG_USB_AUERSWALD
   Say Y here if you want to connect an Auerswald USB ISDN Device
   to your computer's USB port.
@@ -14630,8 +14791,18 @@
   The module will be called auerswald.o. If you want to compile it as
   a module, say M here and read <file:Documenatation/modules.txt>
 
+USB Auerswald ISDN modem support
+CONFIG_USB_AUERISDN
+  Say Y here if you want to enable the ISDN modem option
+  of your Auerswald ISDN devices. 
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documenatation/modules.txt>
+
 CONFIG_USB_TIGL
-  If you own a Texas Instruments graphing calculator and use a 
+  If you own a Texas Instruments graphing calculator and use a
   TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
   interested in this driver.
 
@@ -14649,6 +14820,28 @@
 
   If unsure, say N.
 
+Texas Instruments parallel link cable support
+CONFIG_TIPAR
+  If you own a Texas Instruments graphing calculator and use a
+  parallel link cable, then you might be interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev. The
+  main advantage of this driver is that you don't have to be root
+  to use this precise link cable (depending on the permissions on
+  the device nodes, though).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tipar.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>
+
+  If you don't know what a parallel link cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
   Say Y here if you want to use the Voyager USB Braille display from
@@ -14949,8 +15142,7 @@
 CONFIG_USB_BLUETOOTH
   Say Y here if you want to connect a USB Bluetooth device to your
   computer's USB port. You will need the Bluetooth stack (available
-  at <http://developer.axis.com/software/index.shtml>) to fully use
-  the device.
+  at <http://developer.axis.com/software>) to fully use the device.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -18959,6 +19151,34 @@
   The module is called rtc.o. If you want to compile it as a module,
   say M here and read <file:Documentation/modules.txt>.
 
+Generic Real Time Clock Support
+CONFIG_GEN_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  In 2.4 and later kernels this is the only way to set and get rtc
+  time on m68k systems so it is highly recommended.
+
+  It reports status information via the file /proc/driver/rtc and its 
+  behaviour is set by various ioctls on /dev/rtc. If you enable the
+  "extended RTC operation" below it will also provide an emulation
+  for RTC_UIE which is required by some programs and may improve
+  precision in some cases.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called genrtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>. To load the
+  module automatically add 'alias char-major-10-135 genrtc' to your
+  /etc/modules.conf
+
+Extended RTC operation
+CONFIG_GEN_RTC_X
+  Provides an emulation for RTC_UIE which is required by some programs 
+  and may improve precision of the generic RTC support in some cases.
+
 Tadpole ANA H8 Support
 CONFIG_H8
   The Hitachi H8/337 is a microcontroller used to deal with the power
@@ -19052,10 +19272,11 @@
   The module will be called cs461x.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aureal Vortex and Trident 4DWave gameports
+Aureal Vortex, Trident 4DWave, and ALi 5451 gameports
 CONFIG_INPUT_PCIGAME
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
+  card or an ALi 5451 chip on your motherboard. For more information
+  on how to use the driver please read
   <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
@@ -21278,6 +21499,8 @@
                HCI Device drivers (interface to the hardware)
                L2CAP Module (L2CAP protocol)
                SCO Module (SCO links)
+               RFCOMM Module (RFCOMM protocol)
+               BNEP Module (BNEP protocol)
 
   Say Y here to enable Linux Bluetooth support and to build BlueZ Core
   layer.
@@ -21306,6 +21529,19 @@
   Say Y here to compile SCO support into the kernel or say M to
   compile it as module (sco.o).
 
+RFCOMM protocol support
+CONFIG_BLUEZ_RFCOMM
+  RFCOMM provides connection oriented stream transport. RFCOMM
+  support is required for Dialup Networking, OBEX and other Bluetooth
+  applications.
+
+  Say Y here to compile RFCOMM support into the kernel or say M to
+  compile it as module (rfcomm.o).
+
+RFCOMM TTY emulation support
+CONFIG_BLUEZ_RFCOMM_TTY
+  This option enables TTY emulation support for RFCOMM channels.
+
 BNEP protocol support
 CONFIG_BLUEZ_BNEP
   BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
@@ -21319,6 +21555,14 @@
   Say Y here to compile BNEP support into the kernel or say M to
   compile it as module (bnep.o).
 
+BNEP multicast filter support
+CONFIG_BLUEZ_BNEP_MC_FILTER
+  This option enables the multicast filter support for BNEP.
+
+BNEP protocol filter support
+CONFIG_BLUEZ_BNEP_PROTO_FILTER
+  This option enables the protocol filter support for BNEP.
+
 HCI UART driver
 CONFIG_BLUEZ_HCIUART
   Bluetooth HCI UART driver.
@@ -21333,11 +21577,26 @@
 HCI UART (H4) protocol support 
 CONFIG_BLUEZ_HCIUART_H4
   UART (H4) is serial protocol for communication between Bluetooth 
-  device and host. This protocol is required for most UART based 
-  Bluetooth device (including PCMCIA and CF). 
+  device and host. This protocol is required for most Bluetooth devices 
+  with UART interface, including PCMCIA and CF cards. 
 
   Say Y here to compile support for HCI UART (H4) protocol.
 
+HCI BCSP protocol support 
+CONFIG_BLUEZ_HCIUART_BCSP
+  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
+  between Bluetooth device and host. This protocol is required for non
+  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
+  CF cards.
+
+  Say Y here to compile support for HCI BCSP protocol.
+
+HCI BCSP transmit CRC with every BCSP packet
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+  If you say Y here, a 16-bit CRC checksum will be transmitted along with
+  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
+  This increases reliability, but slightly reduces efficiency.
+
 HCI USB driver
 CONFIG_BLUEZ_HCIUSB
   Bluetooth HCI USB driver.
@@ -21347,12 +21606,21 @@
   Say Y here to compile support for Bluetooth USB devices into the
   kernel or say M to compile it as module (hci_usb.o).
 
+HCI USB SCO (voice) support
+CONFIG_BLUEZ_USB_SCO
+  This option enables the SCO support in the HCI USB driver. You need this
+  to transmit voice data with your Bluetooth USB device. And your device
+  must also support sending SCO data over the HCI layer, because some of
+  them sends the SCO data to an internal PCM adapter.
+ 
+  Say Y here to compile support for HCI SCO data.
+ 
 HCI USB zero packet support
 CONFIG_BLUEZ_USB_ZERO_PACKET
-  Support for USB zero packets.
   This option is provided only as a work around for buggy Bluetooth USB 
-  devices. Do _not_ enable it unless you know for sure that your device 
+  devices. Do NOT enable it unless you know for sure that your device 
   requires zero packets.
+ 
   Most people should say N here.
 
 HCI VHCI Virtual HCI device driver
@@ -21399,6 +21667,20 @@
   Say Y here to compile support for HCI BlueCard devices into the
   kernel or say M to compile it as module (bluecard_cs.o).
 
+HCI UART (PC Card) device driver
+CONFIG_BLUEZ_HCIBTUART
+  Bluetooth HCI UART (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  an UART interface:
+     Xircom CreditCard Bluetooth Adapter
+     Xircom RealPort2 Bluetooth Adapter
+     Sphinx PICO Card
+     H-Soft blue+Card
+     Cyber-blue Compact Flash Card
+
+  Say Y here to compile support for HCI UART devices into the
+  kernel or say M to compile it as module (btuart_cs.o).
+
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
@@ -21884,8 +22166,8 @@
 Sun3 NCR5380 SCSI
 CONFIG_SUN3_SCSI
   This option will enable support for the OBIO (onboard io) NCR5380
-  SCSI controller found in the Sun 3/50 and 3/60.  Note that this
-  driver does not provide support for VME SCSI boards.
+  SCSI controller found in the Sun 3/50 and 3/60, as well as for
+  "Sun3" type VME scsi controllers also based on the NCR5380.
   General Linux information on the Sun 3 series (now discontinued)
   is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
 
@@ -22888,6 +23170,23 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called radio-sf16fmi.o.
 
+SF16FMR2 Radio
+CONFIG_RADIO_SF16FMR2
+  Choose Y here if you have one of these FM radio cards.  If you
+  compile the driver into the kernel and your card is not PnP one, you
+  have to add "sf16fmr2=<io>" to the kernel command line (I/O address is
+  0x284 or 0x384, default 0x384).
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video For Linux API.  Information on
+  this API and pointers to "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called radio-sf16fmr2.o.
+
 Typhoon Radio (a.k.a. EcoRadio)
 CONFIG_RADIO_TYPHOON
   Choose Y here if you have one of these FM radio cards, and then fill
@@ -24413,13 +24712,24 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called ns83820.o.
 
+Toshiba Type-O IR Port device driver (old driver)
+CONFIG_TOSHIBA_OLD
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
+  many more laptops. This driver is obsolete, will no more be
+  maintained and will be removed in favor of the new driver.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called toshoboe.o.
+
 Toshiba Type-O IR Port device driver
 CONFIG_TOSHIBA_FIR
   Say Y here if you want to build support for the Toshiba Type-O IR
-  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
-  many more laptops.  If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called toshoboe.o.
+  and Donau oboe chipsets. These chipsets are used by the Toshiba
+  Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called donauboe.o.
 
 SMC IrCC
 CONFIG_SMC_IRCC_FIR
@@ -25438,16 +25748,6 @@
   for the zx1 IOMMU and makes root bus bridges appear in PCI config space
   (required for zx1 agpgart support).
 
-CONFIG_IA64_SGI_SN_SIM
-  Build a kernel that runs on both the SGI simulator AND on hardware.
-  There is a very slight performance penalty on hardware for including this
-  option.
-
-CONFIG_IA64_SGI_SN_DEBUG
-  This enables addition debug code that helps isolate
-  platform/kernel bugs. There is a small but measurable performance
-  degradation when this option is enabled.
-
 # Choice: pagesize
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
@@ -26181,7 +26481,7 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.  The module
-  will be called amdtp.o.
+  will be called cmp.o.
 
 OHCI-DV I/O support
 CONFIG_IEEE1394_DV1394
@@ -26242,6 +26542,90 @@
 
   If unsure, say N.
 
+NatSemi SCx200 support
+CONFIG_SCx200
+  This provides basic support for the National Semiconductor SCx200
+  processor.  Right now this is just a driver for the GPIO pins.
+
+  If you don't know what to do here, say N.
+
+  This support is also available as a module.  If compiled as a
+  module, it will be called scx200.o.
+
+NatSemi SCx200 Watchdog
+CONFIG_SCx200_WDT
+  Enable the built-in watchdog timer support on the National 
+  Semiconductor SCx200 processors.
+
+  If compiled as a module, it will be called scx200_watchdog.o.
+
+Flash device mapped with DOCCS on NatSemi SCx200
+CONFIG_MTD_SCx200_DOCFLASH
+  Enable support for a flash chip mapped using the DOCCS signal on a
+  National Semiconductor SCx200 processor.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_docflash.o.
+
+NatSemi SCx200 I2C using GPIO pins
+CONFIG_SCx200_GPIO
+  Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_i2c.o.
+
+GPIO pin used for SCL
+CONFIG_SCx200_I2C_SCL
+  Enter the GPIO pin number used for the SCL signal.  This value can
+  also be specified with a module parameter.
+
+GPIO pin used for SDA
+CONFIG_SCx200_I2C_SDA
+  Enter the GPIO pin number used for the SSA signal.  This value can
+  also be specified with a module parameter.
+
+NatSemi SCx200 ACCESS.bus
+CONFIG_SCx200_ACB
+  Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_acb.o.
+
+IPMI top-level message handler
+CONFIG_IPMI_HANDLER
+  This enables the central IPMI message handler, required for IPMI
+  to work.  Note that you must have this enabled to do any other IPMI
+  things.
+
+  IPMI is a standard for managing sensors (temperature,
+  voltage, etc.) in a system.
+
+  See Documentation/IPMI.txt for more details on the driver.
+
+  If unsure, say N.
+
+Generate a panic event to all BMCs on a panic
+CONFIG_IPMI_PANIC_EVENT
+  When a panic occurs, this will cause the IPMI message handler to
+  generate an IPMI event describing the panic to each interface
+  registered with the message handler.
+
+Device interface for IPMI
+CONFIG_IPMI_DEVICE_INTERFACE
+  This provides an IOCTL interface to the IPMI message handler so
+  userland processes may use IPMI.  It supports poll() and select().
+
+IPMI KCS handler
+CONFIG_IPMI_KCS
+  Provides a driver for a KCS-style interface to a BMC.
+
+IPMI Watchdog Timer
+CONFIG_IPMI_WATCHDOG
+  This enables the IPMI watchdog timer.
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/journal-api.tmpl linux-2.4.21-rc3/Documentation/DocBook/journal-api.tmpl
--- linux-2.4.20/Documentation/DocBook/journal-api.tmpl	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/journal-api.tmpl	2003-05-22 22:06:27.000000000 +0000
@@ -196,6 +196,8 @@
 Lock is also providing through journal_{un,}lock_updates(),
 ext3 uses this when it wants a window with a clean and stable fs for a moment.
 eg. 
+</para>
+
 <programlisting>
 
 	journal_lock_updates() //stop new stuff happening..
@@ -204,11 +206,12 @@
 	journal_unlock_updates() // carry on with filesystem use.
 </programlisting>
 
+<para>
 The opportunities for abuse and DOS attacks with this should be obvious,
 if you allow unprivileged userspace to trigger codepaths containing these
 calls.
 
-<para>
+</para>
 </sect1>
 <sect1>
 <title>Summary</title>
@@ -216,9 +219,13 @@
 Using the journal is a matter of wrapping the different context changes,
 being each mount, each modification (transaction) and each changed buffer
 to tell the journalling layer about them.
+</para>
 
+<para>
 Here is a some pseudo code to give you an idea of how it works, as
 an example.
+</para>
+
 <programlisting>
   journal_t* my_jnrl = journal_create();
   journal_init_{dev,inode}(jnrl,...)
@@ -244,6 +251,7 @@
    }
    journal_destroy(my_jrnl);
 </programlisting>
+</sect1>
 
 </chapter>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-api.tmpl linux-2.4.21-rc3/Documentation/DocBook/kernel-api.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-api.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/kernel-api.tmpl	2003-05-22 22:06:24.000000000 +0000
@@ -85,7 +85,11 @@
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
 !Emm/slab.c
-      </sect1>
+     </sect1>
+     <sect1><title>User Space Memory Access</title>
+!Iinclude/asm-i386/uaccess.h
+!Iarch/i386/lib/usercopy.c
+     </sect1>
   </chapter>
 
   <chapter id="proc">
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.21-rc3/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/kernel-hacking.tmpl	2003-05-22 22:06:47.000000000 +0000
@@ -1139,11 +1139,6 @@
     </listitem>
     <listitem>
      <para>
-      Labeled elements
-     </para>
-    </listitem>
-    <listitem>
-     <para>
       typeof
      </para>
     </listitem>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl linux-2.4.21-rc3/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/kernel-locking.tmpl	2003-05-22 22:06:41.000000000 +0000
@@ -1055,10 +1055,8 @@
       Another common problem is deleting timers which restart
       themselves (by calling <function>add_timer()</function> at the end 
       of their timer function).  Because this is a fairly common case 
-      which is prone to races, you can put a call to
-      <function>timer_exit()</function> at the very end of your timer function,
-      and user <function>del_timer_sync()</function> 
-      (<filename class=headerfile>include/linux/timer.h</filename>)
+      which is prone to races, you should use <function>del_timer_sync()</function> 
+      (<filename class=headerfile>include/linux/timer.h</filename>) 
       to handle this case.  It returns the number of times the timer 
       had to be deleted before we finally stopped it from adding itself back 
       in.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl linux-2.4.21-rc3/Documentation/DocBook/mousedrivers.tmpl
--- linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/mousedrivers.tmpl	2003-05-22 22:06:50.000000000 +0000
@@ -153,11 +153,17 @@
 __init ourmouse_init(void)
 {
 
-        if(check_region(OURMOUSE_BASE, 3))
+        if (request_region(OURMOUSE_BASE, 3, "ourmouse") < 0) {
+		printk(KERN_ERR "ourmouse: request_region failed.\n");
                 return -ENODEV;
-        request_region(OURMOUSE_BASE, 3, "ourmouse");
+	}
+
+        if (misc_register(&amp;our_mouse) < 0) {
+		printk(KERN_ERR "ourmouse: cannot register misc device.\n");
+		release_region(OURMOUSE_BASE, 3);
+		return -EBUSY;
+	}
 
-        misc_register(&amp;our_mouse);
         return 0;
 }
   </programlisting>
@@ -177,18 +183,20 @@
     so it is a good idea to obtain a current copy of this file first.
   </para>
   <para>
-    Our code then is fairly simple. We check nobody else has taken our 
-    address space. Having done so we reserve it to ensure nobody stamps 
-    on our device while probing for other ISA bus devices. Such a probe 
-    might confuse our device.
+    Our code then is fairly simple. We reserve our I/O address space with
+    request_region, checking to make sure that it succeeded (i.e. the
+    space wasn't reserved by anyone else). 
   </para>
   <para>
-    Then we tell the misc driver that we wish to own a minor number. We also
+    Then we ask the misc driver to allocate our minor device number. We also
     hand it our name (which is used in 
     <filename class="directory">/proc/misc</filename>) and a set of file 
     operations that are to be used. The file operations work exactly like the 
     file operations you would register for a normal character device. The misc 
     device itself is simply acting as a redirector for requests.
+    Since misc_register can fail, it is important to check for failure
+    and act accordingly (which in the case of a mouse driver is to abort,
+    since you can't use the mouse without a working device node).
   </para>
   <para>
     Next, in order to be able to use and test our code we need to add some 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl linux-2.4.21-rc3/Documentation/DocBook/procfs-guide.tmpl
--- linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl	2001-09-08 19:20:25.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/procfs-guide.tmpl	2003-05-22 22:06:50.000000000 +0000
@@ -99,7 +99,7 @@
 
     <para>
       I'd like to thank Jeff Garzik
-      <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+      <email>jgarzik@pobox.com</email> and Alexander Viro
       <email>viro@math.psu.edu</email> for their input, Tim Waugh
       <email>twaugh@redhat.com</email> for his <ulink
       url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/tulip-user.tmpl linux-2.4.21-rc3/Documentation/DocBook/tulip-user.tmpl
--- linux-2.4.20/Documentation/DocBook/tulip-user.tmpl	2001-10-05 19:06:51.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/tulip-user.tmpl	2003-05-22 22:06:39.000000000 +0000
@@ -10,7 +10,7 @@
     <surname>Garzik</surname>
     <affiliation>
      <address>
-      <email>jgarzik@mandrakesoft.com</email>
+      <email>jgarzik@pobox.com</email>
      </address>
     </affiliation>
    </author>
@@ -57,7 +57,7 @@
     <title>Introduction</title>
 <para>
 The Tulip Ethernet Card Driver
-is maintained by Jeff Garzik (<email>jgarzik@mandrakesoft.com</email>).
+is maintained by Jeff Garzik (<email>jgarzik@pobox.com</email>).
 </para>
 
 <para>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/via-audio.tmpl linux-2.4.21-rc3/Documentation/DocBook/via-audio.tmpl
--- linux-2.4.20/Documentation/DocBook/via-audio.tmpl	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/via-audio.tmpl	2003-05-22 22:06:55.000000000 +0000
@@ -2,7 +2,7 @@
 
 <book id="ViaAudioGuide">
  <bookinfo>
-  <title>Via 686 Audio Driver for Linux</title>
+  <title>Via 686/8233/8235 Audio Driver for Linux</title>
   
   <authorgroup>
    <author>
@@ -54,7 +54,9 @@
   	The Via VT82C686A "super southbridge" chips contain
 	AC97-compatible audio logic which features dual 16-bit stereo
 	PCM sound channels (full duplex), plus a third PCM channel intended for use
-	in hardware-assisted FM synthesis.
+	in hardware-assisted FM synthesis. The VIA VT8233/8235 extends this
+	support to include six channel output and additional record
+	facilities.
   </para>
   <para>
   	The current Linux kernel audio driver for this family of chips
@@ -199,7 +201,9 @@
   <para>
 	This driver by default supports all PCI audio devices which report
 	a vendor id of 0x1106, and a device id of 0x3058.  Subsystem vendor
-	and device ids are not examined.
+	and device ids are not examined. The 8233 support covers all devices
+	with a device id of 0x3059 and vendor id of 0x1106. Again subsystem
+	ids are ignored as they usually hold the AC97 codec vendor information.
   </para>
   <para>
 	GNU indent formatting options:
@@ -224,6 +228,21 @@
   <chapter id="changelog">
       <title>Driver ChangeLog</title>
 
+<sect1 id="version191ac"><title>
+Version 1.9.1-ac
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+    Added VIA 8233/8235 support including six channel support. We don't
+    yet support S/PDIF, EAPD, using the second DSP channel and FM channels
+    as extra dsp devices, or the extra record channel. New features tested
+    on a VIA EPIA-M kindly provided by VIA.
+    </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
 <sect1 id="version191"><title>
 Version 1.9.1
 </title>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/videobook.tmpl linux-2.4.21-rc3/Documentation/DocBook/videobook.tmpl
--- linux-2.4.20/Documentation/DocBook/videobook.tmpl	2001-07-15 23:15:44.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/DocBook/videobook.tmpl	2003-05-22 22:06:53.000000000 +0000
@@ -146,16 +146,17 @@
 
 int __init myradio_init(struct video_init *v)
 {
-        if(check_region(io, MY_IO_SIZE))
+        if(!request_region(io, MY_IO_SIZE, "myradio"))
         {
                 printk(KERN_ERR 
                     "myradio: port 0x%03X is in use.\n", io);
                 return -EBUSY;
         }
 
-        if(video_device_register(&amp;my_radio, VFL_TYPE_RADIO)==-1)
+        if(video_device_register(&amp;my_radio, VFL_TYPE_RADIO)==-1) {
+                release_region(io, MY_IO_SIZE);
                 return -EINVAL;
-        request_region(io, MY_IO_SIZE, "myradio");
+        }		
         return 0;
 }
 
@@ -920,7 +921,7 @@
 
 int __init mycamera_init(struct video_init *v)
 {
-        if(check_region(io, MY_IO_SIZE))
+        if(!request_region(io, MY_IO_SIZE, "mycamera"))
         {
                 printk(KERN_ERR 
                       "mycamera: port 0x%03X is in use.\n", io);
@@ -928,9 +929,10 @@
         }
 
         if(video_device_register(&amp;my_camera, 
-            VFL_TYPE_GRABBER)==-1)
+            VFL_TYPE_GRABBER)==-1) {
+                release_region(io, MY_IO_SIZE);
                 return -EINVAL;
-        request_region(io, MY_IO_SIZE, "mycamera");
+        }
         return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/IPMI.txt linux-2.4.21-rc3/Documentation/IPMI.txt
--- linux-2.4.20/Documentation/IPMI.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/IPMI.txt	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,364 @@
+
+                          The Linux IPMI Driver
+			  ---------------------
+			      Corey Minyard
+			  <minyard@mvista.com>
+			    <minyard@acm.org>
+
+The Intelligent Platform Management Interface, or IPMI, is a
+standard for controlling intelligent devices that monitor a system.
+It provides for dynamic discovery of sensors in the system and the
+ability to monitor the sensors and be informed when the sensor's
+values change or go outside certain boundaries.  It also has a
+standardized database for field-replacable units (FRUs) and a watchdog
+timer.
+
+To use this, you need an interface to an IPMI controller in your
+system (called a Baseboard Management Controller, or BMC) and
+management software that can use the IPMI system.
+
+This document describes how to use the IPMI driver for Linux.  If you
+are not familiar with IPMI itself, see the web site at
+http://www.intel.com/design/servers/ipmi/index.htm.  IPMI is a big
+subject and I can't cover it all here!
+
+Basic Design
+------------
+
+The Linux IPMI driver is designed to be very modular and flexible, you
+only need to take the pieces you need and you can use it in many
+different ways.  Because of that, it's broken into many chunks of
+code.  These chunks are:
+
+ipmi_msghandler - This is the central piece of software for the IPMI
+system.  It handles all messages, message timing, and responses.  The
+IPMI users tie into this, and the IPMI physical interfaces (called
+System Management Interfaces, or SMIs) also tie in here.  This
+provides the kernelland interface for IPMI, but does not provide an
+interface for use by application processes.
+
+ipmi_devintf - This provides a userland IOCTL interface for the IPMI
+driver, each open file for this device ties in to the message handler
+as an IPMI user.
+
+ipmi_kcs_drv - A driver for the KCS SMI.  Most system have a KCS
+interface for IPMI.
+
+
+Much documentation for the interface is in the include files.  The
+IPMI include files are:
+
+ipmi.h - Contains the user interface and IOCTL interface for IPMI.
+
+ipmi_smi.h - Contains the interface for SMI drivers to use.
+
+ipmi_msgdefs.h - General definitions for base IPMI messaging.
+
+
+Addressing
+----------
+
+The IPMI addressing works much like IP addresses, you have an overlay
+to handle the different address types.  The overlay is:
+
+  struct ipmi_addr
+  {
+	int   addr_type;
+	short channel;
+	char  data[IPMI_MAX_ADDR_SIZE];
+  };
+
+The addr_type determines what the address really is.  The driver
+currently understands two different types of addresses.
+
+"System Interface" addresses are defined as:
+
+  struct ipmi_system_interface_addr
+  {
+	int   addr_type;
+	short channel;
+  };
+
+and the type is IPMI_SYSTEM_INTERFACE_ADDR_TYPE.  This is used for talking
+straight to the BMC on the current card.  The channel must be
+IPMI_BMC_CHANNEL.
+
+Messages that are destined to go out on the IPMB bus use the
+IPMI_IPMB_ADDR_TYPE address type.  The format is
+
+  struct ipmi_ipmb_addr
+  {
+	int           addr_type;
+	short         channel;
+	unsigned char slave_addr;
+	unsigned char lun;
+  };
+
+The "channel" here is generally zero, but some devices support more
+than one channel, it corresponds to the channel as defined in the IPMI
+spec.
+
+
+Messages
+--------
+
+Messages are defined as:
+
+struct ipmi_msg
+{
+	unsigned char netfn;
+	unsigned char lun;
+	unsigned char cmd;
+	unsigned char *data;
+	int           data_len;
+};
+
+The driver takes care of adding/stripping the header information.  The
+data portion is just the data to be send (do NOT put addressing info
+here) or the response.  Note that the completion code of a response is
+the first item in "data", it is not stripped out because that is how
+all the messages are defined in the spec (and thus makes counting the
+offsets a little easier :-).
+
+When using the IOCTL interface from userland, you must provide a block
+of data for "data", fill it, and set data_len to the length of the
+block of data, even when receiving messages.  Otherwise the driver
+will have no place to put the message.
+
+Messages coming up from the message handler in kernelland will come in
+as:
+
+  struct ipmi_recv_msg
+  {
+	struct list_head link;
+
+	/* The type of message as defined in the "Receive Types"
+           defines above. */
+	int         recv_type;
+
+	ipmi_user_t      *user;
+	struct ipmi_addr addr;
+	long             msgid;
+	struct ipmi_msg  msg;
+
+	/* Call this when done with the message.  It will presumably free
+	   the message and do any other necessary cleanup. */
+	void (*done)(struct ipmi_recv_msg *msg);
+
+	/* Place-holder for the data, don't make any assumptions about
+	   the size or existence of this, since it may change. */
+	unsigned char   msg_data[IPMI_MAX_MSG_LENGTH];
+  };
+
+You should look at the receive type and handle the message
+appropriately.
+
+
+The Upper Layer Interface (Message Handler)
+-------------------------------------------
+
+The upper layer of the interface provides the users with a consistent
+view of the IPMI interfaces.  It allows multiple SMI interfaces to be
+addressed (because some boards actually have multiple BMCs on them)
+and the user should not have to care what type of SMI is below them.
+
+
+Creating the User
+
+To user the message handler, you must first create a user using
+ipmi_create_user.  The interface number specifies which SMI you want
+to connect to, and you must supply callback functions to be called
+when data comes in.  The callback function can run at interrupt level,
+so be careful using the callbacks.  This also allows to you pass in a
+piece of data, the handler_data, that will be passed back to you on
+all calls.
+
+Once you are done, call ipmi_destroy_user() to get rid of the user.
+
+From userland, opening the device automatically creates a user, and
+closing the device automatically destroys the user.
+
+
+Messaging
+
+To send a message from kernel-land, the ipmi_request() call does
+pretty much all message handling.  Most of the parameter are
+self-explanatory.  However, it takes a "msgid" parameter.  This is NOT
+the sequence number of messages.  It is simply a long value that is
+passed back when the response for the message is returned.  You may
+use it for anything you like.
+
+Responses come back in the function pointed to by the ipmi_recv_hndl
+field of the "handler" that you passed in to ipmi_create_user().
+Remember again, these may be running at interrupt level.  Remember to
+look at the receive type, too.
+
+From userland, you fill out an ipmi_req_t structure and use the
+IPMICTL_SEND_COMMAND ioctl.  For incoming stuff, you can use select()
+or poll() to wait for messages to come in.  However, you cannot use
+read() to get them, you must call the IPMICTL_RECEIVE_MSG with the
+ipmi_recv_t structure to actually get the message.  Remember that you
+must supply a pointer to a block of data in the msg.data field, and
+you must fill in the msg.data_len field with the size of the data.
+This gives the receiver a place to actually put the message.
+
+If the message cannot fit into the data you provide, you will get an
+EMSGSIZE error and the driver will leave the data in the receive
+queue.  If you want to get it and have it truncate the message, us
+the IPMICTL_RECEIVE_MSG_TRUNC ioctl.
+
+When you send a command (which is defined by the lowest-order bit of
+the netfn per the IPMI spec) on the IPMB bus, the driver will
+automatically assign the sequence number to the command and save the
+command.  If the response is not receive in the IPMI-specified 5
+seconds, it will generate a response automatically saying the command
+timed out.  If an unsolicited response comes in (if it was after 5
+seconds, for instance), that response will be ignored.
+
+In kernelland, after you receive a message and are done with it, you
+MUST call ipmi_free_recv_msg() on it, or you will leak messages.  Note
+that you should NEVER mess with the "done" field of a message, that is
+required to properly clean up the message.
+
+Note that when sending, there is an ipmi_request_supply_msgs() call
+that lets you supply the smi and receive message.  This is useful for
+pieces of code that need to work even if the system is out of buffers
+(the watchdog timer uses this, for instance).  You supply your own
+buffer and own free routines.  This is not recommended for normal use,
+though, since it is tricky to manage your own buffers.
+
+
+Events and Incoming Commands
+
+The driver takes care of polling for IPMI events and receiving
+commands (commands are messages that are not responses, they are
+commands that other things on the IPMB bus have sent you).  To receive
+these, you must register for them, they will not automatically be sent
+to you.
+
+To receive events, you must call ipmi_set_gets_events() and set the
+"val" to non-zero.  Any events that have been received by the driver
+since startup will immediately be delivered to the first user that
+registers for events.  After that, if multiple users are registered
+for events, they will all receive all events that come in.
+
+For receiving commands, you have to individually register commands you
+want to receive.  Call ipmi_register_for_cmd() and supply the netfn
+and command name for each command you want to receive.  Only one user
+may be registered for each netfn/cmd, but different users may register
+for different commands.
+
+From userland, equivalent IOCTLs are provided to do these functions.
+
+
+The Lower Layer (SMI) Interface
+-------------------------------
+
+As mentioned before, multiple SMI interfaces may be registered to the
+message handler, each of these is assigned an interface number when
+they register with the message handler.  They are generally assigned
+in the order they register, although if an SMI unregisters and then
+another one registers, all bets are off.
+
+The ipmi_smi.h defines the interface for SMIs, see that for more
+details.
+
+
+The KCS Driver
+--------------
+
+The KCS driver allows up to 4 KCS interfaces to be configured in the
+system.  By default, the driver will register one KCS interface at the
+spec-specified I/O port 0xca2 without interrupts.  You can change this
+at module load time (for a module) with:
+
+  insmod ipmi_kcs_drv.o kcs_ports=<port1>,<port2>... kcs_addrs=<addr1>,<addr2>
+       kcs_irqs=<irq1>,<irq2>... kcs_trydefaults=[0|1]
+
+The KCS driver supports two types of interfaces, ports (for I/O port
+based KCS interfaces) and memory addresses (for KCS interfaces in
+memory).  The driver will support both of them simultaneously, setting
+the port to zero (or just not specifying it) will allow the memory
+address to be used.  The port will override the memory address if it
+is specified and non-zero.  kcs_trydefaults sets whether the standard
+IPMI interface at 0xca2 and any interfaces specified by ACPE are
+tried.  By default, the driver tries it, set this value to zero to
+turn this off.
+
+When compiled into the kernel, the addresses can be specified on the
+kernel command line as:
+
+  ipmi_kcs=<bmc1>:<irq1>,<bmc2>:<irq2>....,[nodefault]
+
+The <bmcx> values is either "p<port>" or "m<addr>" for port or memory
+addresses.  So for instance, a KCS interface at port 0xca2 using
+interrupt 9 and a memory interface at address 0xf9827341 with no
+interrupt would be specified "ipmi_kcs=p0xca2:9,m0xf9827341".
+If you specify zero for in irq or don't specify it, the driver will
+run polled unless the software can detect the interrupt to use in the
+ACPI tables.
+
+By default, the driver will attempt to detect a KCS device at the
+spec-specified 0xca2 address and any address specified by ACPI.  If
+you want to turn this off, use the "nodefault" option.
+
+If you have high-res timers compiled into the kernel, the driver will
+use them to provide much better performance.  Note that if you do not
+have high-res timers enabled in the kernel and you don't have
+interrupts enabled, the driver will run VERY slowly.  Don't blame me,
+the KCS interface sucks.
+
+
+Other Pieces
+------------
+
+Watchdog
+
+A watchdog timer is provided that implements the Linux-standard
+watchdog timer interface.  It has three module parameters that can be
+used to control it:
+
+  insmod ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
+      preaction=<preaction type> preop=<preop type>
+
+The timeout is the number of seconds to the action, and the pretimeout
+is the amount of seconds before the reset that the pre-timeout panic will
+occur (if pretimeout is zero, then pretimeout will not be enabled).
+
+The action may be "reset", "power_cycle", or "power_off", and
+specifies what to do when the timer times out, and defaults to
+"reset".
+
+The preaction may be "pre_smi" for an indication through the SMI
+interface, "pre_int" for an indication through the SMI with an
+interrupts, and "pre_nmi" for a NMI on a preaction.  This is how
+the driver is informed of the pretimeout.
+
+The preop may be set to "preop_none" for no operation on a pretimeout,
+"preop_panic" to set the preoperation to panic, or "preop_give_data"
+to provide data to read from the watchdog device when the pretimeout
+occurs.  A "pre_nmi" setting CANNOT be used with "preop_give_data"
+because you can't do data operations from an NMI.
+
+When preop is set to "preop_give_data", one byte comes ready to read
+on the device when the pretimeout occurs.  Select and fasync work on
+the device, as well.
+
+When compiled into the kernel, the kernel command line is available
+for configuring the watchdog:
+
+  ipmi_wdog=<timeout>[,<pretimeout>[,<option>[,<options>....]]]
+
+The options are the actions and preaction above (if an option
+controlling the same thing is specified twice, the last is taken).  An
+options "start_now" is also there, if included, the watchdog will
+start running immediately when all the drivers are ready, it doesn't
+have to have a user hooked up to start it.
+
+The watchdog will panic and start a 120 second reset timeout if it
+gets a pre-action.  During a panic or a reboot, the watchdog will
+start a 120 timer if it is running to make sure the reboot occurs.
+
+Note that if you use the NMI preaction for the watchdog, you MUST
+NOT use nmi watchdog mode 1.  If you use the NMI watchdog, you
+must use mode 2.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/Booting linux-2.4.21-rc3/Documentation/arm/Booting
--- linux-2.4.20/Documentation/arm/Booting	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/arm/Booting	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,137 @@
+			Booting ARM Linux
+			=================
+
+Author:	Russell King
+Date  : 18 May 2002
+
+The following documentation is relevant to 2.4.18-rmk6 and beyond.
+
+In order to boot ARM Linux, you require a boot loader, which is a small
+program that runs before the main kernel.  The boot loader is expected
+to initialise various devices, and eventually call the Linux kernel,
+passing information to the kernel.
+
+Essentially, the boot loader should provide (as a minimum) the
+following:
+
+1. Setup and initialise the RAM.
+2. Initialise one serial port.
+3. Detect the machine type.
+4. Setup the kernel tagged list.
+5. Call the kernel image.
+
+
+1. Setup and initialise RAM
+---------------------------
+
+Existing boot loaders:		MANDATORY
+New boot loaders:		MANDATORY
+
+The boot loader is expected to find and initialise all RAM that the
+kernel will use for volatile data storage in the system.  It performs
+this in a machine dependent manner.  (It may use internal algorithms
+to automatically locate and size all RAM, or it may use knowledge of
+the RAM in the machine, or any other method the boot loader designer
+sees fit.)
+
+
+2. Initialise one serial port
+-----------------------------
+
+Existing boot loaders:		OPTIONAL, RECOMMENDED
+New boot loaders:		OPTIONAL, RECOMMENDED
+
+The boot loader should initialise and enable one serial port on the
+target.  This allows the kernel serial driver to automatically detect
+which serial port it should use for the kernel console (generally
+used for debugging purposes, or communication with the target.)
+
+As an alternative, the boot loader can pass the relevant 'console='
+option to the kernel via the tagged lists specifing the port, and
+serial format options as described in
+
+       linux/Documentation/kernel-parameters.txt.
+
+
+3. Detect the machine type
+--------------------------
+
+Existing boot loaders:		OPTIONAL
+New boot loaders:		MANDATORY
+
+The boot loader should detect the machine type its running on by some
+method.  Whether this is a hard coded value or some algorithm that
+looks at the connected hardware is beyond the scope of this document.
+The boot loader must ultimately be able to provide a MACH_TYPE_xxx
+value to the kernel. (see linux/arch/arm/tools/mach-types).
+
+
+4. Setup the kernel tagged list
+-------------------------------
+
+Existing boot loaders:		OPTIONAL, HIGHLY RECOMMENDED
+New boot loaders:		MANDATORY
+
+The boot loader must create and initialise the kernel tagged list.
+A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
+The ATAG_CORE tag may or may not be empty.  An empty ATAG_CORE tag
+has the size field set to '2' (0x00000002).  The ATAG_NONE must set
+the size field to zero.
+
+Any number of tags can be placed in the list.  It is undefined
+whether a repeated tag appends to the information carried by the
+previous tag, or whether it replaces the information in its
+entirety; some tags behave as the former, others the latter.
+
+The boot loader must pass at a minimum the size and location of
+the system memory, and root filesystem location.  Therefore, the
+minimum tagged list should look:
+
+	+-----------+
+base ->	| ATAG_CORE |  |
+	+-----------+  |
+	| ATAG_MEM  |  | increasing address
+	+-----------+  |
+	| ATAG_NONE |  |
+	+-----------+  v
+
+The tagged list should be stored in system RAM.
+
+The tagged list must be placed in a region of memory where neither
+the kernel decompressor nor initrd 'bootp' program will overwrite
+it.  The recommended placement is in the first 16KiB of RAM.
+
+5. Calling the kernel image
+---------------------------
+
+Existing boot loaders:		MANDATORY
+New boot loaders:		MANDATORY
+
+There are two options for calling the kernel zImage.  If the zImage
+is stored in flash, and is linked correctly to be run from flash,
+then it is legal for the boot loader to call the zImage in flash
+directly.
+
+The zImage may also be placed in system RAM (at any location) and
+called there.  Note that the kernel uses 16K of RAM below the image
+to store page tables.  The recommended placement is 32KiB into RAM.
+
+In either case, the following conditions must be met:
+
+- CPU register settings
+  r0 = 0,
+  r1 = machine type number discovered in (3) above.
+  r2 = physical address of tagged list in system RAM.
+
+- CPU mode
+  All forms of interrupts must be disabled (IRQs and FIQs)
+  The CPU must be in SVC mode.  (A special exception exists for Angel)
+
+- Caches, MMUs
+  The MMU must be off.
+  Instruction cache may be on or off.
+  Data cache must be off.
+
+- The boot loader is expected to call the kernel image by jumping
+  directly to the first instruction of the kernel image.
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/ConfigVars linux-2.4.21-rc3/Documentation/arm/ConfigVars
--- linux-2.4.20/Documentation/arm/ConfigVars	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/arm/ConfigVars	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,26 @@
+CONFIG_ARCH_CO285		- co-ebsa285
+CONFIG_ARCH_FOOTBRIDGE		- all other footbridge systems
+
+  CONFIG_ARCH_CATS		- CATS support
+  CONFIG_ARCH_PERSONAL_SERVER	- personal server support
+  CONFIG_ARCH_EBSA285_ADDIN	- add-in ebsa285 support
+  CONFIG_ARCH_EBSA285_HOST	- host ebsa285 support
+  CONFIG_ARCH_NETWINDER 	- netwinder support
+
+CONFIG_FOOTBRIDGE		- any system with a footbridge chip
+ |- (CONFIG_ARCH_CO285)
+ \- (CONFIG_ARCH_FOOTBRIDGE)
+
+CONFIG_FOOTBRIDGE_HOST		- any system with host mode footbridge support
+ |- (CONFIG_ARCH_CATS)
+ |- (CONFIG_ARCH_EBSA285_HOST)
+ |- (CONFIG_ARCH_NETWINDER)
+ \- (CONFIG_ARCH_PERSONAL_SERVER)
+
+CONFIG_FOOTBRIDGE_ADDIN 	- any system with addin mode footbridge support
+ |- (CONFIG_ARCH_CO285)
+ \- (CONFIG_ARCH_EBSA285_ADDIN)
+
+CONFIG_ARCH_EBSA285		- either host or add-in ebsa285 support, but
+ |- (CONFIG_ARCH_EBSA285_ADDIN)   not co-ebsa285
+ \- (CONFIG_ARCH_EBSA285_HOST)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/MEMC linux-2.4.21-rc3/Documentation/arm/MEMC
--- linux-2.4.20/Documentation/arm/MEMC	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/arm/MEMC	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,57 @@
+MEMC enhancements for Linux 2.3
+-------------------------------
+
+The current interface:
+
+  There is a cache of the MEMC settings held in tsk->tss.memcmap, which is
+  kept up to date by the following functions (from the page tables):
+
+  update_memc_all()				hits:	2
+	Updates all MEMC caches on all processes.  Update the real MEMC
+	to reflect the `current' tasks page tables.
+
+  update_memc_tsk(tsk)				hits:	0
+	Update the MEMC cache for the specified task.  If tsk is the
+	`current' task, then update the real MEMC as well.
+
+  update_memc_mm(mm)				hits:	16
+	Update the MEMC cache for any task which has a mm_struct
+	corresponding to `mm'.  If the `current' tasks mm_struct
+	includes this, then update the real MEMC as well.
+
+  update_memc_addr(mm, addr, pte)		hits:	8
+	Update the MEMC cache entry defined by the physical address
+	in pte for any task which has a mm_struct corresponding to `mm'.
+	If the `current' tasks mm_struct includes this, then update the
+	real MEMC as well.
+
+The proposed interface:
+
+  Couple the MEMC cache into the mm_struct so that we only have to
+  keep one copy per mm_struct.  This also allows us to reduce the
+  number of loops through all existing tasks on each MEMC change.
+
+  memc_clear(mm, physaddr)			hits:	6
+	Clear the MEMC mapping associated with the physical address
+	`physaddr'.  If the `current' tasks mm_struct is `mm', then
+	update the real MEMC as well.	(should equate to a possible
+	two writes and zero reads).
+
+  memc_update_addr(mm, pte, logaddr)		hits:	10
+	Change the MEMC mapping for the physical address specified
+	in `pte' to point to the logical address `logaddr', with the
+	protection specified in `pte'.  If the `current' tasks mm_struct
+	is `mm', then update the real MEMC as well.  (should again equate
+	to a possible two writes and zero reads).
+
+  memc_update_mm(mm)				hits:	7
+	Rebuild the MEMC mappings for the specified `mm' in the same way
+	that update_memc_mm used to.  If the `current' tasks mm_struct
+	is `mm', update the real MEMC as well.
+
+  memc_update_all()				hits:	2
+	Rebuild the MEMC mappings for all mm_structs, including the real
+	MEMC.
+
+The hit numbers are approximate usage of each function in the 2.2.7
+memory management (mm) code, and there are other uses outside this area.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/SA1100/SA1100_USB linux-2.4.21-rc3/Documentation/arm/SA1100/SA1100_USB
--- linux-2.4.20/Documentation/arm/SA1100/SA1100_USB	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/arm/SA1100/SA1100_USB	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,344 @@
+StrongARM SA-1100 USB function Driver
+Ward Willats <ward.willats@extenex.com> -  08Mar01
+
+1. History
+''''''''''
+Brad Parker <brad@parker.boston.ma.us> ported the DEC/Compaq "Itsy"
+SA-1100 USB Function driver to the 2.4.x code base in late 2000, for
+use as an "ethernet over usb" link. His original notes are here in
+section 4. Nicolas Pitre <nico@cam.org> rewrote the transmitter and
+reciver (endpoints 1 and 2) in late 2000 to use the standard SA DMA
+API and I added a bulk character interface and reworked the control
+control module code and rewrote endpoint zero in early 2001.
+
+This release (22Feb01) is the first that completely separates
+client modules (usb-eth.c and usb-char.c) from the SA-1100 USB core.
+(usb_ctl, usb_ep0, usb_send and usb_receive)and makes the whole
+mess a module. Oleg Drokin has done a huge amount of work, fixing
+things I break and adding support for the generic usbnet driver
+from the AC tree.
+
+2. Usage
+''''''''
+Turn on CONFIG_SA1100_USB_NETLINK to use the "ethernet over usb"
+functionality. Turn it off to use the character oriented
+interface. The character driver currently uses mknod c 10 240.
+
+Programming:
+The public interface is in sa1100_usb.h. For a client USB service
+to use the SA-1100 USB core driver it should:
+
+1. Call sa1100_usb_open() to get the usb core assigned to it.
+
+2. Setup descriptors as appropriate for the task at hand. Esp.
+important are endpoint max packet lengths, vendor and product IDs,
+and type of endpoint (bulk or interrupt). Call
+sa1100_get_descriptor_ptr() to get this.
+
+3. Call sa1100_usb_start() to actually start the usb hardware.
+At this time the host will configure the device.
+
+...at shutdown...
+
+4. Call sa1100_usb_stop() to stop the USB core.
+5. Call sa1100_usb_close() to free the core for use by another
+client.
+
+3. Netlink Usage
+''''''''''''''''
+StrongARM SA-1100 USB function "ethernet over usb driver"
+Brad Parker <brad@parker.boston.ma.us>
+
+I ported the DEC "Itsy" usb "ethernet over usb driver" code to the 2.4.x
+base and made some enhacements and bug fixes.  This code has 2 sides and
+implements a simple "ethernet over usb" functionality.
+
+function (SA1100) side:
+- the driver has two endpoints and uses interrupt and bulk transfer to
+receive/send packets.  the driver does not require any other usb code
+and should work on most any sa1100.
+
+host (SA1111) side:
+- because the SA1111 usb host is not working yet I tested this driver
+(usb-net-host.c) on a 2.2.14 based PC with the latest usb backport.
+It has been fully converted to use URBs and worked well with my UHCI
+based controller.
+
+TESTING:
+
+To test you need an assabet on the 'function' side, a PC on the 'host'
+side and a USB A-B cable to connect them together.
+
+Boot a kernel on the assabet with "USB function and net-host support"
+(CONFIG_SA1100_USB) turned on.  This will define an interface named
+"usbf".  Once it's booted you can setup the interface with
+
+	mount -t proc /proc /proc
+	/sbin/ifconfig usbf 1.1.1.2
+
+I used a 2.2.14 kernel on a x86 PC for the host side.  It has a built
+in UHCI usb controller chip.  I installed the latest USB backport from
+http://www.linux-usb.org onto the 2.2.14 kernel sources and turned on
+"USB net-host" (CONFIG_USB_NET_HOST) as a module.  Load the module
+"usb-net-host.o" and connect the USB cable to the assabet.  Configure
+the usb network interface with
+
+	/sbin/ifconfig usb0 1.1.1.1
+
+You should be able to "ping" the assabet now with
+
+	ping -c 1 1.1.1.2
+
+If the assabet is running inetd the usual network services such as
+telnet and ftp should work.
+
+Oleg Drokin in 2.4.2-rmk1-np2 (08Mar01) added module config params for
+read and write size to the usb-eth.c client to allow dynamic setting
+of the DATA0/DATA1 packet size on the usb wire:
+
+usb_rsize - number of bytes in OUT packets from host to SA1100
+usb_wsize - number of bytes in IN packets from SA1100 to host
+
+This allows dynamic tuning for performance or to prevent overruning
+the the host with data.
+
+4. Known Issues
+'''''''''''''''
+- We are fiddling with various ways to set the IMP register in
+usb_send.c. A small percentage of the time, this value does not
+"take."
+
+- I've started to bring back the /proc interface, but clients
+of the sa-usb core currently don't have a directory or something
+to put their stats into.
+
+- Only a useful subset of ep0 setup calls have been implemented.
+
+
+5. Mysteries of the Universe
+''''''''''''''''''''''''''''
+This driver has been hard to develop because the documentation
+provided by Intel is incomplete, and the UDC itself seems to have a
+variety of bugs. The errata for the part is particularly scary! This
+section is an attempt to document some of the discoveries and
+questions I have come across while working on this thing.
+
+pp 11-63 of the "Intel Strong ARM SA-1110 Microprocessor Advanced
+Developer Information" give an ominous warning about how "due to
+internal synchronization required by the UDC configuration registers,
+it is possible for the procesor to write the UDC refisters and FIFOs
+too fast." This has led to a variety of approaches that attempt to
+bang on the hardware repeatedly and read it back until the write
+"sticks."
+
+All of these approaches have been problematic. Currently some macros
+in udc_ctl.h that Nicolas wrote are being used. My hardware guy told
+me that writes would never be "lost" but stuck on some internal bus in
+the UDC module and propagated to the rest of the circuit when the time
+was right. Indeed this seemed to be the case, for example, it seems
+impossible to reliably read back the interrupt mask register of the UDC when in
+the interrupt service routine. Often times the state was not reflected
+on a read until after pending interrupt sources were cleared.
+
+I was feeling prety good about this and was ripping out the looping
+macros right and left until I came upon a situation where, while
+receiving a continuous set of 1 character packets, ep1 (usb_receive.c)
+could not clear receive packet complete (RPC). After much desperate
+faliling about it turns out changing the UDC_flip() macro to bang like
+crazy on the RPC bit did in fact clear it, and clear it
+consistently. So go figure.
+
+Other items of interest:
+
+- Upon emerging from a reset, the UDC will clear the mask register except
+for a mask on suspend.
+
+- USB 1.0 spec says maximum size of a DATA0/1 packet is 64 bytes,
+which is what the character driver is using. However, the UDC can do
+256 bytes and every host I've tried can handle it, even though they
+are not required to. (Perhaps it is a problem when hubs are on the
+line, but the SA UDC has other problems in a hub environment -- like
+even getting the correct address -- per the errata).
+
+- Endpoint zero FIFOs: ARGHHH! Just leave those routines alone.
+Believe me, I have tried every other variation you can think of.
+Probably.
+
+- Sometimes I get a setup request of 0x80 from Windows hosts. I have
+not determined if this is a read_fifo error (none is reported) or if
+this is some undocumented secret Redmond handshake only known to
+initiates of the inner-order.
+
+6. Test Program
+'''''''''''''''
+This is now in the /proc interface. (For good or ill, probably don't
+actually need to dump all this stuff..)
+
+7. Errors and Notes on Intel's 1110 Documentation
+'''''''''''''''''''''''''''''''''''''''''''''''''
+These corrections apply to "Intel StrongARM SA-1110 Microprocessor,
+Advanced Developer's Manual of December 1999" Some of these have been
+corrected in later editions, some not. There have been several updates
+to this document published through 2000. Always use the latest
+available on http://developer.intel.com/design/strong/collateral.htm.
+
+pp 11-65 section 11.8.3.8 bit 2, reserved is now the resume interrupt
+mask. SRM is now SUSIM on SA-1110, and masks only the suspend
+interrupt.
+
+pp 11-67 section 11.8.6, Max IN register, end should be 9 _bytes_
+not 9 bits.
+
+pp 11-68 section 11.8.7.3, SST. This is set by the CPU _not_ the UDC.
+And it looks like you don't get a SST if you FST yourself.
+
+pp 11-68 section 11.8.7.5, DE. This is set by the CPU _not_ the UDC.
+
+pp 11-73 section 11.8.9.7, UDCCS2 table, bit 2, Should be "valid only
+when _TPC_ (not RPC) is set.
+
+pp 11-74 section 11.8.10, should end with a GET_DESCRIPTOR _or
+similar_ command. (Like, for example, GET_CONFIGURATION).
+
+
+8. Change History
+'''''''''''''''''
+Following are current chages  8Mar01 (released in 2.4.2-rmk1-np2?)
+
+- Resetting UDC when coming out of suspend helped enumeration get
+going considerably.
+
+- Added support for client-supplied notify routine to be called
+by the USB core when core reaches "configured" state.
+
+- Added error returns from interrupt reads and buffer flush ioctl
+calls to usb-char. Added usb-char.h file for ioctl calls.
+
+- Fixed bug that kept usb-char transmitter from working the second
+time the module was loaded.
+
+- Turned off a lot of the noise in /proc
+
+- Added specialty routines in ep0 to set and clear bits.
+
+- More enumeration fiddling.
+
+- There are horrible hacks to set max IN length in usb_send
+  that ARE GOING AWAY SOON! REALLY!
+
+*** Following changes 26Feb01 (released in 2.4.2-rmk1-np1)
+
+- usb-eth integration with generic usbnet from AC tree.
+
+- Creation of public interface for usb clients in sa1100_usb.h
+and final separation into a "core" driver (usb_ctl.c, usb_ep0.c
+usb_recv.c usb_send.c) and "client" services (usb-eth.c and
+usb-char.c). Modularized.
+
+- Descriptor handling rewritten. Support for string descriptors
+added. More bugs in ep0 fixed. More setup packets handled.
+
+- /proc interface in usb_ctl returning
+
+- removed client specific stuff from usbd_info_t and hid the
+structure in usb_ctl. Removed RAM-backing of address and pktsize
+in this structure. Now the descriptor values are gospel.
+
+- usb_dbg.h eliminated
+
+- Many bugs fixed in usb-char.c
+
+- Fiddled startup sequence so should start everytime.
+
+- Arch specific "soft connect" hook in usb_ctl.c
+
+- Bumped the interation count in write/set/clear macros
+in usb_ctl.h up to 10000. This seemed to help various bit
+setting in ep0 and usb_send.c.
+
+*** Following changes 10Feb01 release:
+
+- endpoint zero entirely rewitten
+
+- Various changes by Oleg to make Netlink work again after the
+  2.4.1-rmk1-np1 release.
+
+- Resetting of new max packet length done after clearing TPC
+in usb_send, per Nicolas Pitre.
+
+
+*** Following changes 23Jan01 (came out in 2.4.1-rmk1-np1):
+
+- Moved host initiated SET/GET feature stall into endpoint code of
+usb_send.c and usb_receive.c and removed stallep from usb_ctl.c
+Opposite of a SET_FEATURE stall is a reset, so no code to unstall is
+provided.
+
+- Added explicit USB state machine to usb_ctl so driver and device
+state can be tracked closely and explicitly. Added hard-wired
+notification routines in endpoints 1 and 2 so they can track device
+state changes as required. State machine has notion of "zombie" state
+the covers USB states NONATTACHED, ATTACHED and POWERED since these
+are murky, and USB driver currently has no way to differentiate
+between the two.
+
+- Reworked ISR in usb_ctl so reset has higher priority than any other
+event. Stopped using sync macros to clear interrupt pending flags and set
+mask registers since it appears mask register changes are not
+always reflected on a mask register read until the pending flag is
+cleared (yet other tests show they are always cleared
+eventually). Toggle suspend/resume interrupt masks back and forth during
+suspend and resume to debounce and keep UDC internal state machine in
+sync per Intel documentation.
+
+- Flipped UDC flip, clear, write and set macros from do{}while to
+while() loops. Theory is you might save a loop iteration if value
+becomes valid immediately. Also, my hardware guy says writes are never
+"lost", just pipelined and not executed immediately depending on
+internal device conditions (like setting int masks when ints
+pending), so moved write cycles in macros outside of loops.
+
+- Added #defines to SA-1110.h for suspend and resume interrupt mask
+bits per Intel eratta. Submitted to ARM patch system (444/1).
+
+- Removed task queue and defered execution of configure() from
+usb_ctl.
+
+- Removed usb_write_reg() from usb_ctl.c, and various cruft from
+usb_ctl.h.
+
+- Added sa1100_usb_xmitter_avail() to usb_send.c. Makes implementing
+poll() fileop easier.
+
+- Added sa1100_usb_send_reset() to usb_send.c. Makes implementing
+transmitter timeout easier.
+
+- Added API to usb_ctl to set vendor and product ID
+
+- Changed BMATTR descriptor fron int to bulk, when not using netlink. (All
+the docs say UDC does not support INT xfers -- though, at the protocol
+level I don't see why not, since bulk and int are both just
+IN-DATA-ACK. I figure netlink may rely on this, and not just a
+continuous pending read from the host, but for "pure bulk" host
+polling may not be generally correct.)
+
+- Removed unused rx_lock and tx_lock from usb_ctl
+
+- Converted everyone to SA-1100.h and nuked hardware defines in usb_ctl.h
+
+- Removed udc_init() in usb_ctl.c and folded functionality into udc_start().
+
+- Clear force stall (FST) in udc_start and reset so UDC actually runs when
+first turned on.
+
+- Emit NAK in receiver until ep1_start() for error (RPE) case too.
+
+- Remove enable/disable UDC from reset handler in udc_ctl. The UDC has
+already been reset, so no need to do this again.
+
+- Explicitly set address to zero in ep0_reset()
+
+- Added "naking" boolean to usb_receiv.c. An attempt to solve a
+hypothetical race condition where we are in the critical section
+initiating a read from base-level code, a RPC happens, and start()
+might clear the condition before the packet is handled by the ISR.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/SA1100/nanoEngine linux-2.4.21-rc3/Documentation/arm/SA1100/nanoEngine
--- linux-2.4.20/Documentation/arm/SA1100/nanoEngine	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/arm/SA1100/nanoEngine	2003-05-22 22:06:38.000000000 +0000
@@ -7,5 +7,7 @@
 (Ref: Stuart Adams <sja@brightstareng.com>)
 
 Also visit Larry Doolittle's "Linux for the nanoEngine" site:
-http://recycle.lbl.gov/~ldoolitt/bse/
-
+  http://recycle.lbl.gov/~ldoolitt/bse/
+This page includes translation code that builds the parameter
+blocks for the Linux kernel, which must happen before each
+kernel boot.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/cciss.txt linux-2.4.21-rc3/Documentation/cciss.txt
--- linux-2.4.20/Documentation/cciss.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/cciss.txt	2003-05-22 22:06:27.000000000 +0000
@@ -9,6 +9,9 @@
 	* SA 5i 
 	* SA 532
 	* SA 5312
+	* SA 641
+	* SA 642
+	* SA 6400
 
 If nodes are not already created in the /dev/cciss directory
 
@@ -86,7 +89,7 @@
 
 Hot plugging of SCSI tape drives is supported, with some caveats.
 The cciss driver must be informed that changes to the SCSI bus
-have been made, in addition to and prior to informing the the SCSI 
+have been made, in addition to and prior to informing the SCSI 
 mid layer.  This may be done via the /proc filesystem.  For example:
 
 	echo "rescan" > /proc/scsi/cciss0/1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/fb/clgenfb.txt linux-2.4.21-rc3/Documentation/fb/clgenfb.txt
--- linux-2.4.20/Documentation/fb/clgenfb.txt	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/fb/clgenfb.txt	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,6 @@
 
 		Framebuffer driver for Cirrus Logic chipsets
-		Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+		Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/Locking linux-2.4.21-rc3/Documentation/filesystems/Locking
--- linux-2.4.20/Documentation/filesystems/Locking	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/filesystems/Locking	2003-05-22 22:06:40.000000000 +0000
@@ -93,6 +93,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
@@ -108,6 +109,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	yes	yes	maybe		(see below)
+sync_fs:	yes	no	maybe		(see below)
 statfs:		yes	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/jfs.txt linux-2.4.21-rc3/Documentation/filesystems/jfs.txt
--- linux-2.4.20/Documentation/filesystems/jfs.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/filesystems/jfs.txt	2003-05-22 22:06:48.000000000 +0000
@@ -28,8 +28,6 @@
 Plans for our near term development items
 
    - enhance support for logfile on dedicated partition
-   - get access control list functionality operational
-   - get extended attributes functionality operational
 
 Longer term work items
 
@@ -37,7 +35,7 @@
    - add quota support
    - add support for block sizes (512,1024,2048)
 
-Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com.
+Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
 
 The JFS mailing list can be subscribed to by using the link labeled
 "Mail list Subscribe" at our web page http://oss.software.ibm.com/jfs/.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/proc.txt linux-2.4.21-rc3/Documentation/filesystems/proc.txt
--- linux-2.4.20/Documentation/filesystems/proc.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/filesystems/proc.txt	2003-05-22 22:06:39.000000000 +0000
@@ -952,15 +952,14 @@
 Table 2-2: Parameters in /proc/sys/vm/bdflush 
 ..............................................................................
  Value      Meaning                                                            
- nfract     Percentage of buffer cache dirty to  activate bdflush              
+ nfract     Percentage of buffer cache dirty to activate bdflush              
  ndirty     Maximum number of dirty blocks to  write out per wake-cycle        
- nrefill    Number of clean buffers to try to obtain  each time we call refill 
- nref_dirt  buffer threshold for activating bdflush when trying to refill
-            buffers. 
  dummy      Unused                                                             
- age_buffer Time for normal buffer to age before we flush it                   
- age_super  Time for superblock to age before we flush it                      
  dummy      Unused                                                             
+ interval   jiffies delay between kupdate flushes
+ age_buffer Time for normal buffer to age before we flush it                   
+ nfract_sync Percentage of buffer cache dirty to activate bdflush synchronously
+ nfract_stop_bdflush Percetange of buffer cache dirty to stop bdflush
  dummy      Unused                                                             
 ..............................................................................
 
@@ -974,6 +973,12 @@
 long time, but it also means that it will have to do a lot of I/O at once when
 memory becomes short. A lower value will spread out disk I/O more evenly.
 
+interval
+--------
+
+The interval between two kupdate runs. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
+
 ndirty
 ------
 
@@ -981,29 +986,18 @@
 disk at  one  time.  A high value will mean delayed, bursty I/O, while a small
 value can lead to memory shortage when bdflush isn't woken up often enough.
 
-nrefill
--------
-
-This is  the  number  of  buffers  that  bdflush  will add to the list of free
-buffers when  refill_freelist()  is  called.  It is necessary to allocate free
-buffers beforehand,  since  the  buffers  are  often  different sizes than the
-memory pages  and some bookkeeping needs to be done beforehand. The higher the
-number, the  more  memory  will be wasted and the less often refill_freelist()
-will need to run.
-
-nref_dirt
----------
+age_buffer
+----------
 
-When refill_freelist() comes across more than nref_dirt dirty buffers, it will
-wake up bdflush.
+Finally, the age_buffer parameter govern the maximum time Linux
+waits before  writing  out  a  dirty buffer to disk. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
 
-age_buffer and age_super
-------------------------
+nfract_sync
+-----------
 
-Finally, the age_buffer and age_super parameters govern the maximum time Linux
-waits before  writing  out  a  dirty buffer to disk. The value is expressed in
-jiffies (clockticks),  the  number of jiffies per second is 100. Age_buffer is
-the maximum age for data blocks, while age_super is for filesystems meta data.
+nfract_stop_bdflush
+-------------------
 
 buffermem
 ---------
@@ -1582,10 +1576,14 @@
 error_burst and error_cost
 --------------------------
 
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  routing  code.  The  higher the error_cost factor is, the fewer
-messages will  be written. Error_burst controls when messages will be dropped.
-The default settings limit warning messages to one every five seconds.
+These  parameters  are used to limit how many ICMP destination unreachable to 
+send  from  the  host  in question. ICMP destination unreachable messages are 
+sent  when  we can not reach the next hop, while trying to transmit a packet. 
+It  will also print some error messages to kernel logs if someone is ignoring 
+our   ICMP  redirects.  The  higher  the  error_cost  factor  is,  the  fewer 
+destination  unreachable  and error messages will be let through. Error_burst 
+controls  when  destination  unreachable  messages and error messages will be
+dropped. The default settings limit warning messages to five every second.
 
 flush
 -----
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/i810_rng.txt linux-2.4.21-rc3/Documentation/i810_rng.txt
--- linux-2.4.20/Documentation/i810_rng.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/i810_rng.txt	2003-05-22 22:06:50.000000000 +0000
@@ -1,5 +1,5 @@
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 Introduction:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/00-INDEX linux-2.4.21-rc3/Documentation/networking/00-INDEX
--- linux-2.4.20/Documentation/networking/00-INDEX	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/00-INDEX	2003-05-22 22:06:51.000000000 +0000
@@ -97,7 +97,8 @@
 sis900.txt
 	- SiS 900/7016 Fast Ethernet device driver info.
 sk98lin.txt
-	- SysKonnect SK-NET (SK-98xx) Gigabit Ethernet driver info.
+	- SysKonnect SK-98xx and SK-98xx Gigabit Ethernet Adapter family 
+	  driver info.
 skfp.txt
 	- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/8139too.txt linux-2.4.21-rc3/Documentation/networking/8139too.txt
--- linux-2.4.20/Documentation/networking/8139too.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/8139too.txt	2003-05-22 22:06:48.000000000 +0000
@@ -2,7 +2,7 @@
 		"8139too" Fast Ethernet driver for Linux
 	 RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters
 
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 
                 http://sourceforge.net/projects/gkernel/
 
@@ -93,6 +93,8 @@
 ---------------
 AOpen ALN-325C
 AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card
+Cnet CNF401 'SinglePoint' 10/100 Base-TX
+Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card
 KTI KF-230TX
 KTI KF-230TX/2
 Lantech FastNet TX
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt linux-2.4.21-rc3/Documentation/networking/NAPI_HOWTO.txt
--- linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/NAPI_HOWTO.txt	2003-05-22 22:06:47.000000000 +0000
@@ -721,6 +721,23 @@
 
 
 
+
+APPENDIX 3: Scheduling issues.
+==============================
+As seen NAPI moves processing to softirq level. Linux uses the ksoftirqd as the 
+general solution to schedule softirq's to run before next interrupt and by putting 
+them under scheduler control. Also this prevents consecutive softirq's from 
+monopolize the CPU. This also have the effect that the priority of ksoftirq needs 
+to be considered when running very CPU-intensive applications and networking to
+get the proper balance of softirq/user balance. Increasing ksoftirq priority to 0 
+(eventually more) is reported cure problems with low network performance at high 
+CPU load.
+
+Most used processes in a GIGE router:
+USER       PID %CPU %MEM  SIZE   RSS TTY STAT START   TIME COMMAND
+root         3  0.2  0.0     0     0  ?  RWN Aug 15 602:00 (ksoftirqd_CPU0)
+root       232  0.0  7.9 41400 40884  ?  S   Aug 15  74:12 gated 
+
 --------------------------------------------------------------------
 
 relevant sites:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/bonding.txt linux-2.4.21-rc3/Documentation/networking/bonding.txt
--- linux-2.4.20/Documentation/networking/bonding.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/bonding.txt	2003-05-22 22:06:39.000000000 +0000
@@ -7,6 +7,7 @@
   - Constantine Gavrilov <const-g at xpert.com>
   - Chad N. Tindel <ctindel at ieee dot org>
   - Janice Girouard <girouard at us dot ibm dot com>
+  - Jay Vosburgh <fubar at us dot ibm dot com>
 
 Note :
 ------
@@ -17,6 +18,23 @@
 For new versions of the driver, patches for older kernels and the updated
 userspace tools, please follow the links at the end of this file.
 
+
+Table of Contents
+=================
+ 
+Installation
+Bond Configuration
+Module Parameters
+Configuring Multiple Bonds
+Switch Configuration
+Verifying Bond Configuration
+Frequently Asked Questions
+High Availability
+Promiscuous Sniffing notes
+Limitations
+Resources and Links
+
+
 Installation
 ============
 
@@ -51,16 +69,21 @@
     # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave 
     # cp ifenslave /sbin/ifenslave
 
-3) Configure your system
-------------------------
-Also see the following section on the module parameters. You will need to add
-at least the following line to /etc/conf.modules (or /etc/modules.conf):
+
+Bond Configuration
+==================
+
+You will need to add at least the following line to /etc/modules.conf
+so the bonding driver will automatically load when the bond0 interface is 
+configured. Refer to the modules.conf manual page for specific modules.conf 
+syntax details. The Module Parameters section of this document describes each 
+bonding driver parameter. 
 
 	alias bond0 bonding
 
-Use standard distribution techniques to define bond0 network interface. For
-example, on modern RedHat distributions, create ifcfg-bond0 file in
-/etc/sysconfig/network-scripts directory that looks like this:
+Use standard distribution techniques to define the bond0 network interface. For
+example, on modern Red Hat distributions, create an ifcfg-bond0 file in
+the /etc/sysconfig/network-scripts directory that resembles the following:
 
 DEVICE=bond0
 IPADDR=192.168.1.1
@@ -71,12 +94,12 @@
 BOOTPROTO=none
 USERCTL=no
 
-(put the appropriate values for you network instead of 192.168.1).
+(use appropriate values for your network above)
 
-All interfaces that are part of the trunk, should have SLAVE and MASTER
-definitions. For example, in the case of RedHat, if you wish to make eth0 and
-eth1 (or other interfaces) a part of the bonding interface bond0, their config
-files (ifcfg-eth0, ifcfg-eth1, etc.) should look like this:
+All interfaces that are part of a bond should have SLAVE and MASTER
+definitions. For example, in the case of Red Hat, if you wish to make eth0 and
+eth1 a part of the bonding interface bond0, their config files (ifcfg-eth0 and
+ifcfg-eth1) should resemble the following:
 
 DEVICE=eth0
 USERCTL=no
@@ -85,89 +108,344 @@
 SLAVE=yes
 BOOTPROTO=none
 
-(use DEVICE=eth1 for eth1 and MASTER=bond1 for bond1 if you have configured
-second bonding interface). 
+Use DEVICE=eth1 in the ifcfg-eth1 config file. If you configure a second bonding
+interface (bond1), use MASTER=bond1 in the config file to make the network
+interface be a slave of bond1.
 
 Restart the networking subsystem or just bring up the bonding device if your
-administration tools allow it. Otherwise, reboot. (For the case of RedHat
-distros, you can do `ifup bond0' or `/etc/rc.d/init.d/network restart'.)
+administration tools allow it. Otherwise, reboot. On Red Hat distros you can 
+issue `ifup bond0' or `/etc/rc.d/init.d/network restart'.
 
 If the administration tools of your distribution do not support master/slave
-notation in configuration of network interfaces, you will need to configure
-the bonding device with the following commands manually:
+notation in configuring network interfaces, you will need to manually configure 
+the bonding device with the following commands:
+
+    # /sbin/ifconfig bond0 192.168.1.1 netmask 255.255.255.0 \
+      broadcast 192.168.1.255 up
 
-    # /sbin/ifconfig bond0 192.168.1.1 up
     # /sbin/ifenslave bond0 eth0
     # /sbin/ifenslave bond0 eth1
 
-(substitute 192.168.1.1 with your IP address and add custom network and custom
-netmask to the arguments of ifconfig if required).
+(use appropriate values for your network above)
 
-You can then create a script with these commands and put it into the appropriate
-rc directory.
+You can then create a script containing these commands and place it in the 
+appropriate rc directory.
 
-If you specifically need that all your network drivers are loaded before the
-bonding driver, use one of modutils' powerful features : in your modules.conf,
-tell that when asked for bond0, modprobe should first load all your interfaces :
+If you specifically need all network drivers loaded before the bonding driver,
+adding the following line to modules.conf will cause the network driver for 
+eth0 and eth1 to be loaded before the bonding driver.
 
 probeall bond0 eth0 eth1 bonding
 
-Be careful not to reference bond0 itself at the end of the line, or modprobe will
-die in an endless recursive loop.
-
-4) Module parameters.
----------------------
-The following module parameters can be passed:
-
-    mode=
-
-Possible values are 0 (round robin policy, default) and 1 (active backup
-policy), and 2 (XOR).  See question 9 and the HA section for additional info.
+Be careful not to reference bond0 itself at the end of the line, or modprobe 
+will die in an endless recursive loop.
 
-    miimon=
+To have device characteristics (such as MTU size) propagate to slave devices, 
+set the bond characteristics before enslaving the device.  The characteristics 
+are propagated during the enslave process.
+
+If running SNMP agents, the bonding driver should be loaded before any network 
+drivers participating in a bond. This requirement is due to the the interface 
+index (ipAdEntIfIndex) being associated to the first interface found with a 
+given IP address. That is, there is only one ipAdEntIfIndex for each IP 
+address. For example, if eth0 and eth1 are slaves of bond0 and the driver for 
+eth0 is loaded before the bonding driver, the interface for the IP address 
+will be associated with the eth0 interface. This configuration is shown below, 
+the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 
+in the ifDescr table (ifDescr.2).
+
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth3
+     interfaces.ifTable.ifEntry.ifDescr.6 = bond0
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 4
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+
+This problem is avoided by loading the bonding driver before any network
+drivers participating in a bond. Below is an example of loading the bonding 
+driver first, the IP address 192.168.1.1 is correctly associated with ifDescr.2.
+
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = bond0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.6 = eth3
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 6
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+
+While some distributions may not report the interface name in ifDescr,
+the association between the IP address and IfIndex remains and SNMP
+functions such as Interface_Scan_Next will report that association.
 
-Use integer value for the frequency (in ms) of MII link monitoring. Zero value
-is default and means the link monitoring will be disabled. A good value is 100
-if you wish to use link monitoring. See HA section for additional info.
 
-    downdelay=
-
-Use integer value for delaying disabling a link by this number (in ms) after
-the link failure has been detected. Must be a multiple of miimon. Default
-value is zero. See HA section for additional info.
+Module Parameters
+=================
 
-    updelay=
+Optional parameters for the bonding driver can be supplied as command line 
+arguments to the insmod command. Typically, these parameters are specified in 
+the file /etc/modules.conf (see the manual page for modules.conf). The 
+available bonding driver parameters are listed below. If a parameter is not 
+specified the default value is used. When initially configuring a bond, it
+is recommended "tail -f /var/log/messages" be run in a separate window to
+watch for bonding driver error messages.
+
+It is critical that either the miimon or arp_interval and arp_ip_target
+parameters be specified, otherwise serious network degradation will occur
+during link failures.
+
+max_bonds
+
+	Specifies the number of bonding devices to create for this
+	instance of the bonding driver.  E.g., if max_bonds is 3, and
+	the bonding driver is not already loaded, then bond0, bond1
+	and bond2 will be created.  The default value is 1.
+
+mode
+
+	Specifies one of four bonding policies. The default is
+round-robin (balance-rr).  Possible values are (you can use either the
+text or numeric option):
+ 
+	balance-rr or 0
+		Round-robin policy: Transmit in a sequential order
+		from the first available slave through the last. This
+		mode provides load balancing and fault tolerance.
+
+	active-backup or 1
+		Active-backup policy: Only one slave in the bond is
+		active. A different slave becomes active if, and only
+		if, the active slave fails. The bond's MAC address is
+		externally visible on only one port (network adapter)
+		to avoid confusing the switch.  This mode provides
+		fault tolerance.
+ 
+        balance-xor or 2
+		XOR policy: Transmit based on [(source MAC address
+		XOR'd with destination MAC address) modula slave
+		count]. This selects the same slave for each
+		destination MAC address. This mode provides load
+		balancing and fault tolerance.
+
+	broadcast or 3
+		Broadcast policy: transmits everything on all slave
+		interfaces. This mode provides fault tolerance.
+
+miimon
+ 
+        Specifies the frequency in milli-seconds that MII link monitoring will 
+        occur. A value of zero disables MII link monitoring. A value of 
+        100 is a good starting point. See High Availability section for 
+        additional information. The default value is 0.
+
+use_carrier
+
+        Specifies whether or not miimon should use MII or ETHTOOL
+        ioctls vs. netif_carrier_ok() to determine the link status.
+        The MII or ETHTOOL ioctls are less efficient and utilize a
+        deprecated calling sequence within the kernel.  The
+        netif_carrier_ok() relies on the device driver to maintain its
+        state with netif_carrier_on/off; at this writing, most, but
+        not all, device drivers support this facility.
+
+        If bonding insists that the link is up when it should not be,
+        it may be that your network device driver does not support
+        netif_carrier_on/off.  This is because the default state for
+        netif_carrier is "carrier on." In this case, disabling
+        use_carrier will cause bonding to revert to the MII / ETHTOOL
+        ioctl method to determine the link state.
+
+        A value of 1 enables the use of netif_carrier_ok(), a value of
+        0 will use the deprecated MII / ETHTOOL ioctls.  The default
+        value is 1.
+
+downdelay
+ 
+        Specifies the delay time in milli-seconds to disable a link after a 
+        link failure has been detected. This should be a multiple of miimon
+        value, otherwise the value will be rounded. The default value is 0.
+
+updelay
+ 
+        Specifies the delay time in milli-seconds to enable a link after a 
+        link up status has been detected. This should be a multiple of miimon
+        value, otherwise the value will be rounded. The default value is 0.
+ 
+arp_interval
+ 
+        Specifies the ARP monitoring frequency in milli-seconds. 
+        If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the 
+        switch should be configured in a mode that evenly distributes packets 
+        across all links - such as round-robin. If the switch is configured to 
+        distribute the packets in an XOR fashion, all replies from the ARP 
+        targets will be received on the same link which could cause the other 
+        team members to fail. ARP monitoring should not be used in conjunction
+        with miimon. A value of 0 disables ARP monitoring. The default value 
+        is 0.
+ 
+arp_ip_target
+ 
+        Specifies the ip addresses to use when arp_interval is > 0. These are
+        the targets of the ARP request sent to determine the health of the link
+        to the targets. Specify these values in ddd.ddd.ddd.ddd format.
+        Multiple ip adresses must be seperated by a comma. At least one ip
+        address needs to be given for ARP monitoring to work. The maximum number
+        of targets that can be specified is set at 16.
+
+primary
+
+        A string (eth0, eth2, etc) to equate to a primary device. If this 
+        value is entered, and the device is on-line, it will be used first as 
+        the output media. Only when this device is off-line, will alternate 
+        devices be used. Otherwise, once a failover is detected and a new 
+        default output is chosen, it will remain the output media until it too 
+        fails. This is useful when one slave was preferred over another, i.e. 
+        when one slave is 1000Mbps and another is 100Mbps. If the 1000Mbps 
+        slave fails and is later restored, it may be preferred the faster slave
+        gracefully become the active slave - without deliberately failing the
+        100Mbps slave. Specifying a primary is only valid in active-backup mode.
+
+multicast
+
+        Option specifying the mode of operation for multicast support.
+        Possible values are:
+
+	disabled or 0
+		Disabled (no multicast support)
+
+        active or 1
+		Enabled on active slave only, useful in active-backup mode
+
+	all or 2
+		Enabled on all slaves, this is the default
+
+
+Configuring Multiple Bonds
+==========================
+
+If several bonding interfaces are required, the driver must be loaded
+multiple times. For example, to configure two bonding interfaces with link 
+monitoring performed every 100 milli-seconds, the /etc/conf.modules should
+resemble the following:
 
-Use integer value for delaying enabling a link by this number (in ms) after
-the "link up" status has been detected. Must be a multiple of miimon. Default
-value is zero. See HA section for additional info.
+alias bond0 bonding
+alias bond1 bonding
 
-    arp_interval=
+options bond0 miimon=100
+options bond1 -o bonding1 miimon=100
 
-Use integer value for the frequency (in ms) of arp monitoring.  Zero value 
-is default and means the arp monitoring will be disabled.  See HA section
-for additional info.   This field is value in active_backup mode only.
+Configuring Multiple ARP Targets
+================================
 
-    arp_ip_target=
+While ARP monitoring can be done with just one target, it can be usefull
+in a High Availability setup to have several targets to monitor. In the
+case of just one target,  the target itself may go down or have a problem
+making it unresponsive to ARP requests. Having an additional target (or
+several) would increase the reliability of the ARP monitoring.
+Multiple ARP targets must be seperated by commas as follows:
 
-An ip address to use when arp_interval is > 0.  This is the target of the
-arp request sent to determine the health of the link to the target.  
-Specify this value in ddd.ddd.ddd.ddd format.
+# example options for ARP monitoring with three targets
+alias bond0 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
 
-If you need to configure several bonding devices, the driver must be loaded
-several times. I.e. for two bonding devices, your /etc/conf.modules must look
-like this:
+For just a single target the options would resemble:
 
+# example options for ARP monitoring with one target
 alias bond0 bonding
-alias bond1 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.100
 
-options bond0 miimon=100
-options bond1 -o bonding1 miimon=100
+Potential Problems When Using ARP Monitor
+=========================================
+
+1. Driver support
 
-5) Testing configuration
-------------------------
-You can test the configuration and transmit policy with ifconfig. For example,
-for round robin policy, you should get something like this:
+The ARP monitor relies on the network device driver to maintain two
+statistics: the last receive time (dev->last_rx), and the last
+transmit time (dev->trans_start).  If the network device driver does
+not update one or both of these, then the typical result will be that,
+upon startup, all links in the bond will immediately be declared down,
+and remain that way.  A network monitoring tool (tcpdump, e.g.) will
+show ARP requests and replies being sent and received on the bonding
+device.
+
+The possible resolutions for this are to (a) fix the device driver, or
+(b) discontinue the ARP monitor (using miimon as an alternative, for
+example).
+
+2. Adventures in Routing
+
+When bonding is set up with the ARP monitor, it is important that the
+slave devices not have routes that supercede routes of the master (or,
+generally, not have routes at all).  For example, suppose the bonding
+device bond0 has two slaves, eth0 and eth1, and the routing table is
+as follows:
+
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth0
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 eth1
+10.0.0.0        0.0.0.0         255.255.0.0     U        40 0          0 bond0
+127.0.0.0       0.0.0.0         255.0.0.0       U        40 0          0 lo
+
+In this case, the ARP monitor (and ARP itself) may become confused,
+because ARP requests will be sent on one interface (bond0), but the
+corresponding reply will arrive on a different interface (eth0).  This
+reply looks to ARP as an unsolicited ARP reply (because ARP matches
+replies on an interface basis), and is discarded.  This will likely
+still update the receive/transmit times in the driver, but will lose
+packets.
+
+The resolution here is simply to insure that slaves do not have routes
+of their own, and if for some reason they must, those routes do not
+supercede routes of their master.  This should generally be the case,
+but unusual configurations or errant manual or automatic static route
+additions may cause trouble.
+
+Switch Configuration
+====================
+
+While the switch does not need to be configured when the active-backup
+policy is used (mode=1), it does need to be configured for the round-robin, 
+XOR, and broadcast policies (mode=0, mode=2, and mode=3). 
+
+
+Verifying Bond Configuration
+============================
+
+1) Bonding information files
+----------------------------
+The bonding driver information files reside in the /proc/net/bond* directories. 
+
+Sample contents of /proc/net/bond0/info after the driver is loaded with 
+parameters of mode=0 and miimon=1000 is shown below.
+ 
+        Bonding Mode: load balancing (round-robin)
+        Currently Active Slave: eth0
+        MII Status: up
+        MII Polling Interval (ms): 1000
+        Up Delay (ms): 0
+        Down Delay (ms): 0
+ 
+        Slave Interface: eth1
+        MII Status: up
+        Link Failure Count: 1
+ 
+        Slave Interface: eth0
+        MII Status: up
+        Link Failure Count: 1
+
+2) Network verification
+-----------------------
+The network configuration can be verified using the ifconfig command. In
+the example below, the bond0 interface is the master (MASTER) while eth0 and 
+eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address 
+(HWaddr) as bond0.
 
 [root]# /sbin/ifconfig
 bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
@@ -193,12 +471,13 @@
           collisions:0 txqueuelen:100 
           Interrupt:9 Base address:0x1400 
 
-Questions :
-===========
+
+Frequently Asked Questions
+==========================
 
 1.  Is it SMP safe?
 
-	Yes.  The old 2.0.xx channel bonding patch was not SMP safe.
+	Yes. The old 2.0.xx channel bonding patch was not SMP safe.
 	The new driver was designed to be SMP safe from the start.
 
 2.  What type of cards will work with it?
@@ -209,31 +488,30 @@
 
 3.  How many bonding devices can I have?
 
-	One for each module you load. See section on module parameters for how
+	One for each module you load. See section on Module Parameters for how
 	to accomplish this.
 
 4.  How many slaves can a bonding device have?
 
-	Limited by the number of network interfaces Linux supports and the
-	number of cards you can place in your system.
+	Limited by the number of network interfaces Linux supports and/or the
+	number of network cards you can place in your system.
 
 5.  What happens when a slave link dies?
 
-	If your ethernet cards support MII status monitoring and the MII
-	monitoring has been enabled in the driver (see description of module
-	parameters), there will be no adverse consequences. This release
-	of the bonding driver knows how to get the MII information and
+	If your ethernet cards support MII or ETHTOOL link status monitoring 
+        and the MII monitoring has been enabled in the driver (see description 
+        of module parameters), there will be no adverse consequences. This 
+        release of the bonding driver knows how to get the MII information and
 	enables or disables its slaves according to their link status.
-	See section on HA for additional information.
+	See section on High Availability for additional information.
 
-	For ethernet cards not supporting MII status, or if you wish to 
-	verify that packets have been both send and received, you may
-	configure the arp_interval and arp_ip_target.  If packets have
-	not been sent or received during this interval, an arp request
-	is sent to the target to generate send and receive traffic.  
-	If after this interval, either the successful send and/or 
-	receive count has not incremented, the next slave in the sequence
-	will become the active slave.
+	For ethernet cards not supporting MII status, the arp_interval and
+        arp_ip_target parameters must be specified for bonding to work
+        correctly. If packets have not been sent or received during the
+        specified arp_interval durration, an ARP request is sent to the targets 
+        to generate send and receive traffic. If after this interval, either 
+        the successful send and/or receive count has not incremented, the next 
+        slave in the sequence will become the active slave.
 
 	If neither mii_monitor and arp_interval is configured, the bonding
 	driver will not handle this situation very well. The driver will 
@@ -245,11 +523,12 @@
 6.  Can bonding be used for High Availability?
 
 	Yes, if you use MII monitoring and ALL your cards support MII link
-	status reporting. See section on HA for more information.
+	status reporting. See section on High Availability for more information.
 
 7.  Which switches/systems does it work with?
 
-	In round-robin mode, it works with systems that support trunking:
+	In round-robin and XOR mode, it works with systems that support 
+	trunking:
 	
 	* Cisco 5500 series (look for EtherChannel support).
 	* SunTrunking software.
@@ -259,7 +538,8 @@
 	  units.
 	* Linux bonding, of course !
 	
-	In Active-backup mode, it should work with any Layer-II switches.
+	In active-backup mode, it should work with any Layer-II switche.
+
 
 8.  Where does a bonding device get its MAC address from?
 
@@ -297,55 +577,68 @@
 
 9.  Which transmit polices can be used?
 
-	Round robin, based on the order of enslaving, the output device
-	is selected base on the next available slave.  Regardless of
+	Round-robin, based on the order of enslaving, the output device
+	is selected base on the next available slave. Regardless of
 	the source and/or destination of the packet.
 
-	XOR, based on (src hw addr XOR dst hw addr) % slave cnt.  This
-	selects the same slave for each destination hw address.
-
 	Active-backup policy that ensures that one and only one device will
 	transmit at any given moment. Active-backup policy is useful for
 	implementing high availability solutions using two hubs (see
-	section on HA).
+	section on High Availability).
+
+	XOR, based on (src hw addr XOR dst hw addr) % slave count. This
+	policy selects the same slave for each destination hw address.
+
+	Broadcast policy transmits everything on all slave interfaces.
 
-High availability
+
+High Availability
 =================
 
-To implement high availability using the bonding driver, you need to
-compile the driver as module because currently it is the only way to pass
-parameters to the driver. This may change in the future.
-
-High availability is achieved by using MII status reporting. You need to
-verify that all your interfaces support MII link status reporting. On Linux
-kernel 2.2.17, all the 100 Mbps capable drivers and yellowfin gigabit driver
-support it. If your system has an interface that does not support MII status
-reporting, a failure of its link will not be detected!
-
-The bonding driver can regularly check all its slaves links by checking the
-MII status registers. The check interval is specified by the module argument
-"miimon" (MII monitoring). It takes an integer that represents the
-checking time in milliseconds. It should not come to close to (1000/HZ)
-(10 ms on i386) because it may then reduce the system interactivity. 100 ms
-seems to be a good value. It means that a dead link will be detected at most
-100 ms after it goes down.
+To implement high availability using the bonding driver, the driver needs to be
+compiled as a module, because currently it is the only way to pass parameters 
+to the driver. This may change in the future.
+
+High availability is achieved by using MII or ETHTOOL status reporting. You 
+need to verify that all your interfaces support MII or ETHTOOL link status 
+reporting.  On Linux kernel 2.2.17, all the 100 Mbps capable drivers and 
+yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting 
+is available for interface eth0, type "ethtool eth0" and the "Link detected:" 
+line should contain the correct link status. If your system has an interface 
+that does not support MII or ETHTOOL status reporting, a failure of its link 
+will not be detected! A message indicating MII and ETHTOOL is not supported by 
+a network driver is logged when the bonding driver is loaded with a non-zero 
+miimon value.
+
+The bonding driver can regularly check all its slaves links using the ETHTOOL
+IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The 
+check interval is specified by the module argument "miimon" (MII monitoring). 
+It takes an integer that represents the checking time in milliseconds. It 
+should not come to close to (1000/HZ) (10 milli-seconds on i386) because it 
+may then reduce the system interactivity. A value of 100 seems to be a good 
+starting point. It means that a dead link will be detected at most 100 
+milli-seconds after it goes down.
 
 Example:
 
    # modprobe bonding miimon=100
 
-Or, put in your /etc/modules.conf :
+Or, put the following lines in /etc/modules.conf:
 
    alias bond0 bonding
    options bond0 miimon=100
 
-There are currently two policies for high availability, depending on whether
-a) hosts are connected to a single host or switch that support trunking
-b) hosts are connected to several different switches or a single switch that
-   does not support trunking.
+There are currently two policies for high availability. They are dependent on 
+whether:
+
+   a) hosts are connected to a single host or switch that support trunking
+
+   b) hosts are connected to several different switches or a single switch that
+      does not support trunking
+
 
-1) HA on a single switch or host - load balancing
--------------------------------------------------
+1) High Availability on a single switch or host - load balancing
+----------------------------------------------------------------
 It is the easiest to set up and to understand. Simply configure the
 remote equipment (host or switch) to aggregate traffic over several
 ports (Trunk, EtherChannel, etc.) and configure the bonding interfaces.
@@ -356,7 +649,7 @@
 long time if all ports in a trunk go down. This is not Linux, but really
 the switch (reboot it to ensure).
 
-Example 1 : host to host at double speed
+Example 1 : host to host at twice the speed
 
           +----------+                          +----------+
           |          |eth0                  eth0|          |
@@ -370,7 +663,7 @@
      # ifconfig bond0 addr
      # ifenslave bond0 eth0 eth1
 
-Example 2 : host to switch at double speed
+Example 2 : host to switch at twice the speed
 
           +----------+                          +----------+
           |          |eth0                 port1|          |
@@ -384,7 +677,9 @@
      # ifconfig bond0 addr                     and port2
      # ifenslave bond0 eth0 eth1
 
-2) HA on two or more switches (or a single switch without trunking support)
+
+2) High Availability on two or more switches (or a single switch without 
+   trunking support)
 ---------------------------------------------------------------------------
 This mode is more problematic because it relies on the fact that there
 are multiple ports and the host's MAC address should be visible on one
@@ -395,12 +690,16 @@
 
 To use this mode, pass "mode=1" to the module at load time :
 
+    # modprobe bonding miimon=100 mode=active-backup
+
+	or:
+
     # modprobe bonding miimon=100 mode=1
 
 Or, put in your /etc/modules.conf :
 
     alias bond0 bonding
-    options bond0 miimon=100 mode=1
+    options bond0 miimon=100 mode=active-backup
 
 Example 1: Using multiple host and multiple switches to build a "no single
 point of failure" solution.
@@ -423,14 +722,14 @@
                +--------------+ host2 +----------------+
                          eth0 +-------+ eth1
 
-In this configuration, there are an ISL - Inter Switch Link (could be a trunk),
+In this configuration, there is an ISL - Inter Switch Link (could be a trunk),
 several servers (host1, host2 ...) attached to both switches each, and one or
 more ports to the outside world (port3...). One an only one slave on each host
 is active at a time, while all links are still monitored (the system can
 detect a failure of active and backup links).
 
 Each time a host changes its active interface, it sticks to the new one until
-it goes down. In this example, the hosts are not too much affected by the
+it goes down. In this example, the hosts are negligibly affected by the
 expiration time of the switches' forwarding tables.
 
 If host1 and host2 have the same functionality and are used in load balancing
@@ -460,6 +759,7 @@
 it goes down. In this example, the host is strongly affected by the expiration
 time of the switch forwarding table.
 
+
 3) Adapting to your switches' timing
 ------------------------------------
 If your switches take a long time to go into backup mode, it may be
@@ -486,10 +786,36 @@
 Examples :
 
     # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000
-    # modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000
+    # modprobe bonding miimon=100 mode=balance-rr downdelay=0 updelay=5000
+
+
+Promiscuous Sniffing notes
+==========================
 
-4) Limitations
---------------
+If you wish to bond channels together for a network sniffing
+application --- you wish to run tcpdump, or ethereal, or an IDS like
+snort, with its input aggregated from multiple interfaces using the
+bonding driver --- then you need to handle the Promiscuous interface
+setting by hand. Specifically, when you "ifconfing bond0 up" you
+must add the promisc flag there; it will be propagated down to the
+slave interfaces at ifenslave time; a full example might look like:
+
+   grep bond0 /etc/modules.conf || echo alias bond0 bonding >/etc/modules.conf
+   ifconfig bond0 promisc up
+   for if in eth1 eth2 ...;do
+       ifconfig $if up
+       ifenslave bond0 $if
+   done
+   snort ... -i bond0 ...
+
+Ifenslave also wants to propagate addresses from interface to
+interface, appropriately for its design functions in HA and channel
+capacity aggregating; but it works fine for unnumbered interfaces;
+just ignore all the warnings it emits.
+
+
+Limitations
+===========
 The main limitations are :
   - only the link status is monitored. If the switch on the other side is
     partially down (e.g. doesn't forward anymore, but the link is OK), the link
@@ -500,7 +826,13 @@
     Use the arp_interval/arp_ip_target parameters to count incoming/outgoing
     frames.  
 
-Resources and links
+  - A Transmit Load Balancing policy is not currently available. This mode 
+    allows every slave in the bond to transmit while only one receives. If 
+    the "receiving" slave fails, another slave takes over the MAC address of 
+    the failed receiving slave.
+
+
+Resources and Links
 ===================
 
 Current development on this driver is posted to:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/e100.txt linux-2.4.21-rc3/Documentation/networking/e100.txt
--- linux-2.4.20/Documentation/networking/e100.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/e100.txt	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-September 16, 2002
+November 19, 2002
 
 
 Contents
@@ -19,7 +19,7 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
-Adapters, version 2.1.x.  This driver includes support for Itanium(TM)-based 
+Adapters, version 2.2.x.  This driver includes support for Itanium(TM)-based 
 systems.
 
 
@@ -94,8 +94,9 @@
 Command Line Parameters
 =======================
 
-The following optional parameters are used by entering them on the command 
-line with the modprobe or insmod command using this syntax:
+If the driver is built as a module, the  following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command
+using this syntax:
 
      modprobe e100 [<option>=<VAL1>,<VAL2>,...]
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/e1000.txt linux-2.4.21-rc3/Documentation/networking/e1000.txt
--- linux-2.4.20/Documentation/networking/e1000.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/e1000.txt	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-October 12, 2002
+January 8, 2003
 
 
 Contents
@@ -20,33 +20,16 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 4.4.x.  This driver includes support for 
+of Adapters, version 5.0.x.  This driver includes support for 
 Itanium(TM)-based systems.
 
-This release version includes the following:
-
-   - Support for the ethtool 1.6 interface. A third-party application can use
-     the ethtool interface to get and set driver parameters.
-
-   - Zero copy. This feature provides faster data throughput. Enabled by
-     default in supporting kernels. It is not supported on the Intel(R)
-     PRO/1000 Gigabit Server Adapter.
-
-Features include:
-
-   - Support for the 82545 and 82546-based adapters listed below
-
-   - Wake on LAN* support via ethtool for 82540, 82544, 82545, and 82546-
-     based adapters
-
-   - Adaptive IFS for increased performance at half duplex
 
 
 
 Supported Adapters
 ==================
 
-The following Intel network adapters are compatible with the drivers in this
+The following Intel network adapters are compatible with the drivers in this 
 release:
 
    Controller  Adapter Name                         Board IDs
@@ -65,6 +48,7 @@
    82544       PRO/1000 T Desktop Adapter           A62947-xxx
 
    82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+   82541                                            C91016-xxx
 
    82545       PRO/1000 MT Server Adapter           A92165-xxx
 
@@ -77,33 +61,42 @@
    82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
 
 
-To verify your Intel adapter is supported, find the board ID number on the
-adapter. Look for a label that has a barcode and a number in the format of
-123456-001 (six digits hyphen three digits). Match this to the list of
-numbers above.
 
-For more information on how to identify your adapter, go to the Adapter &
+To verify your Intel adapter is supported, find the board ID number on the 
+adapter. Look for a label that has a barcode and a number in the format  
+A12345-001. Match this to the list of numbers above.
+
+For more information on how to identify your adapter, go to the Adapter & 
 Driver ID Guide at:
 
     http://support.intel.com/support/network/adapter/pro100/21397.htm
 
-For the latest Intel network drivers for Linux, go to:
+For the latest Intel network drivers for Linux, refer to the following
 
-    http://appsr.intel.com/scripts-df/support_intel.asp
+    http://downloadfinder.intel.com/scripts-df/support_intel.asp
 
 
 Command Line Parameters
 =======================
 
-If the driver is built as a module, the following optional parameters are 
-used by entering them on the command line with the modprobe or insmod command. 
+If the driver is built as a module, the  following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command
+using this syntax:
+
+     modprobe e1000 [<option>=<VAL1>,<VAL2>,...]
+
+     insmod e1000 [<option>=<VAL1>,<VAL2>,...] 
+
 For example, with two PRO/1000 PCI adapters, entering:
 
-    insmod e1000 TxDescriptors=80,128
+     insmod e1000 TxDescriptors=80,128
 
-loads the e1000 driver with 80 TX resources for the first adapter and 128 TX
+loads the e1000 driver with 80 TX resources for the first adapter and 128 TX 
 resources for the second adapter.
 
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
 For more information about the AutoNeg, Duplex, and Speed parameters, see the
 "Speed and Duplex Configuration" section in this document.
 
@@ -129,6 +122,20 @@
     This parameter controls the automatic generation(Tx) and response(Rx) to 
     Ethernet PAUSE frames.
 
+InterruptThrottleRate
+Valid Range: 100-100000 (0=off, 1=dynamic)
+Default Value: 1
+    This value represents the maximum number of interrupts per second the 
+    controller generates. InterruptThrottleRate is another setting used in 
+    interrupt moderation. Dynamic mode uses a heuristic algorithm to adjust 
+    InterruptThrottleRate based on the current traffic load.
+
+    NOTE: InterruptThrottleRate takes precedence over the TxAbsIntDelay and 
+          RxAbsIntDelay parameters. In other words, minimizing the receive 
+          and/or transmit absolute delays does not force the controller to 
+          generate more interrupts than what the Interrupt Throttle Rate 
+          allows.
+
 RxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
              80-4096 for 82540, 82544, 82545, and 82546-based adapters
@@ -154,9 +161,9 @@
     descriptors.
 
     CAUTION: When setting RxIntDelay to a value other than 0, adapters may 
-             hang (stop transmitting) under certain network conditions. If
+             hang (stop transmitting) under certain network conditions. If 
              this occurs a NETDEV WATCHDOG message is logged in the system
-             event log. In addition, the controller is automatically reset,
+             event log. In addition, the controller is automatically reset, 
              restoring the network connection. To eliminate the potential for
              the hang ensure that RxIntDelay is set to 0.
 
@@ -176,7 +183,7 @@
     Speed forces the line speed to the specified value in megabits per second
     (Mbps). If this parameter is not specified or is set to 0 and the link 
     partner is set to auto-negotiate, the board will auto-detect the correct 
-    speed. Duplex must also be set when Speed is set to either 10 or 100.
+    speed. Duplex should also be set when Speed is set to either 10 or 100.
 
 TxDescriptors
 Valid Range: 80-256 for 82542 and 82543-based adapters
@@ -190,7 +197,7 @@
 Valid Range: 0-65535 (0=off)
 Default Value: 64
     This value delays the generation of transmit interrupts in units of 
-    1.024 microseconds.  Transmit interrupt reduction can improve CPU
+    1.024 microseconds. Transmit interrupt reduction can improve CPU
     efficiency if properly tuned for specific network traffic. If the
     system is reporting dropped transmits, this value may be set too high
     causing the driver to run out of available transmit descriptors.
@@ -205,7 +212,7 @@
     along with TxIntDelay, may improve traffic throughput in specific 
     network conditions.
 
-XsumRX (not available on the PRO/1000 Gigabit Server Adapter)
+XsumRX (not available on the 82542-based adapter)
 Valid Range: 0-1
 Default Value: 1
     A value of '1' indicates that the driver should enable IP checksum
@@ -215,10 +222,10 @@
 Speed and Duplex Configuration
 ==============================
 
-Three keywords are used to control the speed and duplex configuration. These
+Three keywords are used to control the speed and duplex configuration. These 
 keywords are Speed, Duplex, and AutoNeg.
 
-If the board uses a fiber interface, these keywords are ignored, and the
+If the board uses a fiber interface, these keywords are ignored, and the 
 fiber interface board only links at 1000 Mbps full-duplex.
 
 For copper-based boards, the keywords interact as follows:
@@ -230,23 +237,23 @@
   If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is
   advertised (The 1000BaseT spec requires auto-negotiation.)
 
-  If Speed = 10 or 100, then both Speed and Duplex must be set. Auto-
-  negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST
+  If Speed = 10 or 100, then both Speed and Duplex should be set. Auto-
+  negotiation is disabled, and the AutoNeg parameter is ignored. Partner SHOULD
   also be forced.
 
 The AutoNeg parameter is used when more control is required over the auto-
-negotiation process.  When this parameter is used, Speed and Duplex must not
-be specified.  This parameter is a bitmap that specifies which speed and
+negotiation process.  When this parameter is used, Speed and Duplex must not 
+be specified.  This parameter is a bitmap that specifies which speed and 
 duplex settings are advertised to the link partner.
 
 Bit            7      6      5       4       3      2      1       0
 Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
 Duplex                       Full            Full   Half   Full    Half
 
-Note that setting AutoNeg does not guarantee that the board will link at the
-highest specified speed or duplex mode, but the board will link at the
+Note that setting AutoNeg does not guarantee that the board will link at the 
+highest specified speed or duplex mode, but the board will link at the 
 highest possible speed/duplex of the link partner IF the link partner is also
-set to auto-negotiate. If the link partner is forced speed/duplex, the
+set to auto-negotiate. If the link partner is forced speed/duplex, the 
 adapter MUST be forced to the same speed/duplex.
 
 
@@ -256,13 +263,19 @@
   Jumbo Frames
   ------------
 
-  The driver supports Jumbo Frames for all adapters except 82542-based
-  adapters.  Jumbo Frames support is enabled by changing the MTU to a value
-  larger than the default of 1500.  Use the ifconfig command to increase the
+  The driver supports Jumbo Frames for all adapters except 82542-based 
+  adapters. Jumbo Frames support is enabled by changing the MTU to a value 
+  larger than the default of 1500. Use the ifconfig command to increase the 
   MTU size. For example:
 
         ifconfig ethx mtu 9000 up
 
+  The maximum MTU setting for Jumbo Frames is 16110. This value coincides 
+  with the maximum Jumbo Frames size of 16128.
+
+  NOTE: Jumbo Frames are supported at 1000 Mbps only. Using Jumbo Frames at 
+  10 or 100 Mbps may result in poor performance or loss of link.
+
 
 Known Issues
 ============
@@ -270,33 +283,33 @@
   Jumbo Frames System Requirement
   -------------------------------
 
-  Memory allocation failures have been observed on Linux systems with 64 MB
-  of RAM or less that are running Jumbo Frames. If you are using Jumbo
-  Frames, your system may require more than the advertised minimum
+  Memory allocation failures have been observed on Linux systems with 64 MB 
+  of RAM or less that are running Jumbo Frames. If you are using Jumbo 
+  Frames, your system may require more than the advertised minimum 
   requirement of 64 MB of system memory.
 
 
 Support
 =======
 
-For general information and support, go to the Intel support website at:
+For general information, go to the Intel support website at:
 
     http://support.intel.com
 
 If an issue is identified with the released source code on the supported
-kernel with a supported adapter, email the specific information related to
+kernel with a supported adapter, email the specific information related to 
 the issue to linux.nics@intel.com.
 
 
 License
 =======
 
-This software program is released under the terms of a license agreement
-between you ('Licensee') and Intel. Do not use or load this software or any
-associated materials (collectively, the 'Software') until you have carefully
-read the full terms and conditions of the LICENSE located in this software
-package. By loading or using the Software, you agree to the terms of this
-Agreement. If you do not agree with the terms of this Agreement, do not
+This software program is released under the terms of a license agreement 
+between you ('Licensee') and Intel. Do not use or load this software or any 
+associated materials (collectively, the 'Software') until you have carefully 
+read the full terms and conditions of the LICENSE located in this software 
+package. By loading or using the Software, you agree to the terms of this 
+Agreement. If you do not agree with the terms of this Agreement, do not 
 install or use the Software.
 
 * Other names and brands may be claimed as the property of others.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/generic-hdlc.txt linux-2.4.21-rc3/Documentation/networking/generic-hdlc.txt
--- linux-2.4.20/Documentation/networking/generic-hdlc.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/generic-hdlc.txt	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,115 @@
+Generic HDLC layer for Linux kernel 2.4/2.5
+Krzysztof Halasa <khc@pm.waw.pl>
+May, 2001
+
+
+Generic HDLC layer currently supports:
+- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP),
+- raw HDLC (IPv4 only),
+- Cisco HDLC,
+- PPP (uses syncppp.c),
+- X.25 (uses X.25 routines).
+
+There are hardware drivers for the following cards:
+- C101 by Moxa Technologies Co., Ltd.
+- RISCom/N2 by SDL Communications Inc.
+- and others, some not in the official kernel.
+
+Make sure the hdlc.o and the hardware driver are loaded. It should
+create a number of "hdlc" (hdlc0 etc) network devices, one for each
+WAN port. You'll need the "sethdlc" utility, get it from:
+	http://hq.pm.waw.pl/hdlc/
+
+Compile sethdlc.c utility:
+	gcc -O2 -Wall -o sethdlc sethdlc.c
+Make sure you're using a correct version of sethdlc for your kernel.
+
+Use sethdlc to set physical interface, clock rate, HDLC mode used,
+and add any required PVCs if using Frame Relay.
+Usually you want something like:
+
+	sethdlc hdlc0 clock int rate 128000
+	sethdlc hdlc0 cisco interval 10 timeout 25
+or
+	sethdlc hdlc0 rs232 clock ext
+	sethdlc fr lmi ansi
+	sethdlc create 99
+
+In Frame Relay mode, ifconfig master hdlc device up (without assigning
+any IP address to it) before using pvc devices.
+
+
+Setting interface:
+
+* v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port
+                                if the card has software-selectable interfaces
+  loopback - activate hardware loopback (for testing only)
+* clock ext - external clock (uses DTE RX and TX clock)
+* clock int - internal clock (provides clock signal on DCE clock output)
+* clock txint - TX internal, RX external (provides TX clock on DCE output)
+* clock txfromrx - TX clock derived from RX clock (TX clock on DCE output)
+* rate - sets clock rate in bps (not required for external clock or
+                                 for txfromrx)
+
+Setting protocol:
+
+* hdlc - sets raw HDLC (IP-only) mode
+  nrz / nrzi / fm-mark / fm-space / manchester - sets transmission code
+  no-parity / crc16 / crc16-pr0 (CRC16 with preset zeros) / crc32-itu
+  crc16-itu (CRC16 with ITU-T polynomial) / crc16-itu-pr0 - sets parity
+
+* cisco - sets Cisco HDLC mode (IP, IPv6 and IPX supported)
+  interval - time in seconds between keepalive packets
+  timeout - time in seconds after last received keepalive packet before
+            we assume the link is down
+
+* ppp - sets synchronous PPP mode
+
+* x25 - sets X.25 mode
+
+* fr - Frame Relay mode
+  lmi ansi / ccitt / none - LMI (link management) type
+  dce - Frame Relay DCE (network) side LMI instead of default DTE (user).
+  It has nothing to do with clocks!
+  t391 - link integrity verification polling timer (in seconds) - user
+  t392 - polling verification timer (in seconds) - network
+  n391 - full status polling counter - user
+  n392 - error threshold - both user and network
+  n393 - monitored events count - both user and network
+
+* create | delete n - FR only - adds / deletes PVC interface with DLCI #n.
+
+
+
+
+Board-specific issues
+---------------------
+
+n2.o and c101.o need parameters to work (note double quotes):
+
+	insmod n2 hw='"io,irq,ram,ports[:io,irq,...]"'
+example:
+	insmod n2 hw='"0x300,10,0xD0000,01"'
+
+or
+	insmod c101 hw='"irq,ram[:irq,...]"
+example:
+	insmod c101 hw='"9,0xdc000"'
+
+If built into the kernel, these drivers need kernel (command line) parameters:
+	n2=io,irq,ram,ports:...
+or
+	c101=irq,ram:...
+
+
+
+If you have a problem with N2 or C101 card, you can issue the "private"
+command to see port's packet descriptor rings:
+
+	sethdlc hdlc0 private
+
+The hardware driver have to be build with CONFIG_HDLC_DEBUG_RINGS.
+Attaching this info to bug reports would be helpful. Anyway, let me know
+if you have problems using this.
+
+For patches and other info look at http://hq.pm.waw.pl/hdlc/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/ifenslave.c linux-2.4.21-rc3/Documentation/networking/ifenslave.c
--- linux-2.4.20/Documentation/networking/ifenslave.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/ifenslave.c	2003-05-22 22:06:28.000000000 +0000
@@ -41,6 +41,16 @@
  *    - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
  *       - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
  *         SIOCGIFFLAGS now called before hwaddr_notset test
+ *
+ *    - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
+ *       - If the master does not have a hardware address when the first slave
+ *         is enslaved, the master is assigned the hardware address of that 
+ *         slave - there is a comment in bonding.c stating "ifenslave takes 
+ *         care of this now." This corrects the problem of slaves having 
+ *         different hardware addresses in active-backup mode when 
+ *         multiple interfaces are specified on a single ifenslave command
+ *         (ifenslave bond0 eth0 eth1).
+ *
  */
 
 static char *version =
@@ -131,6 +141,7 @@
 	sa_family_t master_family;
 	char **spp, *master_ifname, *slave_ifname;
 	int hwaddr_notset;
+	int master_up;
 
 	while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF)
 		switch (c) {
@@ -300,10 +311,86 @@
 				return 1;
 			}
 
-			if (hwaddr_notset) { /* we do nothing */
+			if (hwaddr_notset) {
+				/* assign the slave hw address to the 
+				 * master since it currently does not 
+				 * have one; otherwise, slaves may
+				 * have different hw addresses in 
+				 * active-backup mode as seen when enslaving 
+				 * using "ifenslave bond0 eth0 eth1" because
+				 * hwaddr_notset is set outside this loop.
+				 * TODO: put this and the "else" portion in
+				 *       a function.
+				 */
+				goterr = 0;
+				master_up = 0;
+				if (if_flags.ifr_flags & IFF_UP) {
+					if_flags.ifr_flags &= ~IFF_UP;
+					if (ioctl(skfd, SIOCSIFFLAGS, 
+							&if_flags) < 0) {
+						goterr = 1;
+						fprintf(stderr, 
+							"Shutting down "
+							"interface %s failed: "
+							"%s\n",
+							master_ifname, 
+							strerror(errno));
+					} else {
+						/* we took the master down, 
+						 * so we must bring it up 
+						 */
+						master_up = 1; 
+					}
+				}
 
-			}
-			else {  /* we'll assign master's hwaddr to this slave */
+				if (!goterr) {
+					/* get the slaves MAC address */
+					strncpy(if_hwaddr.ifr_name, 
+							slave_ifname, IFNAMSIZ);
+					if (ioctl(skfd, SIOCGIFHWADDR, 
+							&if_hwaddr) < 0) {
+						fprintf(stderr, 
+							"Could not get MAC "
+							"address of %s: %s\n",
+							slave_ifname, 
+							strerror(errno));
+						strncpy(if_hwaddr.ifr_name, 
+							master_ifname, 
+							IFNAMSIZ);
+						goterr=1;
+					}
+				}
+
+				if (!goterr) {
+					strncpy(if_hwaddr.ifr_name, 
+						master_ifname, IFNAMSIZ);
+					if (ioctl(skfd, SIOCSIFHWADDR, 
+							&if_hwaddr) < 0) {
+						fprintf(stderr, 
+							"Could not set MAC "
+							"address of %s: %s\n",
+							master_ifname, 
+							strerror(errno));
+						goterr=1;
+					} else {
+						hwaddr_notset = 0;
+					}
+				}
+
+				if (master_up) {
+					if_flags.ifr_flags |= IFF_UP;
+					if (ioctl(skfd, SIOCSIFFLAGS, 
+							&if_flags) < 0) {
+						fprintf(stderr, 
+							"Bringing up interface "
+							"%s failed: %s\n",
+							master_ifname, 
+							strerror(errno));
+					}
+				}
+
+			} else {  
+				/* we'll assign master's hwaddr to this slave */
 				if (ifr2.ifr_flags & IFF_UP) {
 					ifr2.ifr_flags &= ~IFF_UP;
 					if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/ip-sysctl.txt linux-2.4.21-rc3/Documentation/networking/ip-sysctl.txt
--- linux-2.4.20/Documentation/networking/ip-sysctl.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/ip-sysctl.txt	2003-05-22 22:06:42.000000000 +0000
@@ -281,6 +281,14 @@
 	asassination.	
 	Default: 0
 
+tcp_low_latency - BOOLEAN
+	If set, the TCP stack makes decisions that prefer lower
+	latency as opposed to higher throughput.  By default, this
+	option is not set meaning that higher throughput is preferred.
+	An example of an application where this default should be
+	changed would be a Beowulf compute cluster.
+	Default: 0
+
 ip_local_port_range - 2 INTEGERS
 	Defines the local port range that is used by TCP and UDP to
 	choose the local port. The first number is the first, the 
@@ -351,15 +359,26 @@
 	Change the maximum number of multicast groups we can subscribe to.
 	Default: 20
 
-conf/interface/*: 
-conf/all/* is special and changes the settings for all interfaces.
-	Change special settings per interface.
+conf/interface/*  changes special settings per interface (where "interface" is 
+		  the name of your network interface)
+conf/all/*	  is special, changes the settings for all interfaces
+
 
 log_martians - BOOLEAN
 	Log packets with impossible addresses to kernel log.
+	log_martians for the interface will be enabled if at least one of
+	conf/{all,interface}/log_martians is set to TRUE,
+	it will be disabled otherwise
 
 accept_redirects - BOOLEAN
 	Accept ICMP redirect messages.
+	accept_redirects for the interface will be enabled if:
+	- both conf/{all,interface}/accept_redirects are TRUE in the case forwarding
+	  for the interface is enabled
+	or
+	- at least one of conf/{all,interface}/accept_redirects is TRUE in the case
+	  forwarding for the interface is disabled
+	accept_redirects for the interface will be disabled otherwise
 	default TRUE (host)
 		FALSE (router)
 
@@ -369,6 +388,8 @@
 mc_forwarding - BOOLEAN
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
+	conf/all/mc_forwarding must also be set to TRUE to enable multicast routing
+	for the interface
 
 medium_id - INTEGER
 	Integer value used to differentiate the devices by the medium they
@@ -383,30 +404,46 @@
 
 proxy_arp - BOOLEAN
 	Do proxy arp.
+	proxy_arp for the interface will be enabled if at least one of
+	conf/{all,interface}/proxy_arp is set to TRUE,
+	it will be disabled otherwise
 
 shared_media - BOOLEAN
 	Send(router) or accept(host) RFC1620 shared media redirects.
 	Overrides ip_secure_redirects.
+	shared_media for the interface will be enabled if at least one of
+	conf/{all,interface}/shared_media is set to TRUE,
+	it will be disabled otherwise
 	default TRUE
 
 secure_redirects - BOOLEAN
 	Accept ICMP redirect messages only for gateways,
 	listed in default gateway list.
+	secure_redirects for the interface will be enabled if at least one of
+	conf/{all,interface}/secure_redirects is set to TRUE,
+	it will be disabled otherwise
 	default TRUE
 
 send_redirects - BOOLEAN
-	Send redirects, if router. Default: TRUE
+	Send redirects, if router.
+	send_redirects for the interface will be enabled if at least one of
+	conf/{all,interface}/send_redirects is set to TRUE,
+	it will be disabled otherwise
+	Default: TRUE
 
 bootp_relay - BOOLEAN
 	Accept packets with source address 0.b.c.d destined
 	not to this host as local ones. It is supposed, that
 	BOOTP relay daemon will catch and forward such packets.
-
+	conf/all/bootp_relay must also be set to TRUE to enable BOOTP relay
+	for the interface
 	default FALSE
 	Not Implemented Yet.
 
 accept_source_route - BOOLEAN
 	Accept packets with SRR option.
+	conf/all/accept_source_route must also be set to TRUE to accept packets
+	with SRR option on the interface
 	default TRUE (router)
 		FALSE (host)
 
@@ -417,7 +454,10 @@
 	    networks running a slow unreliable protocol (sort of RIP),
 	    or using static routes.
 
-	0 - No source validation. 
+	0 - No source validation.
+
+	conf/all/rp_filter must also be set to TRUE to do source validation
+	on the interface
 
 	Default value is 0. Note that some distributions enable it
 	in startup scripts.
@@ -437,6 +477,10 @@
 	particular interfaces. Only for more complex setups like load-
 	balancing, does this behaviour cause problems.
 
+	arp_filter for the interface will be enabled if at least one of
+	conf/{all,interface}/arp_filter is set to TRUE,
+	it will be disabled otherwise
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
@@ -451,8 +495,8 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-
-
+Nicolas Delon
+delon.nicolas@wanadoo.fr
 
 
 
@@ -462,6 +506,15 @@
 IPv6 has no global variables such as tcp_*.  tcp_* settings under ipv4/ also
 apply to IPv6 [XXX?].
 
+bindv6only - BOOLEAN
+	Default value for IPV6_V6ONLY socket option,
+	which restricts use of the IPv6 socket to IPv6 communication 
+	only.
+		TRUE: disable IPv4-mapped address feature
+		FALSE: enable IPv4-mapped address feature
+
+	Default: FALSE (as specified in RFC2553bis)
+
 conf/default/*:
 	Change the interface-specific default settings.
 
@@ -560,8 +613,14 @@
 	routers are present.
 	Default: 3
 
+icmp/*:
+ratelimit - INTEGER
+	Limit the maximal rates for sending ICMPv6 packets.
+	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
+	Default: 100
+
 IPv6 Update by:
-Pekka Savola
-pekkas@netcore.fi
+Pekka Savola <pekkas@netcore.fi>
+YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
 
 $Id: ip-sysctl.txt,v 1.19.2.1 2001/12/13 08:59:27 davem Exp $
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/netdevices.txt linux-2.4.21-rc3/Documentation/networking/netdevices.txt
--- linux-2.4.20/Documentation/networking/netdevices.txt	2000-11-09 03:09:49.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/netdevices.txt	2003-05-22 22:06:38.000000000 +0000
@@ -12,31 +12,39 @@
 struct net_device synchronization rules
 =======================================
 dev->open:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->stop:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
+	Note1: netif_running() is guaranteed false
+	Note2: dev->poll() is guaranteed to be stopped
 
 dev->do_ioctl:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->get_stats:
-	Locking: Inside dev_base_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev_base_lock rwlock.
+	Context: nominally process, but don't sleep inside an rwlock
 
 dev->hard_start_xmit:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
+	Notes: netif_queue_stopped() is guaranteed false
 
 dev->tx_timeout:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
+	Notes: netif_queue_stopped() is guaranteed true
 
 dev->set_multicast_list:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
 
+dev->poll:
+	Synchronization: __LINK_STATE_RX_SCHED bit in dev->state.  See
+		dev_close code and comments in net/core/dev.c for more info.
+	Context: softirq
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/pktgen.txt linux-2.4.21-rc3/Documentation/networking/pktgen.txt
--- linux-2.4.20/Documentation/networking/pktgen.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/pktgen.txt	2003-05-22 22:06:52.000000000 +0000
@@ -6,7 +6,7 @@
 3. Edit script to set preferred device and destination IP address.
 3a.  Create more scripts for different interfaces.  Up to thirty-two
      pktgen processes can be configured and run at once by using the
-     32 /proc/net/pg* files.
+     32 /proc/net/pktgen/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -52,7 +52,7 @@
 
 modprobe pktgen
 
-PGDEV=/proc/net/pg/pg0
+PGDEV=/proc/net/pktgen/pg0
 
 function pgset() {
     local result
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/sk98lin.txt linux-2.4.21-rc3/Documentation/networking/sk98lin.txt
--- linux-2.4.20/Documentation/networking/sk98lin.txt	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/networking/sk98lin.txt	2003-05-22 22:06:50.000000000 +0000
@@ -1,120 +1,158 @@
-(C)Copyright 1999-2001 SysKonnect GmbH.
+(C)Copyright 1999-2002 SysKonnect GmbH.
 All rights reserved
 ===========================================================================
 
-sk98lin.txt created 28-May-2001
+sk98lin.txt created 19-Dec-2002
 
-Readme File for sk98lin v4.06
-SK-NET Gigabit Ethernet PCI driver for LINUX
+Readme File for sk98lin v6.02
+SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX
 
 This file contains
-(1) OVERVIEW
-(2) REQUIRED FILES
-(3) INSTALLATION
-(4) INCLUSION OF ADAPTER AT SYSTEM START
-(5) DRIVER PARAMETERS
-(6) LARGE FRAME SUPPORT
-(7) TROUBLESHOOTING
-(8) HISTORY
+ 1  Overview
+ 2  Required Files
+ 3  Installation
+    3.1  Driver Installation
+    3.2  Inclusion of adapter at system start
+ 4  Driver Parameters
+    4.1  Per-Port Parameters
+    4.2  Adapter Parameters
+ 5  Large Frame Support
+ 6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+ 7  Troubleshooting
+ 8  History
 
 ===========================================================================
 
 
-(1) OVERVIEW
-============
+1  Overview
+===========
 
-The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet
-Adapter SK-98xx family on Linux 2.2.x and above.
-It has been tested with Linux on Intel/x86 machines.
-From v3.02 on, the driver is integrated in the linux kernel source.
+The sk98lin driver supports the SysKonnect SK-98xx and SK-95xx family 
+on Linux. It has been tested with Linux on Intel/x86 machines.
 ***
 
 
-(2) REQUIRED FILES
-==================
+2  Required Files
+=================
 
 The linux kernel source.
 No additional files required.
 ***
 
 
-(3) INSTALLATION
-================
+3  Installation
+===============
+
+It is recommended to download the latest version of the driver from the 
+SysKonnect web site www.syskonnect.com. If you have downloaded the latest
+driver, the Linux kernel has to be patched before the driver can be 
+installed. For details on how to patch a Linux kernel, refer to the 
+patch.txt file.
+
+3.1  Driver Installation
+------------------------
 
 The following steps describe the actions that are required to install
 the driver and to start it manually. These steps should be carried
 out for the initial driver setup. Once confirmed to be ok, they can
-be included in the system start which is described in the next
-chapter.
+be included in the system start.
 
-NOTE 1: You must have 'root' access to the system to perform
-        the following tasks.
-NOTE 2:	IMPORTANT: In case of problems, please read the section
-	"Troubleshooting" below.
-
-1) The driver can either be integrated into the kernel or it can
-   be compiled as a module.
-   Select the appropriate option during the kernel configuration.
-   For use as a module, your kernel must have
-   'loadable module support' enabled.
-   For automatic driver start, you also need 'Kernel module loader'
-   enabled.
-   Configure those options, build and install the new kernel. If you
-   choose to use the driver as a module, do "make modules" and
-   "make modules_install".
-   Reboot your system.
-
-2) Load the module manually by entering:
-       modprobe sk98lin
-   If the SysKonnect SK-98xx adapter is installed in your
-   computer and you have a /proc filesystem, running the command
-   'more /proc/net/dev' should produce an output containing a
-   line with the following format:
-       eth0:    0    0 ...
-   which means that your adapter has been found and initialized.
+NOTE 1: To perform the following tasks you need 'root' access.
+
+NOTE 2: In case of problems, please read the section "Troubleshooting" 
+        below.
+
+The driver can either be integrated into the kernel or it can be compiled 
+as a module. Select the appropriate option during the kernel 
+configuration.
+
+Compile/use the driver as a module
+----------------------------------
+To compile the driver, go to the directory /usr/src/linux and
+execute the command "make menuconfig" or "make xconfig" and proceed as 
+follows:
+
+To integrate the driver permanently into the kernel, proceed as follows:
+
+1. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+2. Mark "SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter
+   family support" with (*) 
+3. Build a new kernel when the configuration of the above options is 
+   finished.
+4. Install the new kernel.
+5. Reboot your system.
+
+To use the driver as a module, proceed as follows:
+
+1. Enable 'loadable module support' in the kernel.
+2. For automatic driver start, enable the 'Kernel module loader'.
+3. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+4. Mark "SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter
+   family support" with (M)
+5. Execute the command "make modules".
+6. Execute the command "make modules_install".
+   The appropiate modules will be installed.
+7. Reboot your system.
+
+
+Load the module manually
+------------------------
+To load the module manually, proceed as follows:
+
+1. Enter "modprobe sk98lin".
+2. If the SysKonnect SK-98xx adapter is installed in your computer and you
+   have a /proc file system, execute the command:
+   "ls /proc/net/sk98lin/" 
+   This should produce an output containing a line with the following 
+   format:
+   eth0   eth1  ...
+   which indicates that your adapter has been found and initialized.
    
-   NOTE 1: If you have more than one SysKonnect SK-98xx adapter, the
-           adapters will be listed as 'eth0', 'eth1', 'eth2', etc.
-           For each adapter, repeat the steps 3) and 4).
-   NOTE 2: If you have other Ethernet adapters installed,
-           your SysKonnect SK-98xx adapter can be mapped to 'eth1' or
-	   'eth2' ...
-	   The module installation message (in system logfile or
-	   on console, depending on /etc/syslog.conf) prints a line
-	   for each adapter that is found, containing the
-	   corresponding 'ethX'.
+   NOTE 1: If you have more than one SysKonnect SK-98xx adapter installed,
+           the adapters will be listed as 'eth0', 'eth1', 'eth2', etc.
+           For each adapter, repeat steps 3 and 4 below.
+
+   NOTE 2: If you have other Ethernet adapters installed, your SysKonnect
+           SK-98xx adapter will be mapped to the next available number, 
+           e.g. 'eth1'. The mapping is executed automatically.
+           The module installation message (displayed either in a system
+           log file or on the console) prints a line for each adapter 
+           found containing the corresponding 'ethX'.
 
-3) Select an IP address and assign it to the respective adapter by
+3. Select an IP address and assign it to the respective adapter by 
    entering:
-       ifconfig eth0 <ip-address>
-   This causes the adapter to connect to the ethernet. The solitary
-   yellow LED at the adapter is now active, the link status LED of
-   the primary port is on and the link status LED of the secondary
-   port (on dual port adapters) is blinking (only if the laters are
-   connected to a switch or hub).
-   You will also get a status message on the console saying
-   "ethX: network connection up using port Y" and indicating
-   the selected connection parameters.
+   ifconfig eth0 <ip-address>
+   With this command, the adapter is connected to the Ethernet. 
    
+   SK-98xx Gigabit Ethernet Server Adapters: The yellow LED on the adapter 
+   is now active, the link status LED of the primary port is active and 
+   the link status LED of the secondary port (on dual port adapters) is 
+   blinking (if the ports are connected to a switch or hub).
+   SK-98xx V2.0 Gigabit Ethernet Adapters: The link status LED is active.
+   In addition, you will receive a status message on the console stating
+   "ethX: network connection up using port Y" and showing the selected 
+   connection parameters (x stands for the ethernet device number 
+   (0,1,2, etc), y stands for the port name (A or B)).
+
    NOTE: If you are in doubt about IP addresses, ask your network
          administrator for assistance.
+  
+4. Your adapter should now be fully operational.
+   Use 'ping <otherstation>' to verify the connection to other computers 
+   on your network.
+5. To check the adapter configuration view /proc/net/sk98lin/[devicename].
+   For example by executing:	
+   "cat /proc/net/sk98lin/eth0" 
+
+Unload the module
+-----------------
+To stop and unload the driver modules, proceed as follows:
 
-4) Your adapter should now be fully operational.
-   Use 'ping <otherstation>' to verify the connection to other
-   computers on your network.
-   By viewing /proc/net/sk98lin/[devicename], you can check some 
-   information regarding to the adapter configuration.
-
-
-5) The driver module can be stopped and unloaded using the following
-   commands:
-       ifconfig eth0 down
-       rmmod sk98lin
-***
-
+1. Execute the command "ifconfig eth0 down".
+2. Execute the command "rmmod sk98lin".
 
-(4) INCLUSION OF ADAPTER AT SYSTEM START
-========================================
+3.2  Inclusion of adapter at system start
+-----------------------------------------
 
 Since a large number of different Linux distributions are 
 available, we are unable to describe a general installation procedure
@@ -122,41 +160,45 @@
 Because the driver is now integrated in the kernel, installation should
 be easy, using the standard mechanism of your distribution.
 Refer to the distribution's manual for installation of ethernet adapters.
+
 ***
 
+4  Driver Parameters
+====================
 
-(5) DRIVER PARAMETERS
-=====================
+Parameters can be set at the command line after the module has been 
+loaded with the command 'modprobe'.
+In some distributions, the configuration tools are able to pass parameters
+to the driver module.
 
-Parameters can be set at the command line while loading the
-module with 'modprobe'. The configuration tools of some distributions
-can also give parameters to the driver module.
 If you use the kernel module loader, you can set driver parameters
 in the file /etc/modules.conf (or old name: /etc/conf.modules).
-Insert a line of the form:
-
-options sk98lin ...
+To set the driver parameters in this file, proceed as follows:
 
-For "...", use the same syntax as described below for the command
-line paramaters of modprobe.
-You either have to reboot your computer or unload and reload
-the driver to activate the new parameters.
-The syntax of the driver parameters is:
-
-modprobe sk98lin parameter=value1[,value2[,value3...]]
-
-value1 is for the first adapter, value2 for the second one etc.
-All Parameters are case sensitive, so write them exactly as
-shown below.
-
-Sample: Suppose you have two adapters. You want to set AutoNegotiation
-	on Port A of the first adapter to ON and on Port A of the
-	second adapter to OFF.
-	You also want to set DuplexCapabilities on Port A of the first
-	adapter to FULL and on Port A of the second adapter to HALF.
-	You must enter:
+1. Insert a line of the form :
+   options sk98lin ...
+   For "...", the same syntax is required as described for the command
+   line paramaters of modprobe below.
+2. To activate the new parameters, either reboot your computer
+   or 
+   unload and reload the driver.
+   The syntax of the driver parameters is:
+
+ 	modprobe sk98lin parameter=value1[,value2[,value3...]]
+
+   where value1 refers to the first adapter, value2 to the second etc.
+
+NOTE: All parameters are case sensitive. Write them exactly as shown 
+      below.
+
+Example:
+Suppose you have two adapters. You want to set auto-negotiation
+on the first adapter to ON and on the second adapter to OFF.
+You also want to set DuplexCapabilities on the first adapter
+to FULL, and on the second adapter to HALF.
+Then, you must enter:
 
-	modprobe sk98lin AutoNeg_A=On,Off DupCap_A=Full,Half
+ 	modprobe sk98lin AutoNeg=On,Off DupCap=Full,Half
 
 NOTE: The number of adapters that can be configured this way is
       limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM).
@@ -164,221 +206,324 @@
       more adapters, adjust this and recompile.
 
 
-5.1 Per-Port Parameters
------------------------
-Those setting are available for each port on the adapter.
+4.1  Per-Port Parameters
+------------------------
+
+These settings are available for each port on the adapter.
 In the following description, '?' stands for the port for
 which you set the parameter (A or B).
 
-- Auto Negotiation
-  Parameter:	AutoNeg_?
-  Values:	On, Off, Sense
-  Default:	Sense
+Speed
+-----
+Parameter:    Speed_?
+Values:       10, 100, 1000, Auto
+Default:      Auto
+
+This parameter is used to set the speed capabilities. It is only valid 
+for the SK-98xx V2.0 copper adapters.
+Usually, the speed is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
+
+Auto-Negotiation
+----------------
+Parameter:    AutoNeg_?
+Values:       On, Off, Sense
+Default:      On
   
-  The "Sense"-mode finds out automatically whether the link
-  partner supports autonegotiation or not.
+The "Sense"-mode automatically detects whether the link partner supports
+auto-negotiation or not.
 
-- Duplex Capabilities
-  Parameter:	DupCap_?
-  Values:	Half, Full, Both
-  Default:	Both
-
-  This parameters is relevant only if autonegotiation for
-  this port is not "Sense". If autonegotiation is "On", all
-  three values are possible. If it is "Off", only "Full" and
-  "Half" are allowed.
-  It is usefull if your link partner does not support all
-  possible combinations.
-
-- Flow Control
-  Parameter:	FlowCtrl_?
-  Values:	Sym, SymOrRem, LocSend, None
-  Default:	SymOrRem
-
-  This parameter can be used to set the flow control capabilities
-  that the port reports during autonegotiation.
-  The meaning of the different modes is:
--- Sym = Symetric: both link partners are allowed to send PAUSE frames
--- SymOrRem = SymetricOrRemote: both or only remote partner are allowed
-   to send PAUSE frames
--- LocSend = LocalSend: only local link partner is allowed to send
-   PAUSE frames
--- None: no link partner is allowed to send PAUSE frames
+Duplex Capabilities
+-------------------
+Parameter:    DupCap_?
+Values:       Half, Full, Both
+Default:      Both
+
+This parameters is only relevant if auto-negotiation for this port is 
+not set to "Sense". If auto-negotiation is set to "On", all three values
+are possible. If it is set to "Off", only "Full" and "Half" are allowed.
+This parameter is usefull if your link partner does not support all
+possible combinations.
+
+Flow Control
+------------
+Parameter:    FlowCtrl_?
+Values:       Sym, SymOrRem, LocSend, None
+Default:      SymOrRem
+
+This parameter can be used to set the flow control capabilities the 
+port reports during auto-negotiation. It can be set for each port 
+individually.
+Possible modes:
+   -- Sym      = Symetric: both link partners are allowed to send 
+                  PAUSE frames
+   -- SymOrRem = SymetricOrRemote: both or only remote partner 
+                  are allowed to send PAUSE frames
+   -- LocSend  = LocalSend: only local link partner is allowed 
+                  to send PAUSE frames
+   -- None     = no link partner is allowed to send PAUSE frames
   
-  NOTE: This parameter is ignored if autonegotiation is set to "Off".
+NOTE: This parameter is ignored if auto-negotiation is set to "Off".
 
-- Role in Master-Slave-Negotiation (1000Base-T only).
-  Parameter:    Role_?
-  Values:       Auto, Master, Slave
-  Default:      Auto
-  
-  This parameter is only valid for the SK-9821 and SK-9822 adapters.
-  For two 1000Base-T ports to communicate, one must take the role as
-  master (providing timing information), while the other must be slave.
-  Normally, this is negotiated between the two ports during link 
-  establishment. If this should ever fail, you can force a port to a
-  specific setting with this parameter.
-  
+Role in Master-Slave-Negotiation (1000Base-T only)
+--------------------------------------------------
+Parameter:    Role_?
+Values:       Auto, Master, Slave
+Default:      Auto
+
+This parameter is only valid for the SK-9821 and SK-9822 adapters.
+For two 1000Base-T ports to communicate, one must take the role of the
+master (providing timing information), while the other must be the 
+slave. Usually, this is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
 
-5.2 Per-Adapter Parameters
---------------------------
 
-- Preferred Port
-  Parameter:	PrefPort
-  Values:	A, B
-  Default:	A
-
-  This is used to force the preferred port to A or B (on two-port NICs).
-  The preferred port is the one that is used if both are detected as
-  fully functional.
-
-- RLMT (Redundant Link Management Technology) Mode
-  Parameter:	RlmtMode
-  Values:	CheckLinkState,CheckLocalPort, CheckSeg, DualNet
-  Default:	CheckLinkState
-
-  RLMT (the driver part that decides which port to use) knows three
-  ways of checking if a port is available for use:
-
--- CheckLinkState = Check link state only: RLMT uses the link state
-   reported by the adapter hardware for each individual port to determine
-   whether a port can be used for all network traffic or not.
-
--- CheckLocalPort - Check other port on adapter: RLMT sends test frames
-   from each port to each other port and checks if they are received by
-   the other port, respectively. Thus, the ports must be connected to the
-   network such that LLC test frames can be exchanged between them
-   (i.e. there must be no routers between the ports).
-
--- CheckSeg - Check other port and segmentation: RLMT checks the other port
-   and in addition requests information from the Gigabit Ethernet
-   switch next to each port to see if the network is segmented between
-   the ports. Thus, this mode is only to be used if you have Gigabit
-   Ethernet switches installed in your network that have been configured
-   to use the Spanning Tree protocol.
-
--- DualNet - Both ports A and B are used as separate devices at the same
-   time. So if you have a dual port adapter, port A will show up as eth0
-   and port B as eth1. Both ports can be used independend with distinct
-   IP addresses.
-   The preferred port setting is not used. Rlmt is turned off.
-   
+4.2  Adapter Parameters
+-----------------------
 
-  NOTE: The modes CheckLocalPort and CheckSeg are meant to operate in
-        configurations where a network path between the ports on one
-        adapter exists. Especially, they are not designed to work where
-        adapters are connected back-to-back.
+Preferred Port
+--------------
+Parameter:    PrefPort
+Values:       A, B
+Default:      A
+
+This is used to force the preferred port to A or B (on dual-port network 
+adapters). The preferred port is the one that is used if both are detected
+as fully functional.
+
+RLMT Mode (Redundant Link Management Technology)
+------------------------------------------------
+Parameter:    RlmtMode
+Values:       CheckLinkState,CheckLocalPort, CheckSeg, DualNet
+Default:      CheckLinkState
+
+RLMT monitors the status of the port. If the link of the active port 
+fails, RLMT switches immediately to the standby link. The virtual link is 
+maintained as long as at least one 'physical' link is up. 
+
+Possible modes:
+
+   -- CheckLinkState - Check link state only: RLMT uses the link state
+      reported by the adapter hardware for each individual port to 
+      determine whether a port can be used for all network traffic or 
+      not.
+
+   -- CheckLocalPort - In this mode, RLMT monitors the network path 
+      between the two ports of an adapter by regularly exchanging packets
+      between them. This mode requires a network configuration in which 
+      the two ports are able to "see" each other (i.e. there must not be 
+      any router between the ports).
+
+   -- CheckSeg - Check local port and segmentation: This mode supports the
+      same functions as the CheckLocalPort mode and additionally checks 
+      network segmentation between the ports. Therefore, this mode is only
+      to be used if Gigabit Ethernet switches are installed on the network
+      that have been configured to use the Spanning Tree protocol. 
+
+   -- DualNet - In this mode, ports A and B are used as separate devices. 
+      If you have a dual port adapter, port A will be configured as eth0 
+      and port B as eth1. Both ports can be used independently with 
+      distinct IP addresses. The preferred port setting is not used. 
+      RLMT is turned off.
+   
+NOTE: RLMT modes CLP and CLPSS are designed to operate in configurations 
+      where a network path between the ports on one adapter exists. 
+      Moreover, they are not designed to work where adapters are connected
+      back-to-back.
 ***
 
 
-(6) LARGE FRAME SUPPORT
-=======================
+5  Large Frame Support
+======================
 
-Large frames (also called jumbo frames) are now supported by the
-driver. This can result in a greatly improved throughput if
-transfering large amounts of data.
-To enable large frames, set the MTU (maximum transfer unit)
-of the interface to the value you wish (up to 9000). The command
-for this is:
-  ifconfig eth0 mtu 9000
+The driver supports large frames (also called jumbo frames). Using large 
+frames can result in an improved throughput if transferring large amounts 
+of data.
+To enable large frames, set the MTU (maximum transfer unit) of the 
+interface to the desired value (up to 9000), execute the following 
+command:
+      ifconfig eth0 mtu 9000
 This will only work if you have two adapters connected back-to-back
-or if you use a switch that supports large frames. When using a
-switch, it should be configured to allow large frames, without
-autonegotiating for them.
-The setting must be done on all adapters that can be reached by
-the large frames. If one adapter is not set to receive large frames,
-it will simply drop them.
+or if you use a switch that supports large frames. When using a switch, 
+it should be configured to allow large frames and auto-negotiation should  
+be set to OFF. The setting must be configured on all adapters that can be 
+reached by the large frames. If one adapter is not set to receive large 
+frames, it will simply drop them.
+
+You can switch back to the standard ethernet frame size by executing the 
+following command:
+      ifconfig eth0 mtu 1500
 
-You can switch back to the standard ethernet frame size with:
-  ifconfig eth0 mtu 1500
-
-To make this setting persitent, add a script with the 'ifconfig'
-line to the system startup sequence (named something like "S99sk98lin"
+To permanently configure this setting, add a script with the 'ifconfig' 
+line to the system startup sequence (named something like "S99sk98lin" 
 in /etc/rc.d/rc2.d).
 ***
 
 
-(7) TROUBLESHOOTING
-===================
+6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+==================================================================
+
+The SysKonnect Linux drivers are able to support VLAN and Link Aggregation
+according to IEEE standards 802.1, 802.1q, and 802.3ad. These features are
+only available after installation of open source modules available on the 
+Internet:
+For VLAN go to: http://scry.wanfear.com/~greear/vlan.html
+For Link Aggregation go to: http://www.st.rim.or.jp/~yumo
+
+NOTE: SysKonnect GmbH does not offer any support for these open source 
+      modules and does not take the responsibility for any kind of 
+      failures or problems arising in connection with these modules.
+
+NOTE: Configuring Link Aggregation on a SysKonnect dual link adapter may 
+      cause problems when unloading the driver.
+
+
+7  Troubleshooting
+==================
+
+If any problems occur during the installation process, check the 
+following list:
 
-If you run into problems during installation, check those items:
 
 Problem:  The SK-98xx adapter can not be found by the driver.
-Reason:   Look in /proc/pci for the following entry:
+Solution: In /proc/pci search for the following entry:
              'Ethernet controller: SysKonnect SK-98xx ...'
-	  If this entry exists, then the SK-98xx adapter has been
-	  found by the system and should be able to be used.
-	  If this entry does not exist or if the file '/proc/pci'
-	  is not there, then you may have a hardware problem or PCI
-	  support may not be enabled in your kernel.
-	  The adapter can be checked using the diagnostic program
-	  which is available from the SysKonnect web site:
-	      www.syskonnect.de
-	  Some COMPAQ machines have a problem with PCI under
-	  Linux. This is described in the 'PCI howto' document
-	  (included in some distributions or available from the
-	  www, e.g. at 'www.linux.org'). This might be fixed in the
-	  2.2.x kernel series (I've not tested it).
-
-Problem:  Programs such as 'ifconfig' or 'route' can not be found or
-          you get an error message 'Operation not permitted'.
-Reason:   You are not logged in as user 'root'. Logout and 
-          login as root or change to root via 'su'.
-
-Problem:  Using the command 'ping <address>', you get a message
-          "ping: sendto: Network is unreachable".
-Reason:   Your route is not set up correct.
-	  If you are using RedHat, you probably forgot
-	  to set up the route in 'network configuration'.
-	  Check the existing routes with the 'route' command
-	  and check if there is an entry for 'eth0' and if
-	  it is correct.
-
-Problem:  The driver can be started, the adapter is connected
-          to the network, but you can not receive or transmit
-          any packet; e.g. 'ping' does not work.
-Reason:   You have an incorrect route in your routing table.
-          Check the routing table with the command 'route' and
-	  read the manual pages about route ('man route').
-NOTE:	  Although the 2.2.x kernel versions generate the routing
-	  entry automatically, you may have problems of this kind
-	  here, too. We found a case where the driver started correct
-	  at system boot, but after removing and reloading the driver,
-	  the route of the adapter's network pointed to the 'dummy0'
-	  device and had to be corrected manually.
-	  
-Problem:  You want to use your computer as a router between
-          multiple IP subnetworks (using multiple adapters), but
-	  you can not reach computers in other subnetworks.
-Reason:   Either the router's kernel is not configured for IP
-	  forwarding or there is a problem with the routing table
-	  and gateway configuration in at least one of the
-	  computers.
-
-Problem:  At the start of the driver, you get an error message:
-	  "eth0: -- ERROR --
-	   Class: internal Software error
-	   Nr: 0xcc
-	   Msg: SkGeInitPort() cannot init running ports"
-Reason:	  You are using a driver compiled for single processor
-	  machines on an multiprocessor machine with SMP (Symetric
-	  MultiProcessor) kernel.
-	  Configure your kernel appropriate and recompile the kernel or
-	  the modules.
+          If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has 
+          been found by the system and should be operational.
+          If this entry does not exist or if the file '/proc/pci' is not 
+          found, there may be a hardware problem or the PCI support may 
+          not be enabled in your kernel.
+          The adapter can be checked using the diagnostics program which 
+          is available on the SysKonnect web site:
+          www.syskonnect.com
+          
+          Some COMPAQ machines have problems dealing with PCI under Linux.
+          Linux. This problem is described in the 'PCI howto' document
+          (included in some distributions or available from the
+          web, e.g. at 'www.linux.org'). 
+
+
+Problem:  Programs such as 'ifconfig' or 'route' can not be found or the 
+          error message 'Operation not permitted' is displayed.
+Reason:   You are not logged in as user 'root'.
+Solution: Logout and login as 'root' or change to 'root' via 'su'.
+
+
+Problem:  Upon use of the command 'ping <address>' the message
+          "ping: sendto: Network is unreachable" is displayed.
+Reason:   Your route is not set correctly.
+Solution: If you are using RedHat, you probably forgot to set up the 
+          route in the 'network configuration'.
+          Check the existing routes with the 'route' command and check 
+          if an entry for 'eth0' exists, and if so, if it is set correctly.
+
+
+Problem:  The driver can be started, the adapter is connected to the 
+          network, but you cannot receive or transmit any packets; 
+          e.g. 'ping' does not work.
+Reason:   There is an incorrect route in your routing table.
+Solution: Check the routing table with the command 'route' and read the 
+          manual help pages dealing with routes (enter 'man route').
+
+NOTE: Although the 2.2.x kernel versions generate the routing entry 
+      automatically, problems of this kind may occur here as well. We've 
+      come across a situation in which the driver started correctly at 
+      system start, but after the driver has been removed and reloaded,
+      the route of the adapter's network pointed to the 'dummy0'device 
+      and had to be corrected manually.
+
+
+Problem:  Your computer should act as a router between multiple 
+          IP subnetworks (using multiple adapters), but computers in 
+          other subnetworks cannot be reached.
+Reason:   Either the router's kernel is not configured for IP forwarding 
+          or the routing table and gateway configuration of at least one 
+          computer is not working.
+
+Problem:  Upon driver start, the following error message is displayed:
+          "eth0: -- ERROR --
+          Class: internal Software error
+          Nr:    0xcc
+          Msg:   SkGeInitPort() cannot init running ports"
+Reason:   You are using a driver compiled for single processor machines 
+          on a multiprocessor machine with SMP (Symetric MultiProcessor) 
+          kernel.
+Solution: Configure your kernel appropriately and recompile the kernel or
+          the modules.
+
+
 
 If your problem is not listed here, please contact SysKonnect's technical
 support for help (linux@syskonnect.de).
-When contacting our technical support, please ensure that the
-following information is available:
+When contacting our technical support, please ensure that the following 
+information is available:
 - System Manufacturer and Model
 - Boards in your system
 - Distribution
 - Kernel version
+- Driver version
 ***
 
+8  History
+==========
 
-(8) HISTORY
-===========
+VERSION 6.00 (In-Kernel version)
+New Features:
+- Support for SK-98xx V2.0 adapters
+- Support for gmac
+- Support for kernel 2.4.x and kernel 2.2.x
+- Zerocopy support for kernel 2.4.x with sendfile()
+- Support for scatter-gather functionality with sendfile()
+- Speed support for SK-98xx V2.0 adapters
+- New ProcFs entries
+- New module parameters
+Problems fixed:
+- ProcFS initialization
+- csum packet error
+- Ierror/crc counter error (#10767)
+- rx_too_long counter error (#10751)
+Known limitations:
+- None
+
+VERSION 4.11
+New Features:
+- none
+Problems fixed:
+- Error statistic counter fix (#10620)
+- RLMT-Fixes (#10659, #10639, #10650)
+- LM80 sensor initialization fix (#10623)
+- SK-CSUM memory fixes (#10610).
+Known limitations:
+- None
+
+VERSION 4.10
+New Features:
+- New ProcFs entries
+Problems fixed:
+- Corrected some printk's
+Known limitations:
+- None
+
+VERSION 4.09
+New Features:
+- IFF_RUNNING support (link status)
+- New ProcFs entries
+Problems fixed:
+- too long counters
+- too short counters
+- Kernel error compilation
+Known limitations:
+- None
+ 
+VERSION 4.06 (In-Kernel version)
+Problems fixed:
+- MTU init problems
+ 
+VERSION 4.04
+Problems fixed:
+- removed VLAN error messages
 
 VERSION 4.02 (In-Kernel version)
 New Features:
@@ -518,3 +663,4 @@
 ***End of Readme File***
 
 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/sonypi.txt linux-2.4.21-rc3/Documentation/sonypi.txt
--- linux-2.4.20/Documentation/sonypi.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/sonypi.txt	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,7 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
 	Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
 	Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
@@ -15,14 +16,14 @@
 	- capture button events (only on Vaio Picturebook series)
 	- Fn keys
 	- bluetooth button (only on C1VR model)
-	- back button (PCG-GR7/K model)
-	- lid open/close events (Z600NE model)
+	- programmable keys, back, help, zoom, thumbphrase buttons, etc.
+	  (when available)
 
 Those events (see linux/sonypi.h) can be polled using the character device node
 /dev/sonypi (major 10, minor auto allocated or specified as a option).
 
 A simple daemon which translates the jogdial movements into mouse wheel events
-can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/>
+can be downloaded at: <http://popies.net/sonypi/>
 
 This driver supports also some ioctl commands for setting the LCD screen
 brightness and querying the batteries charge information (some more 
@@ -43,7 +44,7 @@
 to /etc/modules.conf file, when the driver is compiled as a module or by
 adding the following to the kernel command line (in your bootloader):
 
-	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,nojogdial]]]]]
+	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask[,useinput]]]]]]
 
 where:
 
@@ -64,15 +65,42 @@
 			with it and it shouldn't be required anyway if 
 			ACPI is already enabled).
 
-	verbose:	print unknown events from the sonypi device
+	verbose:	set to 1 to print unknown events received from the 
+			sonypi device.
+			set to 2 to print all events received from the 
+			sonypi device.
 
 	compat:		uses some compatibility code for enabling the sonypi
 			events. If the driver worked for you in the past
 			(prior to version 1.5) and does not work anymore,
 			add this option and report to the author.
 
-	nojogdial:	gives more accurate PKEY events on those Vaio models
-			which don't have a jogdial (like the FX series).
+	mask:		event mask telling the driver what events will be
+			reported to the user. This parameter is required for some 
+			Vaio models where the hardware reuses values used in 
+			other Vaio models (like the FX series who does not
+			have a jogdial but reuses the jogdial events for
+			programmable keys events). The default event mask is
+			set to 0xffffffff, meaning that all possible events will be
+			tried. You can use the following bits to construct
+			your own event mask (from drivers/char/sonypi.h):
+				SONYPI_JOGGER_MASK 		0x0001
+				SONYPI_CAPTURE_MASK 		0x0002
+				SONYPI_FNKEY_MASK 		0x0004
+				SONYPI_BLUETOOTH_MASK 		0x0008
+				SONYPI_PKEY_MASK 		0x0010
+				SONYPI_BACK_MASK 		0x0020
+				SONYPI_HELP_MASK 		0x0040
+				SONYPI_LID_MASK 		0x0080
+				SONYPI_ZOOM_MASK 		0x0100
+				SONYPI_THUMBPHRASE_MASK 	0x0200
+				SONYPI_MEYE_MASK		0x0400
+				SONYPI_MEMORYSTICK_MASK		0x0800
+
+	useinput:	if set (which is the default) jogdial events are
+			forwarded to the input subsystem as mouse wheel
+			events.
+			
 
 Module use:
 -----------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/sysrq.txt linux-2.4.21-rc3/Documentation/sysrq.txt
--- linux-2.4.20/Documentation/sysrq.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/sysrq.txt	2003-05-22 22:06:46.000000000 +0000
@@ -36,6 +36,10 @@
 On other - If you know of the key combos for other architectures, please
            let me know so I can add them to this section.
 
+On all -  write a character to /proc/sysrq-trigger.  eg:
+
+		echo t > /proc/sysrq-trigger
+
 *  What are the 'command' keys?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 'r'     - Turns off keyboard raw mode and sets it to XLATE.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/tipar.txt linux-2.4.21-rc3/Documentation/tipar.txt
--- linux-2.4.20/Documentation/tipar.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/tipar.txt	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,93 @@
+
+		Parallel link cable for Texas Instruments handhelds
+		===================================================
+
+
+Author: Romain Lievin
+Homepage: http://lpg.ticalc.org/prj_tidev
+
+
+INTRODUCTION:
+
+This is a driver for the very common home-made parallel link cable, a cable 
+designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
+or workstation (Alpha, Sparc). Given that driver is built on parport, the 
+parallel port abstraction layer, this driver is independant of the platform.
+
+It can also be used with another device plugged on the same port (such as a
+ZIP drive). I have a 100MB ZIP and both of them work fine !
+
+If you need more information, please visit the 'TI drivers' homepage at the URL
+above.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tipar (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled parport support (CONFIG_PARPORT_DEV): either 
+compiled in your kernel, either as a module. 
+This driver supports the new device hierarchy (devfs).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       modprobe parport
+       insmod tipar.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tipar0 c 115 0
+       mknod /dev/tipar1 c 115 1
+       mknod /dev/tipar2 c 115 2
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tipar?
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tipar NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+	time has expired then the driver will return with a timeout error.
+
+  NAME: delay
+  TYPE: integer
+  DEFAULT: 10
+  DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data 
+	rate but makes transmission less reliable.
+
+These parameters can be changed at run time by any program via ioctl(2) calls 
+as listed in ./include/linux/ticable.h
+Rather than write 50 pages describing the ioctl() and so on, it is
+perhaps more useful you look at ticables library (dev_link.c) that demonstrates
+how to use them, and demonstrates the features of the driver. This is
+probably a lot more useful to people interested in writing applications
+that will be using this driver.
+
+QUIRKS/BUGS:
+
+None.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIPAR: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org. He packaged these drivers for Debian.
+
+CREDITS:
+
+The code is based on tidev.c & parport.c.
+The driver has been developed independantly of Texas Instruments.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/auerswald.txt linux-2.4.21-rc3/Documentation/usb/auerswald.txt
--- linux-2.4.20/Documentation/usb/auerswald.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/auerswald.txt	2003-05-22 22:06:46.000000000 +0000
@@ -23,8 +23,15 @@
 	...
 	mknod -m 666 /dev/usb/auer15 c 180 127
 
-Future plans
+ISDN support
 ============
-- Connection to ISDN4LINUX (the hisax interface)
+If you enable CONFIG_USB_AUERISDN, you will get full
+ISDN modem support via the HISAX ISDN4LINUX driver.
+
+Of course, as for every USB-based ISDN adaptor, you
+will have to modify your hotplug scripts to load
+the isdn subsystem and configure the network interfaces.
+Same procedure as for the ST5481 driver.
+
 
 The maintainer of this driver is wolfgang@iksw-muees.de
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/ehci.txt linux-2.4.21-rc3/Documentation/usb/ehci.txt
--- linux-2.4.20/Documentation/usb/ehci.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/ehci.txt	2003-05-22 22:06:47.000000000 +0000
@@ -1,4 +1,4 @@
-26-Apr-2002
+27-Dec-2002
 
 The EHCI driver is used to talk to high speed USB 2.0 devices using
 USB 2.0-capable host controller hardware.  The USB 2.0 standard is
@@ -21,11 +21,15 @@
 
 At this writing, this driver has been seen to work with implementations
 of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
+Other EHCI implementations are becoming available from other vendors;
+you should expect this driver to work with them too.
 
-At this writing, high speed devices are finally beginning to appear.
-While usb-storage devices have been available for some time (working
+While usb-storage devices have been available since mid-2001 (working
 quite speedily on the 2.4 version of this driver), hubs have only
-very recently become available.
+been available since late 2001, and other kinds of high speed devices
+appear to be on hold until more systems come with USB 2.0 built-in.
+Such new systems have been available since early 2002, and became much
+more typical in the second half of 2002.
 
 Note that USB 2.0 support involves more than just EHCI.  It requires
 other changes to the Linux-USB core APIs, including the hub driver,
@@ -43,26 +47,29 @@
 It's believed to do all the right PCI magic so that I/O works even on
 systems with interesting DMA mapping issues.
 
-At this writing the driver should comfortably handle all control and bulk
-transfers, including requests to USB 1.1 devices through transaction
-translators (TTs) in USB 2.0 hubs.  However, there some situations where
-the hub driver needs to clear TT error state, which it doesn't yet do.
-
-Interrupt transfer support is newly functional and not yet as robust as
-control and bulk traffic.  As yet there is no support for split transaction
-scheduling for interrupt transfers, which means among other things that
-connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work.
-Connect them to USB 1.1 hubs, or to a root hub.
-
-Isochronous (ISO) transfer support is also newly functional.  No production
-high speed devices are available which would need it (though high quality
-webcams are in the works!).  Note that split transaction support for ISO
+Transfer Types
+
+At this writing the driver should comfortably handle all control, bulk,
+and interrupt transfers, including requests to USB 1.1 devices through
+transaction translators (TTs) in USB 2.0 hubs.  But you may find bugs.
+
+High Speed Isochronous (ISO) transfer support is also functional, but
+at this writing no Linux drivers have been using that support.
+
+Full Speed Isochronous transfer support, through transaction translators,
+is not yet available.  Note that split transaction support for ISO
 transfers can't share much code with the code for high speed ISO transfers,
 since EHCI represents these with a different data structure.  So for now,
-most USB audio and video devices have the same restrictions as hubs, mice,
-and keyboards:  don't connect them using high speed USB hubs.
+most USB audio and video devices can't be connected to high speed buses.
+
+Driver Behavior
 
-The EHCI root hub code should hand off USB 1.1 devices to its companion
+Transfers of all types can be queued.  This means that control transfers
+from a driver on one interface (or through usbfs) won't interfere with
+ones from another driver, and that interrupt transfers can use periods
+of one frame without risking data loss due to interrupt processing costs.
+
+The EHCI root hub code hands off USB 1.1 devices to its companion
 controller.  This driver doesn't need to know anything about those
 drivers; a OHCI or UHCI driver that works already doesn't need to change
 just because the EHCI driver is also present.
@@ -70,6 +77,11 @@
 There are some issues with power management; suspend/resume doesn't
 behave quite right at the moment.
 
+Also, some shortcuts have been taken with the scheduling periodic
+transactions (interrupt and isochronous transfers).  These place some
+limits on the number of periodic transactions that can be scheduled,
+and prevent use of polling intervals of less than one frame.
+
 
 USE BY
 
@@ -83,10 +95,10 @@
     # rmmod ehci-hcd
 
 You should also have a driver for a "companion controller", such as
-"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci".  In case of any trouble
-with the EHCI driver, remove its module and then the driver for that
-companion controller will take over (at lower speed) all the devices
-that were previously handled by the EHCI driver.
+"ohci-hcd"  or "uhci-hcd".  In case of any trouble with the EHCI driver,
+remove its module and then the driver for that companion controller will
+take over (at lower speed) all the devices that were previously handled
+by the EHCI driver.
 
 Module parameters (pass to "modprobe") include:
 
@@ -96,9 +108,20 @@
 	is 6, indicating 2^6 = 64 microframes.  This controls how often
 	the EHCI controller can issue interrupts.
 
-The EHCI interrupt handler just acknowledges interrupts and schedules
-a tasklet to handle whatever needs handling.  That keeps latencies low,
-no matter how often interrupts are issued.
+If you're using this driver on a 2.5 kernel, and you've enabled USB
+debugging support, you'll see three files in the "sysfs" directory for
+any EHCI controller:
+
+	"async" dumps the asynchronous schedule, used for control
+		and bulk transfers.  Shows each active qh and the qtds
+		pending, usually one qtd per urb.  (Look at it with
+		usb-storage doing disk I/O; watch the request queues!)
+	"periodic" dumps the periodic schedule, used for interrupt
+		and isochronous transfers.  Doesn't show qtds.
+	"registers" show controller register state, and
+
+The contents of those files can help identify driver problems.
+
 
 Device drivers shouldn't care whether they're running over EHCI or not,
 but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
@@ -107,6 +130,11 @@
 Also, some values in device descriptors (such as polling intervals for
 periodic transfers) use different encodings when operating at high speed.
 
+However, do make a point of testing device drivers through USB 2.0 hubs.
+Those hubs report some failures, such as disconnections, differently when
+transaction translators are in use; some drivers have been seen to behave
+badly when they see different faults than OHCI or UHCI report.
+
 
 PERFORMANCE
 
@@ -122,13 +150,18 @@
 and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
 microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
 
+So more than 50 MByte/sec is available for bulk transfers, when both
+hardware and device driver software allow it.  Periodic transfer modes
+(isochronous and interrupt) allow the larger packet sizes which let you
+approach the quoted 480 MBit/sec transfer rate.
+
 Hardware Performance
 
 At this writing, individual USB 2.0 devices tend to max out at around
 20 MByte/sec transfer rates.  This is of course subject to change;
 and some devices now go faster, while others go slower.
 
-The NEC implementation of EHCI seems to have a hardware bottleneck
+The first NEC implementation of EHCI seems to have a hardware bottleneck
 at around 28 MByte/sec aggregate transfer rate.  While this is clearly
 enough for a single device at 20 MByte/sec, putting three such devices
 onto one bus does not get you 60 MByte/sec.  The issue appears to be
@@ -136,9 +169,11 @@
 so that it's only trying six (or maybe seven) USB transactions each
 microframe rather than thirteen.  (Seems like a reasonable trade off
 for a product that beat all the others to market by over a year!)
+
 It's expected that newer implementations will better this, throwing
 more silicon real estate at the problem so that new motherboard chip
-sets will get closer to that 60 MByte/sec target.
+sets will get closer to that 60 MByte/sec target.  That includes an
+updated implementation from NEC, as well as other vendors' silicon.
 
 There's a minimum latency of one microframe (125 usec) for the host
 to receive interrupts from the EHCI controller indicating completion
@@ -161,10 +196,16 @@
 sequence of 128 KB chunks would waste a lot less.
 
 But rather than depending on such large I/O buffers to make synchronous
-I/O be efficient, it's better to just queue all several (bulk) requests
+I/O be efficient, it's better to just queue up several (bulk) requests
 to the HC, and wait for them all to complete (or be canceled on error).
 Such URB queuing should work with all the USB 1.1 HC drivers too.
 
+In the Linux 2.5 kernels, new usb_sg_*() api calls have been defined; they
+queue all the buffers from a scatterlist.  They also use scatterlist DMA
+mapping (which might apply an IOMMU) and IRQ reduction, all of which will
+help make high speed transfers run as fast as they can.
+
+
 TBD:  Interrupt and ISO transfer performance issues.  Those periodic
 transfers are fully scheduled, so the main issue is likely to be how
 to trigger "high bandwidth" modes.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/ov511.txt linux-2.4.21-rc3/Documentation/usb/ov511.txt
--- linux-2.4.20/Documentation/usb/ov511.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/ov511.txt	2003-05-22 22:06:26.000000000 +0000
@@ -276,6 +276,15 @@
 	might be necessary if your camera has a custom lens assembly. This has
 	no effect with video capture devices.
 
+  NAME: ov518_color
+  TYPE: integer (Boolean)
+  DEFAULT: 0 (off)
+  DESC: Enable OV518 color support. This is off by default since it doesn't
+	work most of the time. If you want to try it, you must also load
+	ov518_decomp with the "nouv=0" parameter. If you get improper colors or
+	diagonal lines through the image, restart your video app and try again.
+	Repeat as necessary.
+
 WORKING FEATURES:
  o Color streaming/capture at most widths and heights that are multiples of 8.
  o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color
@@ -285,6 +294,7 @@
  o /proc status reporting
  o SAA7111A video capture support at 320x240 and 640x480
  o Compression support
+ o SMP compatibility
 
 HOW TO CONTACT ME:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/scanner-hp-sane.txt linux-2.4.21-rc3/Documentation/usb/scanner-hp-sane.txt
--- linux-2.4.20/Documentation/usb/scanner-hp-sane.txt	2000-05-02 20:49:18.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/scanner-hp-sane.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-Copyright (C) 1999, 2000 David E. Nelson
-
-April 26, 2000
-
-CHANGES
-
-- Amended for Linux-2.3.99-pre6-3
-- Updated for multiple scanner support
-
-INTRODUCTION
-
-This document will hopefully provide enough info on how to get SANE
-working with a Hewlett Packard USB capable scanner using the USB
-interface.  The majority of HP Scanners support the Scanner Control
-Language (SCL) which is both published by HP and supported by SANE.
-The only HP Scanners that I'm aware of that do not support SCL are the
-4200C ,3300C, and the PhotoSmart S20.  All other HP scanners with USB
-interfaces should work (4100C, 5200C, 6200C, and 6300C) as do models
-that are derived from the models above. ie the 6350C which is a 6300C
-with a transparency adaptor included with the scanner at time of
-purchase.  Of course as HP releases new scanners this information may
-change.
-
-
-REQUIREMENTS
-
-In order to get this running you'll need USB support in your kernel in
-addition to USB Scanner support.  Please refer to scanner.txt for
-issues pertaining to Linux USB and USB Scanner support.
-
-An installed version of SANE which is available from
-http://www.mostang.com/sane/.  Testing has been performed using
-version SANE-1.0.1.  For instructions on building and installing SANE,
-refer to the various README files within the SANE distribution.
-
-The latest SANE HP backend is available from http://www.kirchgessner.net.
-At the time of this writing, version 0.83 was available.
-
-
-OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
-
-NOTE: $INSTALL_DIR is the location where SANE is installed.  It may be
-/usr/local, /usr, /opt or somewhere else.  If you don't know, ask your
-system administrator.
-
-1) Make sure that you have the libsane-hp.* libraries under the
-$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
-was either not compiled or installed properly.
-
-2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
-files: dll.conf, hp.conf.
-
-  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
-
-  hp.conf: This should contain two lines:
-
-    /dev/usbscanner
-    option connect-device
-
-NOTE: If you are using multiple scanners, make sure to have the correct
-device, ie /dev/usbscanner0.  See scanner.txt for more info.
-
-3) You should now be able to use SANE (xscanimage or scanimage).
-
-Don't forget to read any relevant man pages regarding the usage of
-SANE.  If you have other entries uncommented in 'dll.conf', you may
-have to specify the device to (x)scanimage.  Again, `man` is your
-friend.  The xscanimage (1) man page has info on how to get 'The Gimp'
-to work with xscanimage.  Note that Gimp support must be compiled into
-SANE for it to work.  If you are dealing with a RedHat system, this
-means that you'll also need to install the gimp-devel rpm package
-prior to compiling SANE.
-
-NOTE: The issues regarding core dumping by (x)scanimage have (or seem
-to be thus far) been resolved with version 0.2+ of the USB scanner
-driver which should be available in linux-2.3.23.  If you notice
-otherwise, please contact me.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/scanner.txt linux-2.4.21-rc3/Documentation/usb/scanner.txt
--- linux-2.4.20/Documentation/usb/scanner.txt	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/scanner.txt	2003-05-22 22:06:53.000000000 +0000
@@ -1,154 +1,114 @@
 Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>
+Updated 2003 by Henning Meier-Geinitz <henning@meier-geinitz.de>
 
-April 26, 2000
-
-CHANGES
-
-- Amended for linux-2.4.12
-- Updated devfs support
-- Amended for linux-2.3.99-pre6-3
-- Appended hp_scan.c to end of this README
-- Removed most references to HP
-- Updated uhci/ohci host controller info
-- Updated support for multiple scanner support
-- Updated supported scanners list
-- Updated usbdevfs info
-- Spellcheck
 
 OVERVIEW
 
-This README addresses issues regarding how to configure the kernel
-to access a USB scanner.  Although the driver was originally conceived
-for USB HP scanners, it's general enough so that it can be used with
-other scanners.  Also, one can now pass the USB Vendor and Product
-ID's using module parameters for unknown scanners.  Refer to the
-document scanner-hp-sane.txt for guidance on how to configure SANE to
-use a USB HP Scanner.
+This README addresses issues regarding how to configure the kernel to access a
+USB scanner.  Although the driver was originally conceived for USB HP
+scanners, it's general enough so that it can be used with most other USB
+scanners.  Also, one can pass the USB Vendor and Product IDs using module
+parameters for unknown scanners.
+
+There are two drivers for SCSI-over-USB scanners: 
+* The "hpusbscsi" module for Hewlett-Packard 53xx series, Hewlett-Packard 7400,
+  Minolta Scan Dual II, Minolta Elite II
+* The "microtek" module for the Microtek Scanmaker X6
+
+In addition to the kernel driver, user-space tools like SANE are necessary to
+actually use the scanner.  SANE ("Scanner Access Now Easy") provides drivers
+for a variety of USB scanners.  See the appropriate SANE man page for details,
+e.g. man sane-usb and man sane-hp (for HP scanners).
+
+NOTE: Just because a product is detected by this driver does not mean that
+applications exist that support the product.  It's in the hopes that this will
+allow developers a means to produce applications that will support the listed
+USB products.
 
 
 ADDITIONAL INFORMATION
 
-http://www.linux-usb.org/
+http://www.linux-usb.org/           (General information, mailing lists, links)
+http://www.mostang.com/sane/        (SANE user-space tools)
+http://www.meier-geinitz.de/kernel/ (USB scanner driver information and patches)
 
 
 REQUIREMENTS
 
-A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work.  At the time of this
-writing, there are two UHCI drivers and one OHCI.
-
-A Linux kernel with USB support enabled or a backported version to
-linux-2.2.x.  See http://www.linux-usb.org for more information on
-accomplishing this.
-
-'lspci' which is only needed to determine the type of USB hardware
-available/installed in your machine.
-
-CONFIGURATION
-
-Using `lspci -v`, determine the type of USB hardware available/installed.
+A host with a USB port.  Ideally, either a UHCI (Intel), OHCI (Compaq and
+others) or EHCI hardware should work.  
 
-  If you see something like:
+Using "make menuconfig" or your preferred method for configuring the kernel,
+select "Support for USB", "OHCI/UHCI/EHCI" depending on your hardware, "USB
+Scanner support", and "Preliminary USB device filesystem".  Compile and
+install the modules (you may need to execute "depmod -a" to update the module
+dependencies).  If any of the USB sections were compiled into the kernel, a
+reboot is necessary.  NOTE: Updating the boot disk with "lilo" may also be
+required.  Testing was performed only as modules, YMMV.
+
+Up to 16 scanners can be connected/used simultaneously.  If devfs support is
+enabled, see next section.  Otherwise, the device files must be created
+manually if they don't exist yet, either by MAKEDEV or mknod.
+
+MAKEDEV method:
+  cd /dev
+  MAKEDEV usb
+  Check that the device files "/dev/usb/scanner0" - "/dev/usb/scanner15" have
+  been created.
+
+mknod method:
+  mknod /dev/usb/scanner0 c 180 48
+  mknod /dev/usb/scanner1 c 180 49
+                  . 
+                  .
+  mknod /dev/usb/scanner15 c 180 63
 
-    USB Controller: ......
-    Flags: .....
-    I/O ports at ....
-
-  Then you have a UHCI based controller.
-
-  If you see something like:
-
-     USB Controller: .....
-     Flags: ....
-     Memory at .....
-
-  Then you have a OHCI based controller.
-
-Using `make menuconfig` or your preferred method for configuring the
-kernel, select 'Support for USB', 'OHCI/UHCI' depending on your
-hardware (determined from the steps above), 'USB Scanner support', and
-'Preliminary USB device filesystem'.  Compile and install the modules
-(you may need to execute `depmod -a` to update the module
-dependencies). If any of the USB sections were compiled into the
-kernel, a reboot is necessary. NOTE: Updating the boot disk with
-'lilo' may also be required. Testing was performed only as modules,
-YMMV.
-
-Beginning with version 0.4 of the driver, up to 16 scanners can be
-connected/used simultaneously.  For devfs support, see next section.
-If you intend to use more than one scanner at a time w/o devfs support:
-
-   Add a device for the USB scanner:
-	`mknod /dev/usbscanner0 c 180 48`
-	`mknod /dev/usbscanner1 c 180 49`
-                      . 
-                      .
-	`mknod /dev/usbscanner15 c 180 63`
-
-
-If you foresee using only one scanner it is best to:
-	`mknod /dev/usbscanner0 c 180 48`
-	`ln -s /dev/usbscanner0 /dev/usbscanner`
-
-
-Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
+Set appropriate permissions for /dev/usb/scanner[0-15] (don't forget
 about group and world permissions).  Both read and write permissions
-are required for proper operation. For example:
-	`chmod 666 /dev/usbscanner0`
+are required for proper operation.  For example:
+  chmod 666 /dev/usb/scanner0
 
 Load the appropriate modules (if compiled as modules):
 
-  OHCI:
-    modprobe usb-ohci
-    modprobe scanner
-
-  UHCI:
-    modprobe usb-uhci
-    modprobe scanner
+  modprobe usb-ohci (or uhci, usb-uhci, ehci)
+  modprobe scanner
+
 
 DEVFS
 
 The later versions of the Linux kernel (2.4.8'ish) included a dynamic
-device filesystem call 'devfs'.  With devfs, there is no need to
+device filesystem call "devfs".  With devfs, there is no need to
 create the device files as explained above; instead, they are
 dynamically created for you.  For USB Scanner, the device is created
 in /dev/usb/scannerX where X can range from 0 to 15 depending on the
 number of scanners connected to the system.
 
-To see if you have devfs, issue the command `cat /proc/filesytems`.
-If devfs is listed you should be ready to go.  You sould also have a
-process running called 'devfsd'.  In order to make sure, issue the
-command `ps aux | grep '[d]evfsd'`.
-
-If you would like to maintain /dev/usbscanner0 in order to maintain
-compatibility with applications, then add the following to
-/etc/devfsd.conf:
-
-REGISTER ^usb/scanner0$ CFUNCTION GLOBAL symlink usb/scanner0 usbscanner0
-UNREGISTER ^usb/scanner0$ CFUNCTION GLOBAL unlink usbscanner0
+To see if you have devfs, issue the command "cat /proc/filesytems".
+If devfs is listed you should be ready to go.  You should also have a
+process running called "devfsd".  In order to make sure, issue the
+command "ps aux | grep '[d]evfsd'".
 
-Then reset the scanner (reseat the USB connector or power cycle). This
-will create the necessary symlinks in /dev to /dev/usb.
 
 CONCLUSION
 
-That's it.  SANE should now be able to access the device.  
+That's it.  SANE should now be able to access the device.  To make sure the
+device was detected, use "cat /proc/bus/usb/devices".  Your scanner should be
+listed and the line starting with "I:" should look similar to this example:
+
+  I:  If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=usbscanner
+
+The important part is "Driver=usbscanner".  If it reads "Driver=(none)", the
+USB scanner driver didn't recognize the scanner.  Have a look at the MODULE
+PARAMETERS section for what to do in this case.
+
+For more details on the format of "/proc/bus/usb/devices" see
+Documentation/usb/proc_usb_info.txt.
 
-There is a small test program (hp_scan.c -- appended below) that can
-be used to test the scanner device if it's an HP scanner that supports
-SCL (Scanner Control Language).  Known HP scanner that support SCL are
-the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
-supported since it does not understand SCL; it's also strongly
-suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
-Hp_scan.c's purpose is to test the driver without having to
-retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
-the output into a file called 'out.dat' in the current directory.  The
-data in the file is raw data so it's not very useful for imaging.
 
 MESSAGES
 
 usb_control/bulk_msg: timeout -- On occasions this message will appear
-in '/var/adm/messages', on the console, or both depending on how
+in "/var/adm/messages", on the console, or both depending on how
 your system is configured.  This is a side effect that scanners are
 sometimes very slow at warming up and/or initializing.  In most cases,
 however, only several of these messages should appear and is generally
@@ -165,122 +125,90 @@
 
 probe_scanner: Endpoint determination failed -- This means that the
 driver is unable to detect a supported configuration for means to
-communicate with the scanner.  See also 'probe_scanner: Undetected
-endpoint'.
+communicate with the scanner.  See also "probe_scanner: Undetected
+endpoint".
 
 funky result -- Most of the time the data flow between the computer
 and the scanner goes smoothly.  However, due to whatever reason,
 whether it be solar flares or stray neutrons, sometimes the
 communications don't work as expected.  The driver tries to handle
 most types of errors but not all.  When this message is seen,
-something weird happened.  Please contact the maintaner listed at the
-top of this file.
-
-SUPPORTED SCANNERS
-
-NOTE: Just because a product is listed here does not mean that
-applications exist that support the product.  It's in the hopes that
-this will allow developers a means to produce applications that will
-support the listed USB products.
-
-At the time of this writing, the following scanners were supported by
-scanner.c:
-
- Acer
-	 Prisa Acerscan 620U & 640U (!)
-	 Prisa AcerScan 620U (!)
- Agfa
-	 SnapScan 1212U
-	 Another SnapScan 1212U (?)
-	 SnapScan Touch
- Colorado -- See Primax/Colorado below
- Epson -- See Seiko/Epson below
- Genius
-         ColorPage-Vivid Pro
- Hewlett Packard
-	 3300C
-	 4100C
-	 4200C
-	 PhotoSmart S20
-	 5200C
-	 6200C
-	 6300C
- Microtek
-	 ScanMaker X6 - X6U
-	 Phantom 336CX - C3
-	 Phantom 336CX - C3 #2
-	 Phantom C6
-	 ScanMaker V6USL
-	 ScanMaker V6USL #2
-	 ScanMaker V6UL - SpicyU
- Mustek
-	 1200 CU
- Primax/Colorado
-	 G2-300 #1
-	 G2-600 #1
-	 G2E-300 #1
-	 ReadyScan 636i
-	 G2-300 #2
-	 G2-600 #2
-	 G2E-300 #2
-	 G2E-600
-	 Colorado USB 9600
-	 Colorado USB 19200
-	 Colorado 600u
-	 Colorado 1200u
- Seiko/Epson Corp.
-	 Perfection 636U and 636Photo
-	 Perfection 610
-	 Perfection 1200U and 1200Photo
- Umax
-	 Astra 1220U
-	 Astra 1236U
-	 Astra 2000U
-	 Astra 2200U
- Visioneer
-	 OneTouch 5300
-	 OneTouch 7600 duplicate ID (!)
-	 6100
+something weird happened.  Please contact the mailing list (see
+CONTACT section for details).
 
 
 MODULE PARAMETERS
 
 If you have a device that you wish to experiment with or try using
-this driver with, but the Vendor and Product ID's are not coded in,
+this driver with, but the Vendor and Product IDs are not coded in,
 don't despair.  If the driver was compiled as a module, you can pass
 options to the driver.  Simply add 
 
   options scanner vendor=0x#### product=0x****
 
 to the /etc/modules.conf file replacing the #'s and the *'s with the
-correct ID's.  The ID's can be retrieved from the messages file or
-using `cat /proc/bus/usb/devices`. Note that USB /proc support must be
-enabled during kernel configuration.  If the 'scanner' module is
-already loaded into memory, it must be reloaded for the module
-parameters to take effect.  In essence, `rmmod scanner; modprobe
-scanner` must be performed.
+correct IDs.  The IDs can be retrieved from the messages file or
+using "cat /proc/bus/usb/devices".
 
-**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced,
-usbdevfs.  To mount the filesystem, issue the command (as root):
+If the default timeout is too low, i.e. there are frequent "timeout" messages,
+you may want to increase the timeout manually by using the parameter
+"read_timeout".  The time is given in seconds.  This is an example for
+modules.conf with a timeout of 60 seconds:
+
+  options scanner read_timeout=60
+ 
+If the "scanner" module is already loaded into memory, it must be reloaded for
+the module parameters to take effect.  In essence, "rmmod scanner; modprobe
+scanner" must be performed.
 
-  mount -t usbdevfs /proc/bus/usb /proc/bus/usb
 
-An alternative and more permanent method would be to add
+BUGS
 
-  none  /proc/bus/usb  usbdevfs  defaults  0  0
+Just look at the list of fixes in the source files. 
 
-to /etc/fstab.  This will mount usbdevfs at each reboot.  You can then
-issue `cat /proc/bus/usb/devices` to extract USB device information.
 
+CONTACT
 
-BUGS
+For asking about problems and fixes, use the linux-usb-users mailing list. For
+patches, linux-usb-devel should be used. Information on both lists can be
+found on http://www.linux-usb.org/.
+
+
+CHANGES
+
+- Added information about read_timeout
+- Added more details about /proc/bus/usb/devices
+- Added/updated links
+- Added pointers two "special" scanner drivers
+- Reordering, spell-checking, formatting
+- Used /dev/usb/scanner[0-15] instead of /dev/usbscanner[0-15]
+- Removed some basic USB configuration stuff
+- Added EHCI
+- Removed some more references to HP
+- Amended for linux-2.4.12
+- Updated devfs support
+- Amended for linux-2.3.99-pre6-3
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+- Updated uhci/ohci host controller info
+- Updated support for multiple scanner support
+- Updated supported scanners list
+- Updated usbdevfs info
+- Spellcheck
 
-Just look at the list of fixes in the source files.  So, if you
-encounter any problems feel free to drop me an email.
 
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
+HP TEST PROGRAM
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL (Scanner Control Language).  Known HP scanner that support SCL are
+the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
+supported since it does not understand SCL; it's also strongly
+suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
+Hp_scan.c's purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called "out.dat" in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
 
 --------------- snip -- hp_scan.c -- snip ---------------
 /*
@@ -347,7 +275,7 @@
 		exit (1);
 	}
 	
-	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+	if((fp=open("/dev/usb/scanner0", O_RDWR)) < 0) {
 		perror("Unable to open scanner device");
 		exit (1);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/usb-serial.txt linux-2.4.21-rc3/Documentation/usb/usb-serial.txt
--- linux-2.4.20/Documentation/usb/usb-serial.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/usb/usb-serial.txt	2003-05-22 22:06:26.000000000 +0000
@@ -95,50 +95,27 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ, HP Jornada and Casio EM500 driver
+PocketPC PDA Driver
 
-  This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500
-  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
-  has been tested only on the Compaq H3135, but is rumoured to work on
-  with the H3600 and later models as well as the Jornada 548 and 568.
-  With minor modifications, it may work for other CE based handhelds too.
+  This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500
+  and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB
+  cable/cradle.
+  Most devices supported by ActiveSync are supported out of the box.
+  For others, please use module parameters to specify the product and vendor
+  id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125
 
   The driver presents a serial interface (usually on /dev/ttyUSB0) over
-  which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
+  which one may run ppp and establish a TCP/IP link to the PDA. Once this
   is done, you can transfer files, backup, download email etc. The most
-  significant advantage of using USB is speed - you can get 73 to 113
-  kbytes/sec for download/upload to the iPAQ.
+  significant advantage of using USB is speed - I can get 73 to 113
+  kbytes/sec for download/upload to my iPAQ.
 
-  The driver works intermittently with the usb-uhci driver but quite
-  reliably with the uhci driver. However, performance is much better
-  with usb-uhci. It does not seem to work with ohci at all.
-
-  You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
-  A ppp script like the one below should be kept in the file
-  /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no
-  options in /etc/ppp/options or ~/.ppprc which conflict with the ones
-  given below.
-
-	#!/bin/bash
-
-	MYIP=linux.box.ip
-	REMOTEIP=ipaq.ip
-	MYDNS=my.dns.server
-	killall -9 pppd
-	/usr/sbin/pppd /dev/ttyUSB0 \
-	connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \
-	nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \
-	proxyarp
-
-  You must also download and install asyncd from http://synce.sourceforge.net
-  This is required to emulate keep-alive packets which are exchanged by
-  ActiveSync and the iPAQ.
-
-  On connecting the cable, you should see the usual "Device Connected",
-  "User Authenticated" messages flash by on your iPAQ. Once connected,
-  you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
-  and xcerdisp, synce utilities from the Linux side. Remember to enable IP
-  forwarding. 
+  This driver is only one of a set of components required to utilize
+  the USB connection. Please visit http://synce.sourceforge.net which
+  contains the necessary packages and a simple step-by-step howto.
+
+  Once connected, you can use Win CE programs like ftpView, Pocket Outlook
+  from the PDA and xcerdisp, synce utilities from the Linux side.
 
   To use Pocket IE, follow the instructions given at
   http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
@@ -153,8 +130,18 @@
 
   If it doesn't work for some reason, load both the usbserial and ipaq module
   with the module parameter "debug" set to 1 and examine the system log.
-  You can also try soft-resetting your iPAQ before attempting a connection.
+  You can also try soft-resetting your PDA before attempting a connection.
 
+  Other functionality may be possible depending on your PDA. According to
+  Wes Cilldhaire <billybobjoehenrybob@hotmail.com>, with the Toshiba E570,
+  ...if you boot into the bootloader (hold down the power when hitting the
+  reset button, continuing to hold onto the power until the bootloader screen
+  is displayed), then put it in the cradle with the ipaq driver loaded, open
+  a terminal on /dev/ttyUSB0, it gives you a "USB Reflash" terminal, which can
+  be used to flash the ROM, as well as the microP code..  so much for needing
+  Toshiba's $350 serial cable for flashing!! :D
+  NOTE: This has NOT been tested. Use at your own risk.
+ 
   For any questions or problems with the driver, please contact Ganesh
   Varadarajan <ganesh@veritas.com>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/CARDLIST linux-2.4.21-rc3/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.20/Documentation/video4linux/bttv/CARDLIST	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/video4linux/bttv/CARDLIST	2003-05-22 22:06:26.000000000 +0000
@@ -2,7 +2,7 @@
   card=0 -  *** UNKNOWN/GENERIC *** 
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
-  card=3 - STB
+  card=3 - STB, Gateway P/N 6000699 (bt848)
   card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
@@ -22,24 +22,24 @@
   card=20 - CEI Raffles Card
   card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
   card=22 - Askey CPH050/ Phoebe Tv Master + FM
-  card=23 - Modular Technology MM205 PCTV, bt878
+  card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878
   card=24 - Askey CPH05X/06X (bt878) [many vendors]
-  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
   card=26 - Hauppauge WinCam newer (bt878)
   card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
-  card=28 - Terratec TerraTV+
+  card=28 - Terratec TerraTV+ Version 1.1 (bt878)
   card=29 - Imagenation PXC200
   card=30 - Lifeview FlyVideo 98 LR50
   card=31 - Formac iProTV
   card=32 - Intel Create and Share PCI/ Smart Video Recorder III
-  card=33 - Terratec TerraTValue
-  card=34 - Leadtek WinFast 2000
+  card=33 - Terratec TerraTValue Version Bt878
+  card=34 - Leadtek WinFast 2000/ WinFast 2000 XP
   card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
   card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
   card=37 - Prolink PixelView PlayTV pro
   card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
-  card=40 - STB2
+  card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100
   card=41 - AVerMedia TVPhone 98
   card=42 - ProVideo PV951
   card=43 - Little OnAir TV
@@ -69,7 +69,7 @@
   card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
   card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
   card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
@@ -80,11 +80,28 @@
   card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
   card=79 - DSP Design TCVIDEO
   card=80 - Hauppauge WinTV PVR
+  card=81 - GV-BCTV5/PCI
+  card=82 - Osprey 100/150 (878)
+  card=83 - Osprey 100/150 (848)
+  card=84 - Osprey 101 (848)
+  card=85 - Osprey 101/151
+  card=86 - Osprey 101/151 w/ svid
+  card=87 - Osprey 200/201/250/251
+  card=88 - Osprey 200/250
+  card=89 - Osprey 210/220
+  card=90 - Osprey 500
+  card=91 - Osprey 540
+  card=92 - Osprey 2000
+  card=93 - IDS Eagle
+  card=94 - Pinnacle PCTV Sat
+  card=95 - Formac ProTV II
+  card=96 - MachTV
+  card=97 - Euresys Picolo
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
   type=1 - Philips PAL_I (FI1246 and compatibles)
-  type=2 - Philips NTSC (FI1236 and compatibles)
+  type=2 - Philips NTSC (FI1236,FM1236 and compatibles)
   type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)
   type=4 - NoTuner
   type=5 - Philips PAL_BG (FI1216 and compatibles)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/Cards linux-2.4.21-rc3/Documentation/video4linux/bttv/Cards
--- linux-2.4.20/Documentation/video4linux/bttv/Cards	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/video4linux/bttv/Cards	2003-05-22 22:06:28.000000000 +0000
@@ -4,25 +4,27 @@
 
 
 Suppported cards:
-
-
 Bt848/Bt848a/Bt849/Bt878/Bt879 cards
 ------------------------------------
 
-All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal Composite/S-VHS inputs
-are supported.
-Teletext and Intercast support (PAL only) for ALL cards via VBI sample decoding
-in software.
+All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal
+Composite/S-VHS inputs are supported.  Teletext and Intercast support
+(PAL only) for ALL cards via VBI sample decoding in software.
+
+Some cards with additional multiplexing of inputs or other additional
+fancy chips are only partially supported (unless specifications by the
+card manufacturer are given).  When a card is listed here it isn't
+necessarily fully supported.
 
-Some cards with additional multiplexing of inputs are only partially 
-supported (unless specifications by the card manufacturer are given).
+All other cards only differ by additional components as tuners, sound
+decoders, EEPROMs, teletext decoders ...
 
-All other cards only differ by additional components as tuners, sound decoders,
-EEPROMs, teletext decoders ...
 
 Unsupported Cards: 
 ------------------
-Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by this driver. 
+
+Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by
+this driver.
 
 
 MATRIX Vision
@@ -177,7 +179,8 @@
   has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  FlyVideo A2 (Elta 8680)= LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  Lifeview 3000 (Elta 8681) as sold by Plus(April 2002), Germany = LR138 w/ saa7134
 
 
 Typhoon TV card series:
@@ -197,7 +200,7 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
-  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH, SU1278?) = "KNC1 TV Station DVB-S"
   50692 "TV/FM Tuner" (small PCB)
   50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
   50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
@@ -234,10 +237,20 @@
    PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
    PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
 
+   PixelView PlayTV PAK II (TV/FM card + usb camera)  PV-M3800 
+   PixelView PlayTV XP PV-M4700,PV-M4700(w/FM)
+   PixelView PlayTV DVR PV-M4600  package contents:PixelView PlayTV pro, windvr & videoMail s/w
+
    Further Cards:
    PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
    PV-BT878P+rev.2F
    PV-BT878P Rev.1D (bt878, capture only)
+
+   XCapture PV-CX881P (cx23881)
+   PlayTV HD PV-CX881PL+, PV-CX881PL+(w/FM) (cx23881)
+
+   DTV3000 PV-DTV3000P+ DVB-S CI = Twinhan VP-1030
+   DTV2000 DVB-S = Twinhan VP-1020
    
    Video Conferencing:
    PixelView Meeting PAK - (Model: PV-BT878P)
@@ -245,6 +258,9 @@
    PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
    PixelView Capture - (Model: PV-BT848P)
 
+   PixelView PlayTV USB pro
+   Model No. PV-NT1004+, PV-NT1004+ (w/FM) = NT1004 USB decoder chip + SAA7113 video decoder chip
+
 Dynalink
 --------
    These are CPH series.
@@ -275,6 +291,7 @@
    WinView 601 (Bt848)
    WinView 610 (Zoran)
    WinFast2000
+   WinFast2000 XP
 
 KNC One
 -------
@@ -283,18 +300,37 @@
    TV-Station pro (+TV stereo)
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
+   TV Station SAT (analog satellite)
+   TV-Station DVB-S
 
    newer Cards have saa7134, but model name stayed the same?
 
-Provideo PV951 
---------------
-  These are sold as:
+Provideo 
+--------
+  PV951 or PV-951 (also are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
    Provideo PV951 TF
    3DeMon PV951
    MediaForte TV-Vision PV951
    Yoko PV951
+   Vivanco Tuner Card PCI Art.-Nr.: 68404
+  ) now named PV-951T
+
+  Surveillance Series
+  PV-141
+  PV-143
+  PV-147
+  PV-148 (capture only)
+  PV-150
+  PV-151
+
+  TV-FM Tuner Series
+  PV-951TDV (tv tuner + 1394)
+  PV-951T/TF
+  PV-951PT/TF
+  PV-956T/TF Low Profile
+  PV-911
 
 Highscreen
 ----------
@@ -324,12 +360,45 @@
 
    PCB      PCI-ID      Model-Name      Eeprom  Tuner  Sound    Country
    --------------------------------------------------------------------
-   M1A8-A      --       AVer TV-Phone           FM1216  --
+   M101.C   ISA !
+   M108-B      Bt848                     --     FR1236		 US   (2),(3)
+   M1A8-A      Bt848    AVer TV-Phone           FM1216  --
    M168-T   1461:0003   AVerTV Studio   48:17   FM1216 TDA9840T  D    (1) w/FM w/Remote
    M168-U   1461:0004   TVCapture98     40:11   FI1216   --      D    w/Remote
    M168II-B 1461:0003   Medion MD9592   48:16   FM1216 TDA9873H  D    w/FM
 
    (1) Daughterboard MB68-A with TDA9820T and TDA9840T
+   (2) Sony NE41S soldered (stereo sound?)
+   (3) Daughterboard M118-A w/ pic 16c54 and 4 MHz quartz
+ 
+   US site has different drivers for (as of 09/2002):
+   EZ Capture/InterCam PCI (BT-848 chip)
+   EZ Capture/InterCam PCI (BT-878 chip)
+   TV-Phone (BT-848 chip)
+   TV98 (BT-848 chip)
+   TV98 With Remote (BT-848 chip)
+   TV98 (BT-878 chip)
+   TV98 With Remote (BT-878)
+   TV/FM98 (BT-878 chip)
+   AVerTV
+   AverTV Stereo
+   AVerTV Studio
+
+   DE hat diverse Treiber fuer diese Modelle (Stand 09/2002):
+   TVPhone (848) mit Philips tuner FR12X6 (w/ FM radio)
+   TVPhone (848) mit Philips tuner FM12X6 (w/ FM radio)
+   TVCapture (848) w/Philips tuner FI12X6
+   TVCapture (848) non-Philips tuner
+   TVCapture98 (Bt878)
+   TVPhone98 (Bt878)
+   AVerTV und TVCapture98 w/VCR (Bt 878)
+   AVerTVStudio und TVPhone98 w/VCR (Bt878)
+   AVerTV GO Serie (Kein SVideo Input)
+   AVerTV98 (BT-878 chip)
+   AVerTV98 mit Fernbedienung (BT-878 chip)
+   AVerTV/FM98 (BT-878 chip)
+
+   VDOmate (www.averm.com.cn) = M168U ?
 
 Aimslab
 -------
@@ -338,22 +407,25 @@
 
 IXMicro (former: IMS=Integrated Micro Solutions)
 -------
-   IXTV BT848
+   IXTV BT848 (=TurboTV)
    IXTV BT878
-   TurboTV (Bt848)
+   IMS TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
 --------------------------
    LT9306/MD9306 = CPH061
    LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
-          MD9717 = KNC One (Rev D4, saa7134)
+          MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
+          MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
 
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
    MM100 PCTV (Bt848)
+   MM201 PCTV (Bt878, Bt832) w/ Quartzsight camera
+   MM202 PCTV (Bt878, Bt832, tda9874)
    MM205 PCTV (Bt878)
-   MM210 PCTV (Bt878) (Galaxy TV)
+   MM210 PCTV (Bt878) (Galaxy TV, Galaxymedia ?)
 
 Terratec
 --------
@@ -365,11 +437,13 @@
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra TValue New Revision	  "LR102 Rec.C"
    Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
    Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB
+   Cinergy 600 (saa7134)
 
 Technisat
 ---------
@@ -380,7 +454,7 @@
    Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
    Mediafocus II (saa7146, Sat. analog)
          SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
-   SkyStar 1 DVB  (AV7110)
+   SkyStar 1 DVB  (AV7110) = Technotrend Premium
    SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
@@ -394,6 +468,9 @@
 Powercolor
 ----------
    MTV878
+       Package comes with different contents:
+       a) pcb "MTV878" (CARD=75)
+       b) Pixelview Rev. 4_
    MTV878R w/Remote Control
    MTV878F w/Remote Control w/FM radio
 
@@ -401,10 +478,15 @@
 --------
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
-   Mirovideo PCTV Pro (Bt848 + Daughterboard)
+   Mirovideo PCTV Pro (Bt848 + Daughterboard for TV Stereo and FM)
+   Studio PCTV Rave (Bt848 Version = Mirovideo PCTV)
    Studio PCTV Rave (Bt878 package w/o infrared)
    Studio PCTV      (Bt878)
    Studio PCTV Pro  (Bt878 stereo w/ FM)
+   Pinnacle PCTV    (Bt878, MT2032)
+   Pinnacle PCTV Pro (Bt878, MT2032)
+   Pinncale PCTV Sat (bt878a, HM1821/1221) ["Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811"]
+   Pinnacle PCTV Sat XE
 
    M(J)PEG capture and playback:
    DC1+ (ISA)
@@ -477,7 +559,7 @@
 ------
    iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
    ProTV (Bt848)
-   ProTV II = ProTV Stereo (Bt878)
+   ProTV II = ProTV Stereo (Bt878) ["stereo" means FM stereo, tv is still mono]
 
 ATI
 ---
@@ -502,8 +584,10 @@
 
 STB
 ---
-   TV PCI (Temic4032FY5, tda9850??)
-   other variants?
+   STB Gateway 6000704 (bt878)
+   STB Gateway 6000699 (bt848)
+   STB Gateway 6000402 (bt848)
+   STB TV130 PCI
 
 Videologic
 ----------
@@ -514,6 +598,17 @@
 ------------
    TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
    TT-DVB-Sat
+    revisions 1.1, 1.3, 1.5, 1.6 and 2.1
+    This card is sold as OEM from:
+	Siemens DVB-s Card
+	Hauppauge WinTV DVB-S
+	Technisat SkyStar 1 DVB
+	Galaxis DVB Sat
+    Now this card is called TT-PCline Premium Family
+   TT-Budget (saa7146, bsru6-701a)
+    This card is sold as OEM from:
+	Hauppauge WinTV Nova
+	Satelco Standard PCI (DVB-S)
    TT-DVB-C PCI
 
 Teles
@@ -549,14 +644,99 @@
    Galaxis DVB Card C CI
    Galaxis DVB Card S
    Galaxis DVB Card C
+   Galaxis plug.in S [neuer Name: Galaxis DVB Card S CI
 
 Hauppauge
 ---------
    many many WinTV models ...
-   WinTV DVBs
-   WinTV NOVA
-   WinTV NOVA-CI
-   WinTV-Nexus-s
+   WinTV DVBs = Technotrend Premium 1.3
+   WinTV NOVA = Technotrend Budget 1.1 "S-DVB DATA"
+   WinTV NOVA-CI "SDVBACI"
+   WinTV Nova USB (=Technotrend USB 1.0)
+   WinTV-Nexus-s (=Technotrend Premium 2.1 or 2.2)
+   WinTV PVR
+   WinTV PVR 250
+   WinTV PVR 450
+
+  US models
+  990 WinTV-PVR-350 (249USD) (iTVC15 chipset + radio)
+  980 WinTV-PVR-250 (149USD) (iTVC15 chipset)
+  880 WinTV-PVR-PCI (199USD) (KFIR chipset + bt878)
+  881 WinTV-PVR-USB
+  190 WinTV-GO
+  191 WinTV-GO-FM
+  404 WinTV
+  401 WinTV-radio
+  495 WinTV-Theater
+  602 WinTV-USB
+  621 WinTV-USB-FM
+  600 USB-Live
+  698 WinTV-HD
+  697 WinTV-D
+  564 WinTV-Nexus-S
+
+  Deutsche Modelle
+  603 WinTV GO
+  719 WinTV Primio-FM
+  718 WinTV PCI-FM
+  497 WinTV Theater
+  569 WinTV USB
+  568 WinTV USB-FM
+  882 WinTV PVR
+  981 WinTV PVR 250
+  891 WinTV-PVR-USB
+  541 WinTV Nova
+  488 WinTV Nova-Ci
+  564 WinTV-Nexus-s
+  727 WinTV-DVB-c
+  545 Common Interface
+  898 WinTV-Nova-USB
+
+  UK models
+  607 WinTV Go
+  693,793 WinTV Primio FM
+  647,747 WinTV PCI FM
+  498 WinTV Theater
+  883 WinTV PVR
+  893 WinTV PVR USB  (Duplicate entry)
+  566 WinTV USB (UK)
+  573 WinTV USB FM
+  429 Impact VCB (bt848)
+  600 USB Live (Video-In 1x Comp, 1xSVHS)
+  542 WinTV Nova
+  717 WinTV DVB-S
+  909 Nova-t PCI
+  893 Nova-t USB   (Duplicate entry)
+  802 MyTV
+  804 MyView
+  809 MyVideo
+  872 MyTV2Go FM
+
+ 
+  546 WinTV Nova-S CI
+  543 WinTV Nova
+  907 Nova-S USB
+  908 Nova-T USB
+  717 WinTV Nexus-S
+  157 DEC3000-s Standalone + USB
+
+  Spain
+  685 WinTV-Go
+  690 WinTV-PrimioFM
+  416 WinTV-PCI Nicam Estereo
+  677 WinTV-PCI-FM
+  699 WinTV-Theater
+  683 WinTV-USB
+  678 WinTV-USB-FM
+  983 WinTV-PVR-250
+  883 WinTV-PVR-PCI
+  993 WinTV-PVR-350
+  893 WinTV-PVR-USB
+  728 WinTV-DVB-C PCI
+  832 MyTV2Go
+  869 MyTV2Go-FM
+  805 MyVideo (USB)
+  
 
 Matrix-Vision
 -------------
@@ -567,6 +747,7 @@
 Conceptronic (.net)
 ------------
    TVCON FM,  TV card w/ FM = CPH05x
+   TVCON = CPH06x
 
 BestData
 --------
@@ -601,11 +782,22 @@
 
 Kworld (www.kworld.com.tw)
 --------------------------
-   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
-   KWORLD KW-TV878R-Pro TV
-   KWORLD KW-TVL878RF  (low profile)
-   KWORLD KW-TV878R TV Capture (No FM Radio)
-   KWORLD KW-TV878RF TV
+  PC TV Station
+   KWORLD KW-TV878R  TV (no radio)
+   KWORLD KW-TV878RF TV (w/ radio)
+
+   KWORLD KW-TVL878RF (low profile)
+
+   KWORLD KW-TV713XRF (saa7134)
+
+
+  MPEG TV Station (same cards as above plus WinDVR Software MPEG en/decoder)
+   KWORLD KW-TV878R -Pro   TV (no Radio)
+   KWORLD KW-TV878RF-Pro   TV (w/ Radio)
+   KWORLD KW-TV878R -Ultra TV (no Radio)
+   KWORLD KW-TV878RF-Ultra TV (w/ Radio)
+
+
 
 JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
 ---------------------------------------------------------------------
@@ -622,7 +814,7 @@
 
 NoBrand
 -------
-   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or "878TV Rev.3_"
 
 Mach www.machspeed.com
 ----
@@ -642,9 +834,13 @@
    HS-878 Mini PCI Capture Add-on Card
    HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
 
-Satelco
+Satelco www.citycom-gmbh.de, www.satelco.de
 -------
    TV-FM =KNC1 saa7134
+   Standard PCI (DVB-S) = Technotrend Budget
+   Standard PCI (DVB-S) w/ CI
+   Satelco Highend PCI (DVB-S) = Technotrend Premium
+
 
 Sensoray www.sensoray.com
 --------
@@ -661,3 +857,105 @@
    Manufacturer of video cards is listed as:
    Cogent Electronics Industries [CEI]
 
+AITech
+------
+   Wavewatcher TV (ISA)
+   AITech WaveWatcher TV-PCI = can be LR26 (Bt848) or LR50 (BT878)
+   WaveWatcher TVR-202 TV/FM Radio Card (ISA)
+
+MAXRON
+------
+   Maxron MaxTV/FM Radio (KW-TV878-FNT) = Kworld or JW-TV878-FBK
+
+www.ids-imaging.de
+------------------
+   Falcon Series (capture only)
+ In USA: http://www.theimagingsource.com/
+   DFG/LC1	
+
+www.sknet-web.co.jp
+-------------------
+   SKnet Monster TV (saa7134)
+
+A-Max www.amaxhk.com (Colormax, Amax, Napa)
+-------------------
+   APAC Viewcomp 878
+
+Cybertainment
+-------------
+   CyberMail AV Video Email Kit w/ PCI Capture Card (capture only)
+   CyberMail Xtreme
+  These are Flyvideo
+
+VCR (http://www.vcrinc.com/) 
+---
+  Video Catcher 16
+
+Twinhan
+-------
+   DST Card/DST-IP (bt878, twinhan asic) VP-1020
+    Sold as:
+     KWorld DVBS Satellite TV-Card
+     Powercolor DSTV Satellite Tuner Card
+     Prolink Pixelview DTV2000
+     Provideo PV-911 Digital Satellite TV Tuner Card With Common Interface ?
+   DST-CI Card (DVB Satellite) VP-1030
+   DCT Card (DVB cable)
+
+MSI
+---
+    MSI TV@nywhere Tuner Card (MS-8876) (CX23881/883) Not Bt878 compatible.
+    MS-8401 DVB-S
+
+Focus www.focusinfo.com
+-----
+    InVideo PCI (bt878)
+
+Sdisilk www.sdisilk.com/
+-------
+    SDI Silk 100
+    SDI Silk 200 SDI Input Card
+
+www.euresys.com
+    PICOLO series 
+
+PMC/Pace
+www.pacecom.co.uk website closed
+
+Mercury www.kobian.com (UK and FR)
+    LR50
+    LR138RBG-Rx  == LR138
+
+TEC sound (package and manuals don't have any other manufacturer info) TecSound
+    Though educated googling found: www.techmakers.com
+    TV-Mate = Zoltrix VP-8482
+
+Lorenzen www.lorenzen.de
+--------
+     SL DVB-S PCI = Technotrend Budget PCI (su1278 or bsru version)
+
+Origo (.uk) www.origo2000.com
+     PC TV Card = LR50
+
+I/O Magic www.iomagic.com
+---------
+    PC PVR - Desktop TV Personal Video Recorder DR-PCTV100 = Pinnacle ROB2D-51009464 4.0 + Cyberlink PowerVCR II
+
+Arowana
+-------
+    TV-Karte / Poso Power TV (?) = Zoltrix VP-8482 (?)
+
+iTVC15 boards:
+-------------
+kuroutoshikou.com ITVC15
+yuan.com MPG160 PCI TV (Internal PCI MPEG2 encoder card plus TV-tuner)
+
+Asus www.asuscom.com
+   Asus TV Tuner Card 880 NTSC (low profile, cx23880)
+   Asus TV (saa7134)
+
+Hoontech
+--------
+http://www.hoontech.com/korean/download/down_driver_list03.html
+   HART Vision 848 (H-ART Vision 848)
+   HART Vision 878 (H-Art Vision 878)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/Sound-FAQ linux-2.4.21-rc3/Documentation/video4linux/bttv/Sound-FAQ
--- linux-2.4.20/Documentation/video4linux/bttv/Sound-FAQ	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/video4linux/bttv/Sound-FAQ	2003-05-22 22:06:47.000000000 +0000
@@ -79,10 +79,11 @@
 What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
-values used by the windows driver.  A tool to do this is available from
-ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it does'nt
-work with bt878 boards according to some reports I received.  Another
-one is available from http://www.kki.net.pl/~borgx/bTV.html.
+values used by the windows driver.  A tool to do this is available
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it
+does'nt work with bt878 boards according to some reports I received.
+Another one with bt878 suport is available from
+http://btwincap.sourceforge.net/Files/btspy2.00.zip
 
 You might also dig around in the *.ini files of the Windows applications.
 You can have a look at the board to see which of the gpio pins are
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/meye.txt linux-2.4.21-rc3/Documentation/video4linux/meye.txt
--- linux-2.4.20/Documentation/video4linux/meye.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/video4linux/meye.txt	2003-05-22 22:06:38.000000000 +0000
@@ -1,6 +1,7 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
@@ -52,7 +53,7 @@
 				or
 			xawtv -c /dev/video0 -geometry 320x240
 
-	motioneye (<http://www.alcove-labs.org/en/software/meye/>)
+	motioneye (<http://popies.net/meye/>)
 		for getting ppm or jpg snapshots, mjpeg video
 
 Private API:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/watchdog-api.txt linux-2.4.21-rc3/Documentation/watchdog-api.txt
--- linux-2.4.20/Documentation/watchdog-api.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/watchdog-api.txt	2003-05-22 22:06:47.000000000 +0000
@@ -278,7 +278,7 @@
 	when the timeout runs out which can be 0 = RESET (default), 
 	1 = SMI, 2 = NMI, 3 = SCI.
 
-	Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+	Supports CONFIG_WATCHDOG_NOWAYOUT and the magic character
 	'V' close handling.
 
 	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/x86_64/mm.txt linux-2.4.21-rc3/Documentation/x86_64/mm.txt
--- linux-2.4.20/Documentation/x86_64/mm.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/Documentation/x86_64/mm.txt	2003-05-22 22:06:39.000000000 +0000
@@ -2,7 +2,6 @@
 
 o	per process virtual address space limit of 512 Gigabytes
 o	top of userspace stack located at address 0x0000007fffffffff
-o	PAGE_OFFSET = 0xffff800000000000
 o	start of the kernel mapping =  0x0000010000000000
 o	global RAM per system 508*512GB=254 Terabytes
 o	no need of any common code change
@@ -65,6 +64,7 @@
         1    unmapped
         2    __PAGE_OFFSET - start of direct mapping of physical memory
         ...  direct mapping in further slots as needed.
+	509  some io mappings (others are in a memory hole below 4gb)
         510  vmalloc and ioremap space
 	511  kernel code mapping, fixmaps and modules.  
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/MAINTAINERS linux-2.4.21-rc3/MAINTAINERS
--- linux-2.4.20/MAINTAINERS	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/MAINTAINERS	2003-05-22 22:06:48.000000000 +0000
@@ -80,7 +80,7 @@
 
 3C501 NETWORK DRIVER
 P:	Alan Cox
-M:	alan@the.3c501.cabal.tm
+M:	alan@lxorguk.ukuu.org.uk
 L:	linux-net@vger.kernel.org
 S:	Maintained for 2.2 only
 
@@ -90,6 +90,12 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+3CR990 NETWORK DRIVER
+P:	David Dillow
+M:	dave@thedillows.org
+L:	linux-net@vger.kernel.org
+S:	Maintained
+
 53C700 AND 53C700-66 SCSI DRIVER
 P:	James E.J. Bottomley
 M:	James.Bottomley@HansenPartnership.com
@@ -104,12 +110,12 @@
 
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 S:	Maintained
 
 8139TOO 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -154,6 +160,14 @@
 W:	http://www.ibm.com/linux/ltc/
 S:	Supported
 
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-announce@dell.com
+W:	http://domsch.com/linux
+S:	Supported
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -192,6 +206,13 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+ALTERA EPXA1/EPXA10 DEVELOPMENT BOARD PORT
+P:	Clive Davies
+M:	cdavies@altera.com
+L:	linux-arm-kernel@lists.arm.linux.org.uk
+W:      http://www.arm.linux.org.uk/
+S:	Maintained
+
 APM DRIVER
 P:	Stephen Rothwell
 M:	sfr@canb.auug.org.au
@@ -210,6 +231,13 @@
 M:	linux@treblig.org
 S:	Maintained
 
+ARM/PT DIGITAL BOARD PORT
+P:	Stefan Eletzhofer
+M:	stefan.eletzhofer@eletztrick.de
+L:	linux-arm-kernel@lists.arm.linux.org.uk
+W:	http://www.arm.linux.org.uk/
+S:	Maintained
+
 ARM/SHARK MACHINE SUPPORT
 P:	Alexander Schulz
 M:	alex@shark-linux.de
@@ -229,6 +257,13 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+ATM
+P:	Chas Williams
+M:	chas@cmf.nrl.navy.mil
+L:	linux-atm-general@lists.sourceforge.net
+W:	http://linux-atm.sourceforge.net
+S:	Maintained
+
 AX.25 NETWORK LAYER
 P:	Matthias Welwarsky
 M:	dg2fef@afthd.tu-darmstadt.de
@@ -245,7 +280,7 @@
 BEFS FILE SYSTEM
 P:	Will Dyson
 M:	will@cs.earlham.edu
-W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+W:	http://befs-driver.sourceforge.net/
 S:	Maintained
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
@@ -279,6 +314,15 @@
 W:	http://www.holtmann.org/linux/bluetooth/
 S:	Maintained
 
+BONDING DRIVER
+P:   Chad Tindel
+M:   ctindel@users.sourceforge.net
+P:   Jay Vosburgh
+M:   fubar@us.ibm.com
+L:   bonding-devel@lists.sourceforge.net
+W:   http://sourceforge.net/projects/bonding/
+S:   Supported
+
 BTTV VIDEO4LINUX DRIVER
 P:	Gerd Knorr
 M:	kraxel@bytesex.org
@@ -286,16 +330,9 @@
 W:	http://bytesex.org/bttv/
 S:	Maintained
 
-BUSLOGIC SCSI DRIVER
-P:	Leonard N. Zubkoff
-M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.dandelion.com/Linux/
-S:	Maintained
-
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Odd Fixes
 
@@ -314,25 +351,25 @@
 W:	http://www.coda.cs.cmu.edu/
 S:	Maintained
 
-COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
-P:      Amy Vanzant-Hodge 
-M:      Amy Vanzant-Hodge (fibrechannel@compaq.com)
-L:	compaqandlinux@cpqlin.van-dijk.net
-W:	ftp.compaq.com/pub/products/drivers/linux
-S:      Supported
+HP (was COMPAQ) FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
+P:      Stephen Cameron
+M:      arrays@hp.com 
+M:      steve.cameron@hp.com
+L:	cpqfc-discuss@lists.sourceforge.net
+S:      Odd Fixes
+
+HP (was COMPAQ) SMART2 RAID DRIVER
+P:	Stephen Cameron
+M:	arrays@hp.com
+M:	steve.cameron@hp.com
+L:	cpqarray-discuss@lists.sourceforge.net
+S:	Odd Fixes
 
-COMPAQ SMART2 RAID DRIVER
-P:	Charles White	
-M:	Charles White <arrays@compaq.com>
-L:	compaqandlinux@cpqlin.van-dijk.net
-W:	ftp.compaq.com/pub/products/drivers/linux
-S:	Supported	
-
-COMPAQ SMART CISS RAID DRIVER 
-P:	Charles White
-M:	Charles White <arrays@compaq.com>
-L:	compaqandlinux@cpqlin.van-dijk.net
-W:	ftp.compaq.com/pub/products/drivers/linux	
+HP (was COMPAQ) SMART CISS RAID DRIVER 
+P:	Stephen Cameron
+M:	arrays@hp.com
+M:	steve.cameron@hp.com
+L:	cciss-discuss@lists.sourceforge.net
 S:	Supported 
 
 COMPUTONE INTELLIPORT MULTIPORT CARD
@@ -553,8 +590,8 @@
 S:	Maintained
 
 ETHERNET BRIDGE
-P:	Lennert Buytenhek
-M:	buytenh@gnu.org
+P:	Stephen Hemminger
+M:	shemminger@osdl.org
 L:	bridge@math.leidenuniv.nl
 W:	http://bridge.sourceforge.net/
 S:	Maintained
@@ -710,6 +747,13 @@
 W:	http://www.linuxia64.org/
 S:	Maintained
 
+SN-IA64 (Itanium) SUB-PLATFORM
+P:	John Hesterberg
+M:	jh@sgi.com
+L:	linux-ia64@linuxia64.org
+W:	http://www.sgi.com/altix
+S:	Maintained
+
 IBM MCA SCSI SUBSYSTEM DRIVER
 P:	Michael Lang
 M:	langa2@kph.uni-mainz.de
@@ -792,7 +836,7 @@
 
 INTEL I8XX RANDOM NUMBER GENERATOR SUPPORT
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -801,9 +845,17 @@
 M:	tigran@veritas.com
 S:	Maintained
 
+INTEL PRO/1000 GIGABIT ETHERNET SUPPORT
+P:	Jeb Cramer
+M:	cramerj@intel.com
+P:	Scott Feldman
+M:	scott.feldman@intel.com
+W:	http://sourceforge.net/projects/e1000/
+S:	Supported
+
 INTERMEZZO FILE SYSTEM
-P:	Peter J. Braam
-M:      braam@clusterfs.com
+P:	Chen Yang
+M:	intermezzo-devel@lists.sourceforge.net
 W:      http://www.inter-mezzo.org/
 L:      intermezzo-discuss@lists.sourceforge.net
 S:      Maintained
@@ -1041,6 +1093,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/meye/
+S:	Maintained
+
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -1106,7 +1164,7 @@
 P:	Andrew Morton
 M:	akpm@zip.com.au
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -1123,6 +1181,8 @@
 M:	kuznet@ms2.inr.ac.ru
 P:	Pekka Savola (ipv6)
 M:	pekkas@netcore.fi
+P:	James Morris
+M:	jmorris@intercode.com.au
 L:	netdev@oss.sgi.com
 S:	Maintained
 
@@ -1145,6 +1205,14 @@
 W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:	Maintained
 
+NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
+P:	GOTO Masanori
+M:	gotom@debian.or.jp
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1160,7 +1228,7 @@
 
 NVIDIA (RIVA) FRAMEBUFFER DRIVER
 P:	Ani Joshi
-M:	ajoshi@shell.unixbox.com
+M:	ajoshi@kernel.crashing.org
 L:	linux-nvidia@lists.surfsouth.com
 S:	Maintained
 
@@ -1277,6 +1345,13 @@
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
+PHILIPS NINO PALM PC
+P:	Steven Hill
+M:	sjhill@realitydiluted.com
+L:	linux-mips@oss.sgi.com
+W:	http://www.realitydiluted.com/projects/nino
+S:	Maintained
+
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
@@ -1316,17 +1391,6 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
-PROMISE PDC202XX IDE CONTROLLER DRIVER
-P:	Hank Yang
-M:	support@promise.com.tw [TAIWAN]
-P:	Jordan Rhody
-M:	support@promise.com [U.S.A]
-P:	Jack Hu
-M:	support-china@promise.com [CHINA]
-W:	http://www.promise.com/support/linux_eng.asp
-W:	http://www.promise.com.tw/support/linux_eng.asp
-S:	Maintained
-
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -1401,7 +1465,7 @@
 SA1100 SUPPORT
 P:	Nicolas Pitre
 M:	nico@cam.org
-L:	sa1100-linux@pa.dec.com
+L:	linux-arm@lists.arm.linux.org.uk
 S:	Maintained
 
 SBPCD CDROM DRIVER
@@ -1439,6 +1503,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+SCx200 CPU SUPPORT
+P:	Christer Weinigel
+M:	christer@weinigel.se
+W:	http://www.weinigel.se
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
@@ -1459,6 +1529,12 @@
 L:	linux-net@vger.kernel.org
 S:	Supported
 
+SIS FRAMEBUFFER DRIVER
+P:   	Thomas Winischhofer
+M:	thomas@winischhofer.net
+W:	http://www.winischhofer.net/linuxsisvga.shtml
+S:	Maintained
+
 SMB FILESYSTEM
 P:	Urban Widmark
 M:	urban@teststation.com
@@ -1487,12 +1563,18 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+SONY VAIO CONTROL DEVICE DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/sonypi/
+S:	Maintained
+
 SOUND
 P:	Alan Cox
 M:	alan@redhat.com
 S:	Maintained for 2.2 only
 
-SPARC:
+UltraSPARC (sparc64):
 P:	David S. Miller
 M:	davem@redhat.com
 P:	Eddie C. Dost
@@ -1505,6 +1587,10 @@
 L:	ultralinux@vger.kernel.org
 S:	Maintained
 
+SPARC (sparc32):
+L:	sparclinux@vger.kernel.org
+S:	Unmaintained - please send patches to mailing list
+
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 P:	Roger Wolff
 M:	R.E.Wolff@BitWizard.nl
@@ -1568,6 +1654,12 @@
 L:	linux-video@atrey.karlin.mff.cuni.cz
 S:	Maintained
 
+SYSKONNECT DRIVER
+P: Mirko Lindner
+M: mlindner@syskonnect.de
+W: http://www.syskonnect.com
+S: Supported
+
 SYSV FILESYSTEM
 P:	Christoph Hellwig
 M:	hch@infradead.org
@@ -1580,6 +1672,11 @@
 M:      jb@technologeek.org
 S:      Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
@@ -1631,7 +1728,7 @@
 
 TULIP NETWORK DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	tulip-users@lists.sourceforge.net
 W:	http://sourceforge.net/projects/tulip/
 S:	Maintained
@@ -1695,11 +1792,12 @@
 W:	http://www.kroah.com/linux-usb/
 
 USB CDC ETHERNET DRIVER
-P:	Brad Hards
-M:	bradh@frogmouth.net
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
+W:	http://www.kroah.com/linux-usb/
 
 USB EHCI DRIVER
 P:	David Brownell
@@ -1773,6 +1871,14 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB SCANNER DRIVER
+P:	Henning Meier-Geinitz
+M:	henning@meier-geinitz.de
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://www.meier-geinitz.de/kernel/
+S:	Maintained
+
 USB SE401 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
@@ -1860,6 +1966,11 @@
 L:	linux-via@gtf.org
 S:	Odd fixes
 
+VIA RHINE NETWORK DRIVER
+P:	Roger Luethi
+M:	rl@hellgate.ch
+S:	Maintained
+
 USB DIAMOND RIO500 DRIVER
 P:	Cesar Miquel
 M:	miquel@df.uba.ar
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Makefile linux-2.4.21-rc3/Makefile
--- linux-2.4.20/Makefile	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-rc3/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 20
-EXTRAVERSION =
+SUBLEVEL = 21
+EXTRAVERSION = -rc3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -137,8 +137,7 @@
 DRIVERS-y += drivers/char/char.o \
 	drivers/block/block.o \
 	drivers/misc/misc.o \
-	drivers/net/net.o \
-	drivers/media/media.o
+	drivers/net/net.o
 DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
 DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
 DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
@@ -179,6 +178,7 @@
 DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
+DRIVERS-y +=drivers/media/media.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
 DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
 DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
@@ -342,7 +342,7 @@
 	 ([ -x /bin/domainname ] && /bin/domainname > .ver1) || \
 	 echo > .ver1
 	@echo \#define LINUX_COMPILE_DOMAIN \"`cat .ver1 | $(uts_truncate)`\" >> .ver
-	@echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver
+	@echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -n 1`\" >> .ver
 	@mv -f .ver $@
 	@rm -f .ver1
 
@@ -488,12 +488,13 @@
 	find . -type f -print | sort | xargs sum > .SUMS
 
 dep-files: scripts/mkdep archdep include/linux/version.h
-	scripts/mkdep -- init/*.c > .depend
-	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	rm -f .depend .hdepend
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
 endif
+	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	scripts/mkdep -- init/*.c > .depend
 
 ifdef CONFIG_MODVERSIONS
 MODVERFILE := $(TOPDIR)/include/linux/modversions.h
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/REPORTING-BUGS linux-2.4.21-rc3/REPORTING-BUGS
--- linux-2.4.20/REPORTING-BUGS	2001-04-06 17:42:48.000000000 +0000
+++ linux-2.4.21-rc3/REPORTING-BUGS	2003-05-22 22:06:47.000000000 +0000
@@ -9,7 +9,7 @@
 bug report. This explains what you should do with the "Oops" information
 to make it useful to the recipient.
 
-      Send the output the maintainer of the kernel area that seems to
+      Send the output to the maintainer of the kernel area that seems to
 be involved with the problem. Don't worry too much about getting the
 wrong person. If you are unsure send it to the person responsible for the
 code relevant to what you were doing. If it occurs repeatably try and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/config.in linux-2.4.21-rc3/arch/alpha/config.in
--- linux-2.4.20/arch/alpha/config.in	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/config.in	2003-05-22 22:06:38.000000000 +0000
@@ -42,6 +42,7 @@
 	 Eiger			CONFIG_ALPHA_EIGER		\
 	 Jensen			CONFIG_ALPHA_JENSEN		\
 	 LX164			CONFIG_ALPHA_LX164		\
+	 Marvel			CONFIG_ALPHA_MARVEL		\
 	 Miata			CONFIG_ALPHA_MIATA		\
 	 Mikasa			CONFIG_ALPHA_MIKASA		\
 	 Nautilus		CONFIG_ALPHA_NAUTILUS		\
@@ -181,6 +182,12 @@
 	define_bool CONFIG_ALPHA_EV6 y
 	define_bool CONFIG_ALPHA_EV67 y
 fi
+if [ "$CONFIG_ALPHA_MARVEL" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV6 y
+	define_bool CONFIG_ALPHA_EV67 y
+	define_bool CONFIG_ALPHA_EV7 y
+fi
 if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
@@ -208,7 +215,8 @@
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
-	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" \
+	-o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	define_bool CONFIG_ALPHA_SRM y
 fi
@@ -222,6 +230,8 @@
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
 fi
 
+bool 'Verbose Machine Checks' CONFIG_VERBOSE_MCHECK
+
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
@@ -240,7 +250,7 @@
 if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
 	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" \
-	-o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_SHARK" = "y" -o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	bool 'Symmetric multi-processing support' CONFIG_SMP
 fi
@@ -249,6 +259,10 @@
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
 
+if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_SRM" = "y" ]; then
+	define_bool CONFIG_EARLY_PRINTK y
+fi
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
@@ -311,6 +325,7 @@
 tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
 if [ "$CONFIG_IDE" != "n" ]; then
+  int '  Maximum IDE interfaces' MAX_HWIFS 4
   source drivers/ide/Config.in
 else
   define_bool CONFIG_BLK_DEV_IDE_MODES n
@@ -330,6 +345,7 @@
 
 if [ "$CONFIG_PCI" = "y" ]; then
   source drivers/message/fusion/Config.in
+  source drivers/ieee1394/Config.in
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
@@ -366,6 +382,10 @@
 fi
 endmenu
 
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
 source drivers/char/Config.in
 
 #source drivers/misc/Config.in
@@ -401,7 +421,6 @@
 endmenu
 
 source drivers/usb/Config.in
-source drivers/input/Config.in
 
 source net/bluetooth/Config.in
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/defconfig linux-2.4.21-rc3/arch/alpha/defconfig
--- linux-2.4.20/arch/alpha/defconfig	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/defconfig	2003-05-22 22:06:47.000000000 +0000
@@ -51,6 +51,7 @@
 # CONFIG_ALPHA_TAKARA is not set
 # CONFIG_ALPHA_TITAN is not set
 # CONFIG_ALPHA_WILDFIRE is not set
+CONFIG_VERBOSE_MCHECK=y
 CONFIG_ISA=y
 CONFIG_EISA=y
 # CONFIG_SBUS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/Makefile linux-2.4.21-rc3/arch/alpha/kernel/Makefile
--- linux-2.4.20/arch/alpha/kernel/Makefile	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/Makefile	2003-05-22 22:06:42.000000000 +0000
@@ -17,7 +17,8 @@
 export-objs := alpha_ksyms.o
 
 obj-y    := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \
-	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o
+	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o \
+	    err_common.o
 
 #
 # FIXME!
@@ -38,20 +39,27 @@
 
 obj-y 	 += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \
 	    core_polaris.o core_t2.o core_tsunami.o core_titan.o \
+	    core_wildfire.o core_marvel.o \
 	    sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
 	    sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \
 	    sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
 	    sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \
-	    sys_wildfire.o core_wildfire.o irq_pyxis.o
+	    sys_wildfire.o sys_marvel.o \
+	    err_titan.o err_marvel.o \
+	    irq_pyxis.o srmcons.o gct.o
 
 else
 
+# Misc support
+obj-$(CONFIG_ALPHA_SRM) += srmcons.o gct.o
+
 # Core logic support
 obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
 obj-$(CONFIG_ALPHA_CIA) += core_cia.o
 
 obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o
 obj-$(CONFIG_ALPHA_LCA) += core_lca.o
+obj-$(CONFIG_ALPHA_MARVEL) += core_marvel.o
 obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o
 obj-$(CONFIG_ALPHA_T2) += core_t2.o
 obj-$(CONFIG_ALPHA_TSUNAMI) += core_tsunami.o
@@ -69,7 +77,7 @@
 
 obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o
 obj-$(CONFIG_ALPHA_SHARK) += sys_dp264.o
-obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o
+obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o err_titan.o
 
 ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),)
 obj-y    += sys_eb64p.o
@@ -77,6 +85,7 @@
 
 obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o
 obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o
+obj-$(CONFIG_ALPHA_MARVEL) += sys_marvel.o err_marvel.o
 obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o
 obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o
 obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/alpha_ksyms.c linux-2.4.21-rc3/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.20/arch/alpha/kernel/alpha_ksyms.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/alpha_ksyms.c	2003-05-22 22:06:26.000000000 +0000
@@ -37,6 +37,8 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
+extern void dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+			    struct task_struct *task);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 extern spinlock_t kernel_flag;
 extern spinlock_t rtc_lock;
@@ -119,7 +121,7 @@
 EXPORT_SYMBOL(clear_page);
 
 EXPORT_SYMBOL(__delay);
-EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(ndelay);
 EXPORT_SYMBOL(udelay);
 
 EXPORT_SYMBOL(__direct_map_base);
@@ -142,6 +144,7 @@
 #endif
 
 EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_elf_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(hwrpb);
 EXPORT_SYMBOL(wrusp);
@@ -237,6 +240,13 @@
 EXPORT_SYMBOL(cpu_present_mask);
 #endif /* CONFIG_SMP */
 
+/*
+ * NUMA specific symbols
+ */
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(plat_node_data);
+#endif /* CONFIG_DISCONTIGMEM */
+
 EXPORT_SYMBOL(rtc_lock);
 
 /*
@@ -266,3 +276,11 @@
 EXPORT_SYMBOL(irongate_ioremap);
 EXPORT_SYMBOL(irongate_iounmap);
 #endif
+#ifdef CONFIG_ALPHA_TITAN
+EXPORT_SYMBOL(titan_ioremap);
+EXPORT_SYMBOL(titan_iounmap);
+#endif
+#ifdef CONFIG_ALPHA_MARVEL
+EXPORT_SYMBOL(marvel_ioremap);
+EXPORT_SYMBOL(marvel_iounmap);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_cia.c linux-2.4.21-rc3/arch/alpha/kernel/core_cia.c
--- linux-2.4.20/arch/alpha/kernel/core_cia.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_cia.c	2003-05-22 22:06:48.000000000 +0000
@@ -47,6 +47,15 @@
 
 #define vip	volatile int  *
 
+/* Save CIA configuration data as the console had it set up.  */
+
+struct 
+{
+	unsigned int w_base;
+	unsigned int w_mask;
+	unsigned int t_base;
+} saved_config[4] __attribute((common));
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address.  It is therefore not safe to have
@@ -370,7 +379,7 @@
 }
 
 static inline void
-cia_prepare_tbia_workaround(void)
+cia_prepare_tbia_workaround(int window)
 {
 	unsigned long *ppte, pte;
 	long i;
@@ -382,10 +391,10 @@
 	for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i)
 		ppte[i] = pte;
 
-	*(vip)CIA_IOC_PCI_W1_BASE = CIA_BROKEN_TBIA_BASE | 3;
-	*(vip)CIA_IOC_PCI_W1_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1)
-				    & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T1_BASE = virt_to_phys(ppte) >> 2;
+	*(vip)CIA_IOC_PCI_Wn_BASE(window) = CIA_BROKEN_TBIA_BASE | 3;
+	*(vip)CIA_IOC_PCI_Wn_MASK(window)
+	  = (CIA_BROKEN_TBIA_SIZE*1024 - 1) & 0xfff00000;
+	*(vip)CIA_IOC_PCI_Tn_BASE(window) = virt_to_phys(ppte) >> 2;
 }
 
 static void __init
@@ -605,8 +614,7 @@
 do_init_arch(int is_pyxis)
 {
 	struct pci_controller *hose;
-	int temp;
-	int cia_rev;
+	int temp, cia_rev, tbia_window;
 
 	cia_rev = *(vip)CIA_IOC_CIA_REV & CIA_REV_MASK;
 	printk("pci: cia revision %d%s\n",
@@ -681,13 +689,31 @@
 		hose->dense_io_base = CIA_BW_IO - IDENT_ADDR;
 	}
 
+	/* Save CIA configuration data as the console had it set up.  */
+
+	saved_config[0].w_base = *(vip)CIA_IOC_PCI_W0_BASE;
+	saved_config[0].w_mask = *(vip)CIA_IOC_PCI_W0_MASK;
+	saved_config[0].t_base = *(vip)CIA_IOC_PCI_T0_BASE;
+
+	saved_config[1].w_base = *(vip)CIA_IOC_PCI_W1_BASE;
+	saved_config[1].w_mask = *(vip)CIA_IOC_PCI_W1_MASK;
+	saved_config[1].t_base = *(vip)CIA_IOC_PCI_T1_BASE;
+
+	saved_config[2].w_base = *(vip)CIA_IOC_PCI_W2_BASE;
+	saved_config[2].w_mask = *(vip)CIA_IOC_PCI_W2_MASK;
+	saved_config[2].t_base = *(vip)CIA_IOC_PCI_T2_BASE;
+
+	saved_config[3].w_base = *(vip)CIA_IOC_PCI_W3_BASE;
+	saved_config[3].w_mask = *(vip)CIA_IOC_PCI_W3_MASK;
+	saved_config[3].t_base = *(vip)CIA_IOC_PCI_T3_BASE;
+
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather 1MB at 768MB (for tbia)
+	 * Window 0 is S/G 8MB at 8MB (for isa)
+	 * Window 1 is S/G 1MB at 768MB (for tbia) (unused for CIA rev 1)
 	 * Window 2 is direct access 2GB at 2GB
-	 * Window 3 is DAC access 4GB at 8GB
+	 * Window 3 is DAC access 4GB at 8GB (or S/G for tbia if CIA rev 1)
 	 *
 	 * ??? NetBSD hints that page tables must be aligned to 32K,
 	 * possibly due to a hardware bug.  This is over-aligned
@@ -697,6 +723,7 @@
 
 	hose->sg_pci = NULL;
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768);
+
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
@@ -715,8 +742,20 @@
 	   are compared against W_DAC.  We can, however, directly map 4GB,
 	   which is better than before.  However, due to assumptions made
 	   elsewhere, we should not claim that we support DAC unless that
-	   4GB covers all of physical memory.  */
-	if (is_pyxis || max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
+	   4GB covers all of physical memory.
+
+	   On CIA rev 1, apparently W1 and W2 can't be used for SG.
+	   At least, there are reports that it doesn't work for Alcor.
+	   In that case, we have no choice but to use W3 for the TBIA
+	   workaround, which means we can't use DAC at all.  */
+
+	tbia_window = 1;
+	if (is_pyxis) {
+		*(vip)CIA_IOC_PCI_W3_BASE = 0;
+	} else if (cia_rev == 1) {
+		*(vip)CIA_IOC_PCI_W1_BASE = 0;
+		tbia_window = 3;
+	} else if (max_low_pfn > (0x100000000UL >> PAGE_SHIFT)) {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0;
 	} else {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
@@ -728,7 +767,7 @@
 	}
 
 	/* Prepare workaround for apparently broken tbia. */
-	cia_prepare_tbia_workaround();
+	cia_prepare_tbia_workaround(tbia_window);
 }
 
 void __init
@@ -762,6 +801,26 @@
 	do_init_arch(1);
 }
 
+void
+cia_kill_arch(int mode)
+{
+	*(vip)CIA_IOC_PCI_W0_BASE = saved_config[0].w_base;
+	*(vip)CIA_IOC_PCI_W0_MASK = saved_config[0].w_mask;
+	*(vip)CIA_IOC_PCI_T0_BASE = saved_config[0].t_base;
+
+	*(vip)CIA_IOC_PCI_W1_BASE = saved_config[1].w_base;
+	*(vip)CIA_IOC_PCI_W1_MASK = saved_config[1].w_mask;
+	*(vip)CIA_IOC_PCI_T1_BASE = saved_config[1].t_base;
+
+	*(vip)CIA_IOC_PCI_W2_BASE = saved_config[2].w_base;
+	*(vip)CIA_IOC_PCI_W2_MASK = saved_config[2].w_mask;
+	*(vip)CIA_IOC_PCI_T2_BASE = saved_config[2].t_base;
+
+	*(vip)CIA_IOC_PCI_W3_BASE = saved_config[3].w_base;
+	*(vip)CIA_IOC_PCI_W3_MASK = saved_config[3].w_mask;
+	*(vip)CIA_IOC_PCI_T3_BASE = saved_config[3].t_base;
+}
+
 void __init
 cia_init_pci(void)
 {
@@ -781,6 +840,7 @@
 	*(vip)CIA_IOC_CIA_ERR;		/* re-read to force write.  */
 }
 
+#ifdef CONFIG_VERBOSE_MCHECK
 static void
 cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
 {
@@ -1048,13 +1108,13 @@
 	printk(KERN_CRIT "  Command: %s, Parity bit: %d\n", cmd, par);
 	printk(KERN_CRIT "  Address: %#010lx, Mask: %#lx\n", addr, mask);
 }
+#endif
 
 static int
 cia_decode_mchk(unsigned long la_ptr)
 {
 	struct el_common *com;
 	struct el_CIA_sysdata_mcheck *cia;
-	int which;
 
 	com = (void *)la_ptr;
 	cia = (void *)(la_ptr + com->sys_offset);
@@ -1062,8 +1122,8 @@
 	if ((cia->cia_err & CIA_ERR_VALID) == 0)
 		return 0;
 
-	which = cia->cia_err & 0xfff;
-	switch (ffs(which) - 1) {
+#ifdef CONFIG_VERBOSE_MCHECK
+	switch (ffs(cia->cia_err & 0xfff) - 1) {
 	case 0: /* CIA_ERR_COR_ERR */
 		cia_decode_ecc_error(cia, "Corrected ECC error");
 		break;
@@ -1135,6 +1195,7 @@
 	if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT)
 		printk(KERN_CRIT "CIA lost machine check: "
 		       "I/O timeout\n");
+#endif
 
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_irongate.c linux-2.4.21-rc3/arch/alpha/kernel/core_irongate.c
--- linux-2.4.20/arch/alpha/kernel/core_irongate.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_irongate.c	2003-05-22 22:06:27.000000000 +0000
@@ -25,13 +25,11 @@
 #include <asm/core_irongate.h>
 #undef __EXTERN_INLINE
 
+#include <linux/bootmem.h>
+
 #include "proto.h"
 #include "pci_impl.h"
 
-#undef DEBUG_IRONGATE 		/* define to enable verbose Irongate debug */
-
-#define IRONGATE_DEFAULT_AGP_APER_SIZE	(256*1024*1024) /* 256MB */
-
 /*
  * BIOS32-style PCI interface:
  */
@@ -44,6 +42,7 @@
 # define DBG_CFG(args)
 #endif
 
+igcsr32 *IronECC;
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -197,143 +196,6 @@
 	write_dword:	irongate_write_config_dword
 };
 
-#ifdef DEBUG_IRONGATE
-static void
-irongate_register_dump(const char *function_name)
-{
-	printk("%s: Irongate registers:\n"
-	       "\tFunction 0:\n"
-	       "\tdev_vendor\t0x%08x\n"
-	       "\tstat_cmd\t0x%08x\n"
-	       "\tclass\t\t0x%08x\n"
-	       "\tlatency\t\t0x%08x\n"
-	       "\tbar0\t\t0x%08x\n"
-	       "\tbar1\t\t0x%08x\n"
-	       "\tbar2\t\t0x%08x\n"
-	       "\trsrvd0[0]\t0x%08x\n"
-	       "\trsrvd0[1]\t0x%08x\n"
-	       "\trsrvd0[2]\t0x%08x\n"
-	       "\trsrvd0[3]\t0x%08x\n"
-	       "\trsrvd0[4]\t0x%08x\n"
-	       "\trsrvd0[5]\t0x%08x\n"
-	       "\tcapptr\t\t0x%08x\n"
-	       "\trsrvd1[0]\t0x%08x\n"
-	       "\trsrvd1[1]\t0x%08x\n"
-	       "\tbacsr10\t\t0x%08x\n"
-	       "\tbacsr32\t\t0x%08x\n"
-	       "\tbacsr54\t\t0x%08x\n"
-	       "\trsrvd2[0]\t0x%08x\n"
-	       "\tdrammap\t\t0x%08x\n"
-	       "\tdramtm\t\t0x%08x\n"
-	       "\tdramms\t\t0x%08x\n"
-	       "\trsrvd3[0]\t0x%08x\n"
-	       "\tbiu0\t\t0x%08x\n"
-	       "\tbiusip\t\t0x%08x\n"
-	       "\trsrvd4[0]\t0x%08x\n"
-	       "\trsrvd4[1]\t0x%08x\n"
-	       "\tmro\t\t0x%08x\n"
-	       "\trsrvd5[0]\t0x%08x\n"
-	       "\trsrvd5[1]\t0x%08x\n"
-	       "\trsrvd5[2]\t0x%08x\n"
-	       "\twhami\t\t0x%08x\n"
-	       "\tpciarb\t\t0x%08x\n"
-	       "\tpcicfg\t\t0x%08x\n"
-	       "\trsrvd6[0]\t0x%08x\n"
-	       "\trsrvd6[1]\t0x%08x\n"
-	       "\trsrvd6[2]\t0x%08x\n"
-	       "\trsrvd6[3]\t0x%08x\n"
-	       "\trsrvd6[4]\t0x%08x\n"
-	       "\tagpcap\t\t0x%08x\n"
-	       "\tagpstat\t\t0x%08x\n"
-	       "\tagpcmd\t\t0x%08x\n"
-	       "\tagpva\t\t0x%08x\n"
-	       "\tagpmode\t\t0x%08x\n"
-
-	       "\n\tFunction 1:\n"
-	       "\tdev_vendor:\t0x%08x\n"
-	       "\tcmd_status:\t0x%08x\n"
-	       "\trevid_etc :\t0x%08x\n"
-	       "\thtype_etc :\t0x%08x\n"
-	       "\trsrvd0[0] :\t0x%08x\n"
-	       "\trsrvd0[1] :\t0x%08x\n"
-	       "\tbus_nmbers:\t0x%08x\n"
-	       "\tio_baselim:\t0x%08x\n"
-	       "\tmem_bselim:\t0x%08x\n"
-	       "\tpf_baselib:\t0x%08x\n"
-	       "\trsrvd1[0] :\t0x%08x\n"
-	       "\trsrvd1[1] :\t0x%08x\n"
-	       "\tio_baselim:\t0x%08x\n"
-	       "\trsrvd2[0] :\t0x%08x\n"
-	       "\trsrvd2[1] :\t0x%08x\n"
-	       "\tinterrupt :\t0x%08x\n",
-
-	       function_name,
-	       IRONGATE0->dev_vendor,
-	       IRONGATE0->stat_cmd,
-	       IRONGATE0->class,
-	       IRONGATE0->latency,
-	       IRONGATE0->bar0,
-	       IRONGATE0->bar1,
-	       IRONGATE0->bar2,
-	       IRONGATE0->rsrvd0[0],
-	       IRONGATE0->rsrvd0[1],
-	       IRONGATE0->rsrvd0[2],
-	       IRONGATE0->rsrvd0[3],
-	       IRONGATE0->rsrvd0[4],
-	       IRONGATE0->rsrvd0[5],
-	       IRONGATE0->capptr,
-	       IRONGATE0->rsrvd1[0],
-	       IRONGATE0->rsrvd1[1],
-	       IRONGATE0->bacsr10,
-	       IRONGATE0->bacsr32,
-	       IRONGATE0->bacsr54,
-	       IRONGATE0->rsrvd2[0],
-	       IRONGATE0->drammap,
-	       IRONGATE0->dramtm,
-	       IRONGATE0->dramms,
-	       IRONGATE0->rsrvd3[0],
-	       IRONGATE0->biu0,
-	       IRONGATE0->biusip,
-	       IRONGATE0->rsrvd4[0],
-	       IRONGATE0->rsrvd4[1],
-	       IRONGATE0->mro,
-	       IRONGATE0->rsrvd5[0],
-	       IRONGATE0->rsrvd5[1],
-	       IRONGATE0->rsrvd5[2],
-	       IRONGATE0->whami,
-	       IRONGATE0->pciarb,
-	       IRONGATE0->pcicfg,
-	       IRONGATE0->rsrvd6[0],
-	       IRONGATE0->rsrvd6[1],
-	       IRONGATE0->rsrvd6[2],
-	       IRONGATE0->rsrvd6[3],
-	       IRONGATE0->rsrvd6[4],
-	       IRONGATE0->agpcap,
-	       IRONGATE0->agpstat,
-	       IRONGATE0->agpcmd,
-	       IRONGATE0->agpva,
-	       IRONGATE0->agpmode,
-	       IRONGATE1->dev_vendor,
-	       IRONGATE1->stat_cmd,
-	       IRONGATE1->class,
-	       IRONGATE1->htype,
-	       IRONGATE1->rsrvd0[0],
-	       IRONGATE1->rsrvd0[1],
-	       IRONGATE1->busnos,
-	       IRONGATE1->io_baselim_regs,
-	       IRONGATE1->mem_baselim,
-	       IRONGATE1->pfmem_baselim,
-	       IRONGATE1->rsrvd1[0],
-	       IRONGATE1->rsrvd1[1],
-	       IRONGATE1->io_baselim,
-	       IRONGATE1->rsrvd2[0],
-	       IRONGATE1->rsrvd2[1],
-	       IRONGATE1->interrupt );
-}
-#else
-#define irongate_register_dump(x)
-#endif
-
 int
 irongate_pci_clr_err(void)
 {
@@ -347,11 +209,11 @@
 	mb();
 	IRONGATE_jd = IRONGATE0->stat_cmd;  /* re-read to force write */
 
-	IRONGATE_jd = IRONGATE0->dramms;
-	printk("Iron dramms %x\n", IRONGATE_jd);
-	IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */
+	IRONGATE_jd = *IronECC;
+	printk("Iron ECC %x\n", IRONGATE_jd);
+	*IronECC = IRONGATE_jd; /* write again clears error bits */
 	mb();
-	IRONGATE_jd = IRONGATE0->dramms;  /* re-read to force write */
+	IRONGATE_jd = *IronECC;  /* re-read to force write */
 
 	/* Clear ALI NMI */
         nmi_ctl = inb(0x61);
@@ -360,28 +222,88 @@
         nmi_ctl &= ~0x0c;
         outb(nmi_ctl, 0x61);
 
-	IRONGATE_jd = IRONGATE0->dramms;
+	IRONGATE_jd = *IronECC;
 	if (IRONGATE_jd & 0x300) goto again;
 
 	return 0;
 }
 
+#define IRONGATE_3GB 0xc0000000UL
+
+/* On Albacore (aka UP1500) with 4Gb of RAM we have to reserve some
+   memory for PCI. At this point we just reserve memory above 3Gb. Most
+   of this memory will be freed after PCI setup is done. */
+static void __init
+albacore_init_arch(void)
+{
+	unsigned long memtop = max_low_pfn << PAGE_SHIFT;
+	unsigned long pci_mem = (memtop + 0x1000000UL) & ~0xffffffUL;
+	struct percpu_struct *cpu;
+	int pal_rev, pal_var;
+
+	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
+	pal_rev = cpu->pal_revision & 0xffff;
+	pal_var = (cpu->pal_revision >> 16) & 0xff;
+
+	/* Consoles earlier than A5.6-18 (OSF PALcode v1.62-2) set up
+	   the CPU incorrectly (leave speculative stores enabled),
+	   which causes memory corruption under certain conditions.
+	   Issue a warning for such consoles. */
+	if (alpha_using_srm &&
+	    (pal_rev < 0x13e ||	(pal_rev == 0x13e && pal_var < 2)))
+		printk(KERN_WARNING "WARNING! Upgrade to SRM A5.6-19 "
+				    "or later\n");
+
+	if (pci_mem > IRONGATE_3GB)
+		pci_mem = IRONGATE_3GB;
+	IRONGATE0->pci_mem = pci_mem;
+	alpha_mv.min_mem_address = pci_mem;
+	if (memtop > pci_mem) {
+#ifdef CONFIG_BLK_DEV_INITRD
+		extern unsigned long initrd_start, initrd_end;
+		extern void *move_initrd(unsigned long);
+
+		/* Move the initrd out of the way. */
+		if (initrd_end && __pa(initrd_end) > pci_mem) {
+			unsigned long size;
+
+			size = initrd_end - initrd_start;
+			free_bootmem(__pa(initrd_start), PAGE_ALIGN(size));
+			if (!move_initrd(pci_mem))
+				printk("irongate_init_arch: initrd too big "
+				       "(%ldK)\ndisabling initrd\n",
+				       size / 1024);
+		}
+#endif
+		reserve_bootmem(pci_mem, memtop - pci_mem);
+		printk("irongate_init_arch: temporarily reserving "
+			"region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
+	}
+}
+
+static void __init
+irongate_setup_agp(void)
+{
+	/* Disable the GART window. AGPGART doesn't work due to yet
+	   unresolved memory coherency issues... */
+	IRONGATE0->agpva = IRONGATE0->agpva & ~0xf;
+	alpha_agpgart_size = 0;
+}
+
 void __init
 irongate_init_arch(void)
 {
 	struct pci_controller *hose;
+	int amd761 = (IRONGATE0->dev_vendor >> 16) > 0x7006;	/* Albacore? */
+
+	IronECC = amd761 ? &IRONGATE0->bacsr54_eccms761 : &IRONGATE0->dramms;
 
-	IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
 	irongate_pci_clr_err();
-	irongate_register_dump(__FUNCTION__);
 
-	/*
-	 * HACK: set AGP aperture size to 256MB.
-	 * This should really be changed during PCI probe, when the
-	 * size of the aperture the AGP card wants is known.
-	 */
-	printk("irongate_init_arch: AGPVA was 0x%x\n", IRONGATE0->agpva);
-	IRONGATE0->agpva = (IRONGATE0->agpva & ~0x0000000f) | 0x00000007;
+	if (amd761)
+		albacore_init_arch();
+
+	irongate_setup_agp();
 
 	/*
 	 * Create our single hose.
@@ -412,88 +334,9 @@
  * IO map and AGP support
  */
 #include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-
-static inline void 
-irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
-		     unsigned long phys_addr, unsigned long flags)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	if (address >= end)
-		BUG();
-	do {
-		if (!pte_none(*pte)) {
-			printk("irongate_remap_area_pte: page already exists\n");
-			BUG();
-		}
-		set_pte(pte, 
-			mk_pte_phys(phys_addr, 
-				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
-					     _PAGE_KRE | _PAGE_KWE | flags)));
-		address += PAGE_SIZE;
-		phys_addr += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
-}
-
-static inline int 
-irongate_remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
-		     unsigned long phys_addr, unsigned long flags)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	phys_addr -= address;
-	if (address >= end)
-		BUG();
-	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		irongate_remap_area_pte(pte, address, end - address, 
-				     address + phys_addr, flags);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
-	return 0;
-}
-
-static int
-irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
-		       unsigned long size, unsigned long flags)
-{
-	pgd_t * dir;
-	unsigned long end = address + size;
-
-	phys_addr -= address;
-	dir = pgd_offset(&init_mm, address);
-	flush_cache_all();
-	if (address >= end)
-		BUG();
-	do {
-		pmd_t *pmd;
-		pmd = pmd_alloc(&init_mm, dir, address);
-		if (!pmd)
-			return -ENOMEM;
-		if (irongate_remap_area_pmd(pmd, address, end - address,
-					 phys_addr + address, flags))
-			return -ENOMEM;
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	return 0;
-}
-
 #include <linux/agp_backend.h>
 #include <linux/agpgart.h>
+#include <asm/pgalloc.h>
 
 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
@@ -508,15 +351,13 @@
 	unsigned long vaddr;
 	unsigned long baddr, last;
 	u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
-	unsigned long gart_bus_addr, gart_aper_size;
+	unsigned long gart_bus_addr;
 
-	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
-			PCI_BASE_ADDRESS_MEM_MASK; 
-
-	if (!gart_bus_addr) /* FIXME - there must be a better way!!! */
+	if (!alpha_agpgart_size)
 		return addr + IRONGATE_MEM;
 
-	gart_aper_size = IRONGATE_DEFAULT_AGP_APER_SIZE; /* FIXME */
+	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
+			PCI_BASE_ADDRESS_MEM_MASK; 
 
 	/* 
 	 * Check for within the AGP aperture...
@@ -526,7 +367,7 @@
 		 * Check the AGP area
 		 */
 		if (addr >= gart_bus_addr && addr + size - 1 < 
-		    gart_bus_addr + gart_aper_size)
+		    gart_bus_addr + alpha_agpgart_size)
 			break;
 
 		/*
@@ -580,8 +421,8 @@
 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
 
-		if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr), 
-					   pte, PAGE_SIZE, 0)) {
+		if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+					     pte, PAGE_SIZE, 0)) {
 			printk("AGP ioremap: FAILED to map...\n");
 			vfree(area->addr);
 			return (unsigned long)NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_marvel.c linux-2.4.21-rc3/arch/alpha/kernel/core_marvel.c
--- linux-2.4.20/arch/alpha/kernel/core_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_marvel.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,1125 @@
+/*
+ *	linux/arch/alpha/kernel/core_marvel.c
+ *
+ * Code common to all Marvel based systems.
+ */
+
+#include <linux/config.h>
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_marvel.h>
+#undef __EXTERN_INLINE
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+#include <asm/pgalloc.h>
+
+#include <linux/bootmem.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+
+/*
+ * Debug helpers
+ */
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Private data
+ */
+static struct io7 *io7_head = NULL;
+
+
+/*
+ * Helper functions
+ */
+static unsigned long __attribute__ ((unused))
+read_ev7_csr(int pe, unsigned long offset)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+	unsigned long q;
+
+	mb();
+	q = ev7csr->csr;
+	mb();
+
+	return q;
+}
+
+static void __attribute__ ((unused))
+write_ev7_csr(int pe, unsigned long offset, unsigned long q)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+
+	mb();
+	ev7csr->csr = q;
+	mb();
+}
+
+static char * __init
+mk_resource_name(int pe, int port, char *str)
+{
+	char tmp[80];
+	char *name;
+	
+	sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
+	name = alloc_bootmem(strlen(tmp) + 1);
+	strcpy(name, tmp);
+
+	return name;
+}
+
+inline struct io7 *
+marvel_next_io7(struct io7 *prev)
+{
+	return (prev ? prev->next : io7_head);
+}
+
+struct io7 *
+marvel_find_io7(int pe)
+{
+	struct io7 *io7;
+
+	for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next)
+		continue;
+
+	return io7;
+}
+
+static struct io7 * __init
+alloc_io7(unsigned int pe)
+{
+	struct io7 *io7;
+	struct io7 *insp;
+	int h;
+
+	if (marvel_find_io7(pe)) {
+		printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe);
+		return NULL;
+	}
+
+	io7 = alloc_bootmem(sizeof(*io7));
+	io7->pe = pe;
+	io7->irq_lock = SPIN_LOCK_UNLOCKED;
+
+	for (h = 0; h < 4; h++) {
+		io7->ports[h].io7 = io7;
+		io7->ports[h].port = h;
+		io7->ports[h].enabled = 0; /* default to disabled */
+	}
+
+	/*
+	 * Insert in pe sorted order.
+	 */
+	if (NULL == io7_head)			/* empty list */
+		io7_head = io7;	
+	else if (io7_head->pe > io7->pe) {	/* insert at head */
+		io7->next = io7_head;
+		io7_head = io7;
+	} else {				/* insert at position */
+		for (insp = io7_head; insp; insp = insp->next) {
+			if (insp->pe == io7->pe) {
+				printk(KERN_ERR "Too many IO7s at PE %d\n", 
+				       io7->pe);
+				return NULL;
+			}
+
+			if (NULL == insp->next || 
+			    insp->next->pe > io7->pe) { /* insert here */
+				io7->next = insp->next;
+				insp->next = io7;
+				break;
+			}
+		}
+
+		if (NULL == insp) { /* couldn't insert ?!? */
+			printk(KERN_WARNING "Failed to insert IO7 at PE %d "
+			       " - adding at head of list\n", io7->pe);
+			io7->next = io7_head;
+			io7_head = io7;
+		}
+	}
+	
+	return io7;
+}
+
+void
+io7_clear_errors(struct io7 *io7)
+{
+	io7_port7_csrs *p7csrs;
+	io7_ioport_csrs *csrs;
+	int port;
+
+
+	/*
+	 * First the IO ports.
+	 */
+	for (port = 0; port < 4; port++) {
+		csrs = IO7_CSRS_KERN(io7->pe, port);
+
+		csrs->POx_ERR_SUM.csr = -1UL;
+		csrs->POx_TLB_ERR.csr = -1UL;
+		csrs->POx_SPL_COMPLT.csr = -1UL;
+		csrs->POx_TRANS_SUM.csr = -1UL;
+	}
+
+	/*
+	 * Then the common ones.
+	 */
+	p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	p7csrs->PO7_ERROR_SUM.csr = -1UL;
+	p7csrs->PO7_UNCRR_SYM.csr = -1UL;
+	p7csrs->PO7_CRRCT_SYM.csr = -1UL;
+}
+
+
+/*
+ * IO7 PCI, PCI/X, AGP configuration.
+ */
+static void __init
+io7_init_hose(struct io7 *io7, int port)
+{
+	static int hose_index = 0;
+
+	struct pci_controller *hose = alloc_pci_controller();
+	struct io7_port *io7_port = &io7->ports[port];
+	io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port);
+	int i;
+
+	hose->index = hose_index++;	/* arbitrary */
+	
+	/*
+	 * We don't have an isa or legacy hose, but glibc expects to be
+	 * able to use the bus == 0 / dev == 0 form of the iobase syscall
+	 * to determine information about the i/o system. Since XFree86 
+	 * relies on glibc's determination to tell whether or not to use
+	 * sparse access, we need to point the pci_isa_hose at a real hose
+	 * so at least that determination is correct.
+	 */
+	if (hose->index == 0)
+		pci_isa_hose = hose;
+
+	io7_port->csrs = csrs;
+	io7_port->hose = hose;
+	hose->sysdata = io7_port;
+
+	hose->io_space = alloc_resource();
+	hose->mem_space = alloc_resource();
+
+	/*
+	 * Base addresses for userland consumption. Since these are going
+	 * to be mapped, they are pure physical addresses.
+	 */
+	hose->sparse_mem_base = hose->sparse_io_base = 0;
+	hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port);
+	hose->dense_io_base = IO7_IO_PHYS(io7->pe, port);
+
+	/*
+	 * Base addresses and resource ranges for kernel consumption.
+	 */
+	hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port);
+
+	hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port);
+	hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1;
+	hose->io_space->name = mk_resource_name(io7->pe, port, "IO");
+	hose->io_space->flags = IORESOURCE_IO;
+
+	hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port);
+	hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1;
+	hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM");
+	hose->mem_space->flags = IORESOURCE_MEM;
+
+	if (request_resource(&ioport_resource, hose->io_space) < 0)
+		printk(KERN_ERR "Failed to request IO on hose %d\n", 
+		       hose->index);
+	if (request_resource(&iomem_resource, hose->mem_space) < 0)
+		printk(KERN_ERR "Failed to request MEM on hose %d\n", 
+		       hose->index);
+
+	/*
+	 * Save the existing DMA window settings for later restoration.
+	 */
+	for (i = 0; i < 4; i++) {
+		io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr;
+		io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr;
+		io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr;
+	}
+
+	/*
+	 * Set up the PCI to main memory translation windows.
+	 *
+	 * Window 0 is scatter-gather 8MB at 8MB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather (up-to) 1GB at 3GB
+	 * Window 3 is disabled
+	 */
+
+	/*
+	 * TBIA before modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+
+	/*
+	 * Set up window 0 for scatter-gather 8MB at 8MB.
+	 */
+	hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0x00800000, 0x00800000, 0);
+	hose->sg_isa->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[0].csr = 
+		hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+	/*
+	 * Set up window 1 for direct-mapped 1GB at 2GB.
+	 */
+	csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena;
+	csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[1].csr = 0;
+
+	/*
+	 * Set up window 2 for scatter-gather (up-to) 1GB at 3GB.
+	 */
+	hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0xc0000000, 0x40000000, 0);
+	hose->sg_pci->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[2].csr = 
+		hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes);
+
+	/*
+	 * Disable window 3.
+	 */
+	csrs->POx_WBASE[3].csr = 0;
+
+	/*
+	 * Make sure that the AGP Monster Window is disabled.
+	 */
+	csrs->POx_CTRL.csr &= ~(1UL << 61);
+
+#if 1
+	printk("FIXME: disabling master aborts\n");
+	csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
+#endif
+	/*
+	 * TBIA after modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+}
+
+static void __init
+marvel_init_io7(struct io7 *io7)
+{
+	int i;
+
+	printk("Initializing IO7 at PID %d\n", io7->pe);
+
+	/*
+	 * Get the Port 7 CSR pointer.
+	 */
+	io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	/*
+	 * Init this IO7's hoses.
+	 */
+	for (i = 0; i < IO7_NUM_PORTS; i++) {
+		io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
+		if (csrs->POx_CACHE_CTL.csr == 8) {
+			io7->ports[i].enabled = 1;
+			io7_init_hose(io7, i);
+		}
+	}
+}
+
+void
+marvel_io7_present(gct6_node *node)
+{
+	int pe;
+
+	if (node->type != GCT_TYPE_HOSE ||
+	    node->subtype != GCT_SUBTYPE_IO_PORT_MODULE) 
+		return;
+
+	pe = (node->id >> 8) & 0xff;
+	printk("Found an IO7 at PID %d\n", pe);
+
+	alloc_io7(pe);
+}
+
+static void __init
+marvel_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose = NULL;
+		int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
+		struct io7 *io7;
+		int pid, port;
+
+		/* FIXME - encoding is going to have to change for Marvel
+		 *         since hose will be able to overflow a byte...
+		 *         need to fix this decode when the console 
+		 *         changes its encoding
+		 */
+		printk("console graphics is on hose %d (console)\n", h);
+
+		/*
+		 * The console's hose numbering is:
+		 *
+		 *	hose<n:2>: PID
+		 *	hose<1:0>: PORT
+		 *
+		 * We need to find the hose at that pid and port
+		 */
+		pid = h >> 2;
+		port = h & 3;
+		if ((io7 = marvel_find_io7(pid)))
+			hose = io7->ports[port].hose;
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
+gct6_search_struct gct_wanted_node_list[] = {
+	{ GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
+	{ 0, 0, NULL }
+};
+
+/*
+ * In case the GCT is not complete, let the user specify PIDs with IO7s
+ * at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
+ * where IO7s are connected
+ */
+static int __init
+marvel_specify_io7(char *str)
+{
+	unsigned long pid;
+	struct io7 *io7;
+	char *pchar;
+
+	do {
+		pid = simple_strtoul(str, &pchar, 0);
+		if (pchar != str) {
+			printk("User-specified IO7 at PID %lu\n", pid);
+			io7 = alloc_io7(pid);
+			if (io7) marvel_init_io7(io7);
+		}
+
+		if (pchar == str) pchar++;
+		str = pchar;
+	} while(*str);
+
+	return 0;
+}
+__setup("io7=", marvel_specify_io7);
+
+void __init
+marvel_init_arch(void)
+{
+	struct io7 *io7;
+
+	/* With multiple PCI busses, we play with I/O as physical addrs.  */
+	ioport_resource.end = ~0UL;
+	iomem_resource.end = ~0UL;
+
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Parse the config tree.  */
+	gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
+
+	/* Init the io7s.  */
+	for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); ) 
+		marvel_init_io7(io7);
+
+	/* Check for graphic console location (if any).  */
+	marvel_init_vga_hose();
+}
+
+void
+marvel_kill_arch(int mode)
+{
+}
+
+
+/*
+ * PCI Configuration Space access functions
+ *
+ * Configuration space addresses have the following format:
+ *
+ * 	|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ * 	|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 	|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	 n:24	reserved for hose base
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ * Notes:
+ *	IO7 determines whether to use a type 0 or type 1 config cycle
+ *	based on the bus number. Therefore the bus number must be set 
+ *	to 0 for the root bus on any hose.
+ *	
+ *	The function number selects which function of a multi-function device 
+ *	(e.g., SCSI and Ethernet).
+ * 
+ */
+
+static inline unsigned long
+build_conf_addr(struct pci_controller *hose, u8 bus, 
+		unsigned int devfn, int where)
+{
+	return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
+}
+
+static unsigned long
+mk_conf_addr(struct pci_dev *dev, int where)
+{
+	struct pci_controller *hose = dev->sysdata;
+	unsigned long addr = 0;
+	struct io7_port *io7_port;
+	u8 bus;
+
+	if (!hose)
+		return addr;
+	
+	/* Check for enabled.  */
+	io7_port = hose->sysdata;
+	if (!io7_port->enabled)
+		return addr;
+
+	bus = dev->bus->number;
+
+	if (hose->first_busno == bus) {
+		/* Don't support idsel > 20 on primary bus.  */
+		if (dev->devfn >= PCI_DEVFN(21, 0))
+			return addr;
+		bus = 0;
+	}
+
+	addr = build_conf_addr(hose, bus, dev->devfn, where);
+
+	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return addr;
+}
+
+static int
+marvel_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = *(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stb(value, *(vucp)addr);
+	mb();
+	__kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stw(value, *(vusp)addr);
+	mb();
+	__kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*(vuip)addr = value;
+	mb();
+	*(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops marvel_pci_ops =
+{
+	read_byte:	marvel_read_config_byte,
+	read_word:	marvel_read_config_word,
+	read_dword:	marvel_read_config_dword,
+	write_byte:	marvel_write_config_byte,
+	write_word:	marvel_write_config_word,
+	write_dword:	marvel_write_config_dword
+};
+
+
+/*
+ * Other PCI helper functions.
+ */
+void
+marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	wmb();
+	csrs->POx_SG_TBIA.csr = 0;
+	mb();
+	csrs->POx_SG_TBIA.csr;
+}
+
+
+/*
+ * IO map support.
+ */
+unsigned long
+marvel_ioremap(unsigned long addr, unsigned long size)
+{
+	struct pci_controller *hose;
+	unsigned long baddr, last;
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	if (!marvel_is_ioaddr(addr))
+		return 0UL;
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next) {
+		if ((addr >> 32) == (hose->mem_space->start >> 32))
+			break;
+	}
+	if (!hose)
+		return 0UL;
+
+	/*
+	 * We have the hose - calculate the bus limits.
+	 */
+	baddr = addr - hose->mem_space->start;
+	last = baddr + size - 1;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return IDENT_ADDR | (baddr - __direct_map_base);
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it.
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr;
+}
+
+void
+marvel_iounmap(unsigned long addr)
+{
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		return vfree((void *)(PAGE_MASK & addr)); 
+}
+
+
+/*
+ * RTC Support
+ */
+struct marvel_rtc_access_info {
+	unsigned long function;
+	unsigned long index;
+	unsigned long data;
+};
+
+static void
+__marvel_access_rtc(void *info)
+{
+	struct marvel_rtc_access_info *rtc_access = info;
+
+	register unsigned long __r0 __asm__("$0");
+	register unsigned long __r16 __asm__("$16") = rtc_access->function;
+	register unsigned long __r17 __asm__("$17") = rtc_access->index;
+	register unsigned long __r18 __asm__("$18") = rtc_access->data;
+	
+	__asm__ __volatile__(
+		"call_pal %4 # cserve rtc"
+		: "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
+		: "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
+		: "$1", "$22", "$23", "$24", "$25");
+
+	rtc_access->data = __r0;
+}
+
+u8
+__marvel_rtc_io(int write, u8 b, unsigned long addr)
+{
+	struct marvel_rtc_access_info rtc_access = {0, };
+	static u8 index = 0;
+	u8 ret = 0;
+
+	switch(addr) {
+	case 0x70:					/* RTC_PORT(0) */
+		if (write) index = b;
+		ret = index;
+		break;
+
+	case 0x71:					/* RTC_PORT(1) */
+		rtc_access.index = index;
+		rtc_access.data = BCD_TO_BIN(b);
+		rtc_access.function = 0x49;		/* GET_TOY */
+		if (write) rtc_access.function = 0x48;	/* PUT_TOY */
+
+#if CONFIG_SMP
+		if (smp_processor_id() != boot_cpuid)
+			smp_call_function_on_cpu(__marvel_access_rtc,
+						 &rtc_access,
+						 1,	/* retry */
+						 1,	/* wait  */
+						 1UL << boot_cpuid);
+		else
+			__marvel_access_rtc(&rtc_access);
+#else
+		__marvel_access_rtc(&rtc_access);
+#endif
+		ret = BIN_TO_BCD(rtc_access.data);
+		
+		break;
+
+	default:
+		printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
+		break;
+	}
+
+	return ret;
+}
+
+
+/*
+ * NUMA Support
+ */
+/**********
+ * FIXME - for now each cpu is a node by itself 
+ *              -- no real support for striped mode 
+ **********
+ */
+int
+marvel_pa_to_nid(unsigned long pa)
+{
+	int cpuid;
+
+	if ((pa >> 43) & 1) 	/* I/O */ 
+		cpuid = (~(pa >> 35) & 0xff);
+	else			/* mem */
+		cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
+
+	return marvel_cpuid_to_nid(cpuid);
+}
+
+int
+marvel_cpuid_to_nid(int cpuid)
+{
+	return cpuid;
+}
+
+unsigned long
+marvel_node_mem_start(int nid)
+{
+	unsigned long pa;
+
+	pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
+	pa <<= 34;
+
+	return pa;
+}
+
+unsigned long
+marvel_node_mem_size(int nid)
+{
+	return 16UL * 1024 * 1024 * 1024; /* 16GB */
+}
+
+
+/* 
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct marvel_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+marvel_agp_setup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(*aper), GFP_KERNEL);
+	if (aper == NULL) return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
+}
+
+static void
+marvel_agp_cleanup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
+
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
+}
+
+static int
+marvel_agp_configure(alpha_agp_info *agp)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
+	struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
+	unsigned int new_rate = 0;
+	unsigned long agp_pll;
+
+	/*
+	 * Check the requested mode against the PLL setting.
+	 * The agpgart_be code has not programmed the card yet,
+	 * so we can still tweak mode here.
+	 */
+	agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
+	switch(IO7_PLL_RNGB(agp_pll)) {
+	case 0x4:				/* 2x only */
+		/* 
+		 * The PLL is only programmed for 2x, so adjust the
+		 * rate to 2x, if necessary.
+		 */
+		if (agp->mode.bits.rate != 2) 
+			new_rate = 2;
+		break;
+
+	case 0x6:				/* 1x / 4x */
+		/*
+		 * The PLL is programmed for 1x or 4x.  Don't go faster
+		 * than requested, so if the requested rate is 2x, use 1x.
+		 */
+		if (agp->mode.bits.rate == 2) 
+			new_rate = 1;
+		break;
+
+	default:				/* ??????? */
+		/*
+		 * Don't know what this PLL setting is, take the requested
+		 * rate, but warn the user.
+		 */
+		printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
+		       __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
+		break;
+	}
+
+	/*
+	 * Set the new rate, if necessary.
+	 */
+	if (new_rate) {
+		printk("Requested AGP Rate %dX not compatible "
+		       "with PLL setting - using %dX\n",
+		       agp->mode.bits.rate,
+		       new_rate);
+
+		agp->mode.bits.rate = new_rate;
+	}
+		
+	printk("Enabling AGP on hose %d: %dX%s RQ %d\n", 
+	       agp->hose->index, agp->mode.bits.rate, 
+	       agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
+
+	csrs->AGP_CMD.csr = agp->mode.lw;
+
+	return 0;
+}
+
+static int 
+marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	} 
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops marvel_agp_ops =
+{
+	setup:		marvel_agp_setup,
+	cleanup:	marvel_agp_cleanup,
+	configure:	marvel_agp_configure,
+	bind:		marvel_agp_bind_memory,
+	unbind:		marvel_agp_unbind_memory,
+	translate:	marvel_agp_translate
+};
+
+alpha_agp_info *
+marvel_agp_info(void)
+{
+	struct pci_controller *hose;
+	io7_ioport_csrs *csrs;
+	alpha_agp_info *agp;
+	struct io7 *io7;
+
+	/*
+	 * Find the first IO7 with an AGP card.
+	 *
+	 * FIXME -- there should be a better way (we want to be able to
+	 * specify and what if the agp card is not video???)
+	 */
+	hose = NULL;
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
+		struct pci_controller *h;
+		vuip addr;
+
+		if (!io7->ports[IO7_AGP_PORT].enabled)
+			continue;
+
+		h = io7->ports[IO7_AGP_PORT].hose;
+		addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
+
+		if (*addr != 0xffffffffu) {
+			hose = h;
+			break;
+		}
+	}
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	printk("MARVEL - using hose %d as AGP\n", hose->index);
+
+	/* 
+	 * Get the csrs from the hose.
+	 */
+	csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = NULL;
+	agp->ops = &marvel_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 *
+	 * NOTE: IO7 reports through AGP_STAT that it can support a read queue
+	 *       depth of 17 (rq = 0x10). It actually only supports a depth of
+	 * 	 16 (rq = 0xf).
+	 */
+	agp->capability.lw = csrs->AGP_STAT.csr;
+	agp->capability.bits.rq = 0xf;
+	
+	/*
+	 * Mode.
+	 */
+	agp->mode.lw = csrs->AGP_CMD.csr;
+
+	return agp;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_t2.c linux-2.4.21-rc3/arch/alpha/kernel/core_t2.c
--- linux-2.4.20/arch/alpha/kernel/core_t2.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_t2.c	2003-05-22 22:06:25.000000000 +0000
@@ -26,6 +26,18 @@
 #include "proto.h"
 #include "pci_impl.h"
 
+/*
+ * By default, we direct-map starting at 2GB, in order to allow the
+ * maximum size direct-map window (2GB) to match the maximum amount of
+ * memory (2GB) that can be present on SABLEs. But that limits the
+ * floppy to DMA only via the scatter/gather window set up for 8MB
+ * ISA DMA, since the maximum ISA DMA address is 2GB-1.
+ *
+ * For now, this seems a reasonable trade-off: even though most SABLEs
+ * have far less than even 1GB of memory, floppy usage/performance will
+ * not really be affected by forcing it to go via scatter/gather...
+ */
+#define T2_DIRECTMAP_2G 1
 
 /*
  * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
@@ -325,6 +337,7 @@
 t2_init_arch(void)
 {
 	struct pci_controller *hose;
+	unsigned long t2_iocsr;
 	unsigned int i;
 
 	for (i = 0; i < NR_CPUS; i++) {
@@ -333,43 +346,80 @@
 	}
 
 #if 0
-	{
-	  /* Set up error reporting.  */
-	  unsigned long t2_err;
+	/* Set up error reporting.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 7); /* TLB error check */
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+#endif
 
-	  t2_err = *(vulp)T2_IOCSR;
-	  t2_err |= (0x1 << 7);   /* master abort */
-	  *(vulp)T2_IOCSR = t2_err;
-	  mb();
+	/* Enable scatter/gather TLB use.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	if (!(t2_iocsr & (0x1UL << 26))) {
+		printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
+		       t2_iocsr);
+		*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 26);
+		mb();	
+		*(vulp)T2_IOCSR; /* read it back to make sure */
 	}
-#endif
 
-	printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
 #if 0
-	printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
-	       *(vulp)T2_WBASE1,
-	       *(vulp)T2_WMASK1,
-	       *(vulp)T2_TBASE1);
-	printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
-	       *(vulp)T2_WBASE2,
-	       *(vulp)T2_WMASK2,
-	       *(vulp)T2_TBASE2);
+	printk("t2_init_arch: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
+	printk("t2_init_arch: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+	       *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
+	printk("t2_init_arch: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+	       *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
 #endif
 
 	/*
+	 * Create our single hose.
+	 */
+
+	pci_isa_hose = hose = alloc_pci_controller();
+	hose->io_space = &ioport_resource;
+	hose->mem_space = &iomem_resource;
+	hose->index = 0;
+
+	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
+	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
+	hose->sparse_io_base = T2_IO - IDENT_ADDR;
+	hose->dense_io_base = 0;
+
+	/* Note we can only do 1 SG window, as the other is for direct, so
+	   do an ISA SG area, especially for the floppy. */
+	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	hose->sg_pci = NULL;
+
+	/*
 	 * Set up the PCI->physical memory translation windows.
-	 * For now, window 2 is  disabled.  In the future, we may
-	 * want to use it to do scatter/gather DMA. 
 	 *
-	 * Window 1 goes at 1 GB and is 1 GB large.
+	 * Window 1 goes at ? GB and is ?GB large, direct mapped.
+	 * Window 2 goes at 8 MB and is 8MB large, scatter/gather (for ISA).
 	 */
 
-	/* WARNING!! must correspond to the DMA_WIN params!!! */
+#if T2_DIRECTMAP_2G
+	__direct_map_base = 0x80000000UL;
+	__direct_map_size = 0x80000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
+	*(vulp)T2_WBASE1 = 0x80080fffU;
+	*(vulp)T2_WMASK1 = 0x7ff00000U;
+	*(vulp)T2_TBASE1 = 0;
+#else /* T2_DIRECTMAP_2G */
+	__direct_map_base = 0x40000000UL;
+	__direct_map_size = 0x40000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
 	*(vulp)T2_WBASE1 = 0x400807ffU;
 	*(vulp)T2_WMASK1 = 0x3ff00000U;
 	*(vulp)T2_TBASE1 = 0;
+#endif /* T2_DIRECTMAP_2G */
+
+	/* WARNING!! must correspond to the SG arena/window params!!! */
+	*(vulp)T2_WBASE2 = 0x008c000fU;
+	*(vulp)T2_WMASK2 = 0x00700000U;
+	*(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
 
-	*(vulp)T2_WBASE2 = 0x0;
 	*(vulp)T2_HBASE = 0x0;
 
 	/* Zero HAE.  */
@@ -377,26 +427,28 @@
 	*(vulp)T2_HAE_2 = 0; mb();
 	*(vulp)T2_HAE_3 = 0; mb();
 #if 0
-	*(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */
+	*(vulp)T2_HAE_4 = 0; mb(); /* DO NOT TOUCH THIS!!! */
 #endif
 
-	/*
-	 * Create our single hose.
-	 */
+	t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+}
 
-	pci_isa_hose = hose = alloc_pci_controller();
-	hose->io_space = &ioport_resource;
-	hose->mem_space = &iomem_resource;
-	hose->index = 0;
+void
+t2_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	unsigned long t2_iocsr;
 
-	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
-	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
-	hose->sparse_io_base = T2_IO - IDENT_ADDR;
-	hose->dense_io_base = 0;
+	t2_iocsr = *(vulp)T2_IOCSR;
 
-	hose->sg_isa = hose->sg_pci = NULL;
-	__direct_map_base = 0x40000000;
-	__direct_map_size = 0x40000000;
+	/* set the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+
+	/* clear the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr & ~(0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
 }
 
 #define SIC_SEIC (1UL << 33)    /* System Event Clear */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_titan.c linux-2.4.21-rc3/arch/alpha/kernel/core_titan.c
--- linux-2.4.20/arch/alpha/kernel/core_titan.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_titan.c	2003-05-22 22:06:39.000000000 +0000
@@ -10,10 +10,13 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/vmalloc.h>
 
+#include <asm/hwrpb.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/smp.h>
+#include <asm/pgalloc.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
@@ -25,14 +28,14 @@
 #include "proto.h"
 #include "pci_impl.h"
 
-unsigned TITAN_agp = 0;
+/* Save Titan configuration data as the console had it set up.  */
 
-static struct
+struct
 {
 	unsigned long wsba[4];
 	unsigned long wsm[4];
 	unsigned long tba[4];
-} saved_pachip_port[4];
+} saved_config[4] __attribute__((common));
 
 /*
  * BIOS32-style PCI interface:
@@ -47,6 +50,31 @@
 # define DBG_CFG(args)
 #endif
 
+
+/*
+ * Routines to access TIG registers.
+ */
+static inline volatile unsigned long *
+mk_tig_addr(int offset)
+{
+	return (volatile unsigned long *)(TITAN_TIG_SPACE + (offset << 6));
+}
+
+static inline u8 
+titan_read_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	return (u8)(*tig_addr & 0xff);
+}
+
+static inline void 
+titan_write_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	*tig_addr = (unsigned long)value;
+}
+
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address
@@ -94,7 +122,7 @@
 		 "pci_addr=0x%p, type1=0x%p)\n",
 		 bus, device_fn, where, pci_addr, type1));
 
-        if (hose->first_busno == dev->bus->number)
+        if (hose->first_busno == bus)
 		bus = 0;
         *type1 = (bus != 0);
 
@@ -210,13 +238,16 @@
 	volatile unsigned long *csr;
 	unsigned long value;
 
-	/* Get the right hose */
+	/* Get the right hose.  */
 	port = &pachip->g_port;
 	if (hose->index & 2) 
 		port = &pachip->a_port;
 
 	/* We can invalidate up to 8 tlb entries in a go.  The flush
-	   matches against <31:16> in the pci address.  */
+	   matches against <31:16> in the pci address.  
+	   Note that gtlbi* and atlbi* are in the same place in the g_port
+	   and a_port, respectively, so the g_port offset can be used
+	   even if hose is an a_port */
 	csr = &port->port_specific.g.gtlbia.csr;
 	if (((start ^ end) & 0xffff0000) == 0)
 		csr = &port->port_specific.g.gtlbiv.csr;
@@ -231,9 +262,7 @@
 	*csr;
 }
 
-#define FN __FUNCTION__
-
-static int __init
+static int
 titan_query_agp(titan_pachip_port *port)
 {
 	union TPAchipPCTL pctl;
@@ -244,42 +273,11 @@
 	return pctl.pctl_r_bits.apctl_v_agp_present;
 
 }
-static void __init
-titan_init_agp(titan_pachip_port *port, struct pci_controller *hose)
-{
-	union TPAchipPCTL pctl;
-
-	if (!titan_query_agp(port))
-		return;
-
-	printk("AGP present on hose %d\n", hose->index);
-
-	/* get APCTL */
-	pctl.pctl_q_whole = port->pctl.csr;
-
-
-	pctl.pctl_r_bits.apctl_v_agp_en = 1;	/* enable AGP */
-	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 0;	
-	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 0;	
-
-	port->pctl.csr = pctl.pctl_q_whole;
-
-	TITAN_agp |= 1 << hose->index;
-
-#ifdef CONFIG_VGA_HOSE	
-	/* is a graphics card on the AGP? (always device 5) */
-	if (hose != NULL &&
-	    __kernel_ldwu(*(vusp)(hose->config_space_base + 0x280a)) == 
-	    PCI_CLASS_DISPLAY_VGA)
-		set_vga_hose(hose);
-#endif
-}
 
 static void __init
 titan_init_one_pachip_port(titan_pachip_port *port, int index)
 {
 	struct pci_controller *hose;
-	unsigned long sg_size;
 
 	hose = alloc_pci_controller();
 	if (index == 0)
@@ -287,10 +285,13 @@
 	hose->io_space = alloc_resource();
 	hose->mem_space = alloc_resource();
 
-	/* This is for userland consumption.  For some reason, the 40-bit
-	   PIO bias that we use in the kernel through KSEG didn't work for
-	   the page table based user mappings.  So make sure we get the
-	   43-bit PIO bias.  */
+	/*
+	 * This is for userland consumption.  The 40-bit PIO bias that we 
+	 * use in the kernel through KSEG doesn't work in the page table 
+	 * based user mappings. (43-bit KSEG sign extends the physical
+	 * address from bit 40 to hit the I/O bit - mapped addresses don't).
+	 * So make sure we get the 43-bit PIO bias.  
+	 */
 	hose->sparse_mem_base = 0;
 	hose->sparse_io_base = 0;
 	hose->dense_mem_base
@@ -316,65 +317,64 @@
 	if (request_resource(&iomem_resource, hose->mem_space) < 0)
 		printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
 
-	/* It's safe to call this for both G-Ports and A-Ports */
-	titan_init_agp(port, hose);
-
 	/*
 	 * Save the existing PCI window translations.  SRM will 
 	 * need them when we go to reboot.
 	 */
-	saved_pachip_port[index].wsba[0] = port->wsba[0].csr;
-	saved_pachip_port[index].wsm[0]  = port->wsm[0].csr;
-	saved_pachip_port[index].tba[0]  = port->tba[0].csr;
-
-	saved_pachip_port[index].wsba[1] = port->wsba[1].csr;
-	saved_pachip_port[index].wsm[1]  = port->wsm[1].csr;
-	saved_pachip_port[index].tba[1]  = port->tba[1].csr;
-
-	saved_pachip_port[index].wsba[2] = port->wsba[2].csr;
-	saved_pachip_port[index].wsm[2]  = port->wsm[2].csr;
-	saved_pachip_port[index].tba[2]  = port->tba[2].csr;
-
-	saved_pachip_port[index].wsba[3] = port->wsba[3].csr;
-	saved_pachip_port[index].wsm[3]  = port->wsm[3].csr;
-	saved_pachip_port[index].tba[3]  = port->tba[3].csr;
+	saved_config[index].wsba[0] = port->wsba[0].csr;
+	saved_config[index].wsm[0]  = port->wsm[0].csr;
+	saved_config[index].tba[0]  = port->tba[0].csr;
+
+	saved_config[index].wsba[1] = port->wsba[1].csr;
+	saved_config[index].wsm[1]  = port->wsm[1].csr;
+	saved_config[index].tba[1]  = port->tba[1].csr;
+
+	saved_config[index].wsba[2] = port->wsba[2].csr;
+	saved_config[index].wsm[2]  = port->wsm[2].csr;
+	saved_config[index].tba[2]  = port->tba[2].csr;
+
+	saved_config[index].wsba[3] = port->wsba[3].csr;
+	saved_config[index].wsm[3]  = port->wsm[3].csr;
+	saved_config[index].tba[3]  = port->tba[3].csr;
 
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Note: Window 3 on Titan is Scatter-Gather ONLY
+	 * Note: Window 3 on Titan is Scatter-Gather ONLY.
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather (up to) 1GB at 1GB
-	 * Window 2 is direct access 2GB at 2GB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather 1GB at 3GB
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
 	hose->sg_isa->align_entry = 8; /* 64KB for ISA */
 
-	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
-				       size_for_memory(0x40000000), 0);
+	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x40000000, 0);
 	hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */
 
-	__direct_map_base = 0x80000000;
-	__direct_map_size = 0x80000000;
-
 	port->wsba[0].csr = hose->sg_isa->dma_base | 3;
 	port->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
 	port->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);
 
-	port->wsba[1].csr = hose->sg_pci->dma_base | 3;
-	port->wsm[1].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
-	port->tba[1].csr  = virt_to_phys(hose->sg_pci->ptes);
-
-	port->wsba[2].csr = 0x80000000 | 1;
-	port->wsm[2].csr  = (0x80000000 - 1) & 0xfff00000;
-	port->tba[2].csr  = 0;
+	port->wsba[1].csr = __direct_map_base | 1;
+	port->wsm[1].csr  = (__direct_map_size - 1) & 0xfff00000;
+	port->tba[1].csr  = 0;
+
+	port->wsba[2].csr = hose->sg_pci->dma_base | 3;
+	port->wsm[2].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
+	port->tba[2].csr  = virt_to_phys(hose->sg_pci->ptes);
 
 	port->wsba[3].csr = 0;
 
-	/* Enable the Monster Window to make DAC pci64 possible. */
+	/* Enable the Monster Window to make DAC pci64 possible.  */
 	port->pctl.csr |= pctl_m_mwin;
 
+	/*
+	 * If it's an AGP port, initialize agplastwr.
+	 */
+	if (titan_query_agp(port)) 
+		port->port_specific.a.agplastwr.csr = __direct_map_base;
+
 	titan_pci_tbi(hose, 0, -1);
 }
 
@@ -392,25 +392,51 @@
 		titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
 }
 
+static void __init
+titan_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose;
+		int h = (pu64[30] >> 24) & 0xff;	/* console hose # */
+
+		/*
+		 * Our hose numbering matches the console's, so just find
+		 * the right one...
+		 */
+		for (hose = hose_head; hose; hose = hose->next) {
+			if (hose->index == h) break;
+		}
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
 void __init
 titan_init_arch(void)
 {
 #if 0
-	printk("%s: titan_init_arch()\n", FN);
-	printk("%s: CChip registers:\n", FN);
-	printk("%s: CSR_CSC 0x%lx\n", FN, TITAN_cchip->csc.csr);
-	printk("%s: CSR_MTR 0x%lx\n", FN, TITAN_cchip->mtr.csr);
-	printk("%s: CSR_MISC 0x%lx\n", FN, TITAN_cchip->misc.csr);
-	printk("%s: CSR_DIM0 0x%lx\n", FN, TITAN_cchip->dim0.csr);
-	printk("%s: CSR_DIM1 0x%lx\n", FN, TITAN_cchip->dim1.csr);
-	printk("%s: CSR_DIR0 0x%lx\n", FN, TITAN_cchip->dir0.csr);
-	printk("%s: CSR_DIR1 0x%lx\n", FN, TITAN_cchip->dir1.csr);
-	printk("%s: CSR_DRIR 0x%lx\n", FN, TITAN_cchip->drir.csr);
-
-	printk("%s: DChip registers:\n", FN);
-	printk("%s: CSR_DSC 0x%lx\n", FN, TITAN_dchip->dsc.csr);
-	printk("%s: CSR_STR 0x%lx\n", FN, TITAN_dchip->str.csr);
-	printk("%s: CSR_DREV 0x%lx\n", FN, TITAN_dchip->drev.csr);
+	printk("%s: titan_init_arch()\n", __FUNCTION__);
+	printk("%s: CChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
+	printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
+	printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
+	printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
+	printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
+	printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
+	printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
+	printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);
+
+	printk("%s: DChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
+	printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
+	printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
 #endif
 
 	boot_cpuid = __hard_smp_processor_id();
@@ -419,28 +445,35 @@
 	ioport_resource.end = ~0UL;
 	iomem_resource.end = ~0UL;
 
-	/* Init the PA chip(s) */
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Init the PA chip(s).  */
 	titan_init_pachips(TITAN_pachip0, TITAN_pachip1);
+
+	/* Check for graphic console location (if any).  */
+	titan_init_vga_hose();
 }
 
 static void
 titan_kill_one_pachip_port(titan_pachip_port *port, int index)
 {
-	port->wsba[0].csr = saved_pachip_port[index].wsba[0];
-	port->wsm[0].csr  = saved_pachip_port[index].wsm[0];
-	port->tba[0].csr  = saved_pachip_port[index].tba[0];
-
-	port->wsba[1].csr = saved_pachip_port[index].wsba[1];
-	port->wsm[1].csr  = saved_pachip_port[index].wsm[1];
-	port->tba[1].csr  = saved_pachip_port[index].tba[1];
-
-	port->wsba[2].csr = saved_pachip_port[index].wsba[2];
-	port->wsm[2].csr  = saved_pachip_port[index].wsm[2];
-	port->tba[2].csr  = saved_pachip_port[index].tba[2];
-
-	port->wsba[3].csr = saved_pachip_port[index].wsba[3];
-	port->wsm[3].csr  = saved_pachip_port[index].wsm[3];
-	port->tba[3].csr  = saved_pachip_port[index].tba[3];
+	port->wsba[0].csr = saved_config[index].wsba[0];
+	port->wsm[0].csr  = saved_config[index].wsm[0];
+	port->tba[0].csr  = saved_config[index].tba[0];
+
+	port->wsba[1].csr = saved_config[index].wsba[1];
+	port->wsm[1].csr  = saved_config[index].wsm[1];
+	port->tba[1].csr  = saved_config[index].tba[1];
+
+	port->wsba[2].csr = saved_config[index].wsba[2];
+	port->wsm[2].csr  = saved_config[index].wsm[2];
+	port->tba[2].csr  = saved_config[index].tba[2];
+
+	port->wsba[3].csr = saved_config[index].wsba[3];
+	port->wsm[3].csr  = saved_config[index].wsm[3];
+	port->tba[3].csr  = saved_config[index].tba[3];
 }
 
 static void
@@ -449,8 +482,8 @@
 	int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
 
 	if (pchip1_present) {
-		titan_kill_one_pachip_port(&pachip0->g_port, 1);
-		titan_kill_one_pachip_port(&pachip0->a_port, 3);
+		titan_kill_one_pachip_port(&pachip1->g_port, 1);
+		titan_kill_one_pachip_port(&pachip1->a_port, 3);
 	}
 	titan_kill_one_pachip_port(&pachip0->g_port, 0);
 	titan_kill_one_pachip_port(&pachip0->a_port, 2);
@@ -462,38 +495,333 @@
 	titan_kill_pachips(TITAN_pachip0, TITAN_pachip1);
 }
 
-static inline void
-titan_pci_clr_err_1(titan_pachip *pachip)
+
+/*
+ * IO map support.
+ */
+unsigned long
+titan_ioremap(unsigned long addr, unsigned long size)
 {
-	unsigned int jd;
+	int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT;
+	unsigned long baddr = addr & ~TITAN_HOSE_MASK;
+	unsigned long last = baddr + size - 1;
+	struct pci_controller *hose;	
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __titan_is_mem_vga(addr)) {
+		h = pci_vga_hose->index;
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == h) break;
+	if (!hose) return (unsigned long)NULL;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return addr - __direct_map_base + TITAN_MEM_BIAS;
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr + TITAN_MEM_BIAS;
 
-	jd = pachip->g_port.port_specific.g.gperror.csr;
-	pachip->g_port.port_specific.g.gperror.csr = jd;
-	mb();
-	pachip->g_port.port_specific.g.gperror.csr;
 }
 
-static inline void
-titan_pci_clr_err(void)
+void
+titan_iounmap(unsigned long addr)
 {
-	titan_pci_clr_err_1(TITAN_pachip0);
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		vfree((void *)(PAGE_MASK & addr)); 
+}
 
-	if (TITAN_cchip->csc.csr & 1L<<14)
-	    titan_pci_clr_err_1(TITAN_pachip1);
+
+/*
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct titan_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+titan_agp_setup(alpha_agp_info *agp)
+{
+	struct titan_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
+	if (aper == NULL)
+		return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
 }
 
-void
-titan_machine_check(unsigned long vector, unsigned long la_ptr,
-		      struct pt_regs * regs)
+static void
+titan_agp_cleanup(alpha_agp_info *agp)
 {
-	/* clear error before any reporting. */
-	mb();
-	draina();
-	titan_pci_clr_err();
-	wrmces(0x7);
-	mb();
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
 
-	process_mcheck_info(vector, la_ptr, regs, "TITAN",
-			    mcheck_expected(smp_processor_id()));
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING 
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
 }
 
+static int
+titan_agp_configure(alpha_agp_info *agp)
+{
+	union TPAchipPCTL pctl;
+	titan_pachip_port *port = agp->private;
+	pctl.pctl_q_whole = port->pctl.csr;
+
+	/* Side-Band Addressing? */
+	pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;
+
+	/* AGP Rate? */
+	pctl.pctl_r_bits.apctl_v_agp_rate = 0;		/* 1x */
+	if (agp->mode.bits.rate & 2) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 1;	/* 2x */
+#if 0
+	if (agp->mode.bits.rate & 4) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 2;	/* 4x */
+#endif
+	
+	/* RQ Depth? */
+	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
+	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;
+
+	/*
+	 * AGP Enable.
+	 */
+	pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;
+
+	/* Tell the user.  */
+	printk("Enabling AGP: %dX%s\n", 
+	       1 << pctl.pctl_r_bits.apctl_v_agp_rate,
+	       pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
+	       
+	/* Write it.  */
+	port->pctl.csr = pctl.pctl_q_whole;
+	
+	/* And wait at least 5000 66MHz cycles (per Titan spec).  */
+	udelay(100);
+
+	return 0;
+}
+
+static int 
+titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops titan_agp_ops =
+{
+	setup:		titan_agp_setup,
+	cleanup:	titan_agp_cleanup,
+	configure:	titan_agp_configure,
+	bind:		titan_agp_bind_memory,
+	unbind:		titan_agp_unbind_memory,
+	translate:	titan_agp_translate
+};
+
+alpha_agp_info *
+titan_agp_info(void)
+{
+	alpha_agp_info *agp;
+	struct pci_controller *hose;
+	titan_pachip_port *port;
+	int hosenum = -1;
+	union TPAchipPCTL pctl;
+
+	/*
+	 * Find the AGP port.
+	 */
+	port = &TITAN_pachip0->a_port;
+	if (titan_query_agp(port))
+		hosenum = 2;
+	if (hosenum < 0 && 
+	    titan_query_agp(port = &TITAN_pachip1->a_port)) 
+		hosenum = 3;
+	
+	/*
+	 * Find the hose the port is on.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == hosenum)
+			break;
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = port;
+	agp->ops = &titan_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 *
+	 * FIXME - should we go ahead and allocate it here?
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 */
+	agp->capability.lw = 0;
+	agp->capability.bits.rate = 3; 	/* 2x, 1x */
+	agp->capability.bits.sba = 1;
+	agp->capability.bits.rq = 7;	/* 8 - 1 */
+
+	/*
+	 * Mode.
+	 */
+	pctl.pctl_q_whole = port->pctl.csr;
+	agp->mode.lw = 0;
+	agp->mode.bits.rate = 1 << pctl.pctl_r_bits.apctl_v_agp_rate;
+	agp->mode.bits.sba = pctl.pctl_r_bits.apctl_v_agp_sba_en;
+	agp->mode.bits.rq = 7;	/* RQ Depth? */
+	agp->mode.bits.enable = pctl.pctl_r_bits.apctl_v_agp_en;
+
+	return agp;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_tsunami.c linux-2.4.21-rc3/arch/alpha/kernel/core_tsunami.c
--- linux-2.4.20/arch/alpha/kernel/core_tsunami.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_tsunami.c	2003-05-22 22:06:41.000000000 +0000
@@ -350,10 +350,17 @@
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
 	 * Window 1 is scatter-gather (up to) 1GB at 1GB
 	 * Window 2 is direct access 2GB at 2GB
+	 *
+	 * NOTE: we need the align_entry settings for Acer devices on ES40,
+	 * specifically floppy and IDE when memory is larger than 2GB.
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	/* Initially set for 4 PTEs, but will be overridden to 64K for ISA. */
+	hose->sg_isa->align_entry = 4;
+
 	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
 				       size_for_memory(0x40000000), 0);
+	hose->sg_pci->align_entry = 4; /* Tsunami caches 4 PTEs at a time */
 
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_wildfire.c linux-2.4.21-rc3/arch/alpha/kernel/core_wildfire.c
--- linux-2.4.20/arch/alpha/kernel/core_wildfire.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/core_wildfire.c	2003-05-22 22:06:24.000000000 +0000
@@ -475,6 +475,33 @@
 	write_dword:	wildfire_write_config_dword
 };
 
+
+/*
+ * NUMA Support
+ */
+int wildfire_pa_to_nid(unsigned long pa)
+{
+	return pa >> 36;
+}
+
+int wildfire_cpuid_to_nid(int cpuid)
+{
+	/* assume 4 CPUs per node */
+	return cpuid >> 2;
+}
+
+unsigned long wildfire_node_mem_start(int nid)
+{
+	/* 64GB per node */
+	return (unsigned long)nid * (64UL * 1024 * 1024 * 1024);
+}
+
+unsigned long wildfire_node_mem_size(int nid)
+{
+	/* 64GB per node */
+	return 64UL * 1024 * 1024 * 1024;
+}
+
 #if DEBUG_DUMP_REGS
 
 static void __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/entry.S linux-2.4.21-rc3/arch/alpha/kernel/entry.S
--- linux-2.4.20/arch/alpha/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/entry.S	2003-05-22 22:06:24.000000000 +0000
@@ -231,12 +231,12 @@
 .end	kernel_clone
 
 /*
- * kernel_thread(fn, arg, clone_flags)
+ * arch_kernel_thread(fn, arg, clone_flags)
  */
 .align 3
-.globl	kernel_thread
-.ent	kernel_thread
-kernel_thread:
+.globl	arch_kernel_thread
+.ent	arch_kernel_thread
+arch_kernel_thread:
 	ldgp	$29,0($27)	/* we can be called from a module */
 	.frame $30, 4*8, $26
 	subq	$30,4*8,$30
@@ -265,7 +265,7 @@
 	mov	$0,$16
 	mov	$31,$26
 	jsr	$31,sys_exit
-.end	kernel_thread
+.end	arch_kernel_thread
 
 /*
  * __kernel_execve(path, argv, envp, regs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_common.c linux-2.4.21-rc3/arch/alpha/kernel/err_common.c
--- linux-2.4.20/arch/alpha/kernel/err_common.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/err_common.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,772 @@
+/*
+ *	linux/arch/alpha/kernel/err_common.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+/*
+ * err_print_prefix -- error handling print routines should prefix
+ * all prints with this
+ */
+char *err_print_prefix = KERN_NOTICE;
+
+/*
+ * Forward references
+ */
+static void el_print_timestamp(union el_timestamp);
+static void el_process_subpackets(struct el_subpacket *, int);
+
+
+/*
+ * Generic
+ */
+void
+mchk_dump_mem(void *data, size_t length, char **annotation)
+{
+	unsigned long *ldata = data;
+	size_t i;
+	
+	for (i = 0; (i * sizeof(*ldata)) < length; i++) {
+		if (annotation && !annotation[i]) 
+			annotation = NULL;
+		printk("%s    %08x: %016lx    %s\n",
+		       err_print_prefix,
+		       (unsigned)(i * sizeof(*ldata)), ldata[i],
+		       annotation ? annotation[i] : "");
+	}
+}
+
+void
+mchk_dump_logout_frame(struct el_common *mchk_header)
+{
+	printk("%s  -- Frame Header --\n"
+	         "    Frame Size:   %d (0x%x) bytes\n"
+	         "    Flags:        %s%s\n"
+	         "    MCHK Code:    0x%x\n"
+	         "    Frame Rev:    %d\n"
+	         "    Proc Offset:  0x%08x\n"
+	         "    Sys Offset:   0x%08x\n"
+  	         "  -- Processor Region --\n",
+	       err_print_prefix, 
+	       mchk_header->size, mchk_header->size,
+	       mchk_header->retry ? "RETRY " : "", 
+  	         mchk_header->err2 ? "SECOND_ERR " : "",
+	       mchk_header->code,
+	       mchk_header->frame_rev,
+	       mchk_header->proc_offset,
+	       mchk_header->sys_offset);
+
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->proc_offset),
+		      mchk_header->sys_offset - mchk_header->proc_offset,
+		      NULL);
+	
+	printk("%s  -- System Region --\n", err_print_prefix);
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->sys_offset),
+		      mchk_header->size - mchk_header->sys_offset,
+		      NULL);
+	printk("%s  -- End of Frame --\n", err_print_prefix);
+}
+
+
+/*
+ * EV7 generic
+ */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV7)
+
+void
+ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	printk("%sEV7 MACHINE CHECK vector %lx\n", err_print_prefix, vector);
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+struct ev7_pal_subpacket {
+	union {
+		struct {
+			u32 mchk_code;
+			u32 subpacket_count;
+			u64 whami;
+			u64 rbox_whami;
+			u64 rbox_int;
+			u64 exc_addr;
+			union el_timestamp timestamp;
+			u64 halt_code;
+			u64 reserved;
+		} logout;
+	} by_type;
+};
+
+static char *el_ev7_processor_subpacket_annotation[] = {
+	"Subpacket Header",	"I_STAT",	"DC_STAT",
+	"C_ADDR",		"C_SYNDROME_1",	"C_SYNDROME_0",
+	"C_STAT",		"C_STS",	"MM_STAT",
+	"EXC_ADDR",		"IER_CM",	"ISUM",
+	"PAL_BASE",		"I_CTL",	"PROCESS_CONTEXT",
+	"CBOX_CTL",		"CBOX_STP_CTL",	"CBOX_ACC_CTL",
+	"CBOX_LCL_SET",		"CBOX_GLB_SET",	"BBOX_CTL",
+	"BBOX_ERR_STS",		"BBOX_ERR_IDX",	"CBOX_DDP_ERR_STS",
+	"BBOX_DAT_RMP",		NULL
+};
+
+static char *el_ev7_zbox_subpacket_annotation[] = {
+	"Subpacket Header", 	
+	"ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(0): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(0): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(0): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(0): reserved          / DIFT_ERR_STATUS",
+	"ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(1): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(1): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(1): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(1): reserved          / DIFT_ERR_STATUS",
+	"CBOX_CTL",		"CBOX_STP_CTL",
+	"ZBOX(0)_ERROR_PA",	"ZBOX(1)_ERROR_PA",
+	"ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME",
+	NULL
+};
+
+static char *el_ev7_rbox_subpacket_annotation[] = {
+	"Subpacket Header",	"RBOX_CFG",	"RBOX_N_CFG",
+	"RBOX_S_CFG",		"RBOX_E_CFG",	"RBOX_W_CFG",
+	"RBOX_N_ERR",		"RBOX_S_ERR",	"RBOX_E_ERR",
+	"RBOX_W_ERR",		"RBOX_IO_CFG",	"RBOX_IO_ERR",
+	"RBOX_L_ERR",		"RBOX_WHOAMI",	"RBOX_IMASL",
+	"RBOX_INTQ",		"RBOX_INT",	NULL
+};
+
+static char *el_ev7_io_subpacket_annotation[] = {
+	"Subpacket Header",	"IO_ASIC_REV",	"IO_SYS_REV",
+	"IO7_UPH",		"HPI_CTL",	"CRD_CTL",
+	"HEI_CTL",		"PO7_ERROR_SUM","PO7_UNCRR_SYM",
+	"PO7_CRRCT_SYM",	"PO7_UGBGE_SYM","PO7_ERR_PKT0",
+	"PO7_ERR_PKT1",		"reserved",	"reserved",
+	"PO0_ERR_SUM",		"PO0_TLB_ERR",	"PO0_SPL_COMPLT",
+	"PO0_TRANS_SUM",	"PO0_FIRST_ERR","PO0_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO1_ERR_SUM",		"PO1_TLB_ERR",	"PO1_SPL_COMPLT",
+	"PO1_TRANS_SUM",	"PO1_FIRST_ERR","PO1_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO2_ERR_SUM",		"PO2_TLB_ERR",	"PO2_SPL_COMPLT",
+	"PO2_TRANS_SUM",	"PO2_FIRST_ERR","PO2_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO3_ERR_SUM",		"PO3_TLB_ERR",	"PO3_SPL_COMPLT",
+	"PO3_TRANS_SUM",	"PO3_FIRST_ERR","PO3_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",	
+	NULL
+};
+	
+static struct el_subpacket_annotation el_ev7_pal_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_PROCESSOR,
+			     1,
+			     "EV7 Processor Subpacket",
+			     el_ev7_processor_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_ZBOX,
+			     1,
+			     "EV7 ZBOX Subpacket",
+			     el_ev7_zbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_RBOX,
+			     1,
+			     "EV7 RBOX Subpacket",
+			     el_ev7_rbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_IO,
+			     1,
+			     "EV7 IO Subpacket",
+			     el_ev7_io_subpacket_annotation)
+};
+
+static struct el_subpacket *
+ev7_process_pal_subpacket(struct el_subpacket *header)
+{
+	struct ev7_pal_subpacket *packet;
+
+	if (header->class != EL_CLASS__PAL) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start;
+
+	switch(header->type) {
+	case EL_TYPE__PAL__LOGOUT_FRAME:
+		printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+		       err_print_prefix,
+		       packet->by_type.logout.whami, 
+		       packet->by_type.logout.rbox_whami);
+		el_print_timestamp(packet->by_type.logout.timestamp);
+		printk("%s  EXC_ADDR: %016lx\n"
+		         "  HALT_CODE: %lx\n", 
+		       err_print_prefix,
+		       packet->by_type.logout.exc_addr,
+		       packet->by_type.logout.halt_code);
+		el_process_subpackets(header,
+                                      packet->by_type.logout.subpacket_count);
+		break;
+	default:
+		printk("%s  ** PAL TYPE %d SUBPACKET\n", 
+		       err_print_prefix,
+		       header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+	
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+}
+
+struct el_subpacket_handler ev7_pal_subpacket_handler =
+	SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket);
+
+void 
+ev7_register_error_handlers(void)
+{
+	int i;
+
+	for(i = 0;
+	    i<sizeof(el_ev7_pal_annotations)/sizeof(el_ev7_pal_annotations[1]);
+	    i++) {
+		cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]);
+	}	
+	cdl_register_subpacket_handler(&ev7_pal_subpacket_handler);
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV7 */
+
+
+/*
+ * EV6 generic
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
+
+static int
+ev6_parse_ibox(u64 i_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__I_STAT__PAR	(1UL << 29)
+#define EV6__I_STAT__ERRMASK	(EV6__I_STAT__PAR)
+
+	if (!(i_stat & EV6__I_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (i_stat & EV6__I_STAT__PAR)
+		printk("%s    Icache parity error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_mbox(u64 mm_stat, u64 d_stat, u64 c_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__MM_STAT__DC_TAG_PERR	(1UL << 10)
+#define EV6__MM_STAT__ERRMASK		(EV6__MM_STAT__DC_TAG_PERR)
+#define EV6__D_STAT__TPERR_P0		(1UL << 0)
+#define EV6__D_STAT__TPERR_P1		(1UL << 1)
+#define EV6__D_STAT__ECC_ERR_ST		(1UL << 2)
+#define EV6__D_STAT__ECC_ERR_LD		(1UL << 3)
+#define EV6__D_STAT__SEO		(1UL << 4)
+#define EV6__D_STAT__ERRMASK		(EV6__D_STAT__TPERR_P0 |	\
+                                         EV6__D_STAT__TPERR_P1 | 	\
+                                         EV6__D_STAT__ECC_ERR_ST | 	\
+                                         EV6__D_STAT__ECC_ERR_LD | 	\
+                                         EV6__D_STAT__SEO)
+
+	if (!(d_stat & EV6__D_STAT__ERRMASK) && 
+	    !(mm_stat & EV6__MM_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (mm_stat & EV6__MM_STAT__DC_TAG_PERR)
+		printk("%s    Dcache tag parity error on probe\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P0)
+		printk("%s    Dcache tag parity error - pipe 0\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P1)
+		printk("%s    Dcache tag parity error - pipe 1\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_ST)
+		printk("%s    ECC error occurred on a store\n", 
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_LD)
+		printk("%s    ECC error occurred on a %s load\n",
+		       err_print_prefix,
+		       c_stat ? "" : "speculative ");
+	if (d_stat & EV6__D_STAT__SEO)
+		printk("%s    Dcache second error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn, 
+	       u64 c_stat, u64 c_sts, int print)
+{
+	char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
+			       "MEMORY", "BCACHE", "DCACHE", 
+			       "BCACHE PROBE", "BCACHE PROBE" };
+	char *streamname[] = { "D", "I" };
+	char *bitsname[] = { "SINGLE", "DOUBLE" };
+	int status = MCHK_DISPOSITION_REPORT;
+	int source = -1, stream = -1, bits = -1;
+
+#define EV6__C_STAT__BC_PERR		(0x01)
+#define EV6__C_STAT__DC_PERR		(0x02)
+#define EV6__C_STAT__DSTREAM_MEM_ERR	(0x03)
+#define EV6__C_STAT__DSTREAM_BC_ERR	(0x04)
+#define EV6__C_STAT__DSTREAM_DC_ERR	(0x05)
+#define EV6__C_STAT__PROBE_BC_ERR0	(0x06)	/* both 6 and 7 indicate... */
+#define EV6__C_STAT__PROBE_BC_ERR1	(0x07)	/* ...probe bc error.       */
+#define EV6__C_STAT__ISTREAM_MEM_ERR	(0x0B)
+#define EV6__C_STAT__ISTREAM_BC_ERR	(0x0C)
+#define EV6__C_STAT__DSTREAM_MEM_DBL	(0x13)
+#define EV6__C_STAT__DSTREAM_BC_DBL	(0x14)
+#define EV6__C_STAT__ISTREAM_MEM_DBL	(0x1B)
+#define EV6__C_STAT__ISTREAM_BC_DBL	(0x1C)
+#define EV6__C_STAT__SOURCE_MEMORY	(0x03)
+#define EV6__C_STAT__SOURCE_BCACHE	(0x04)
+#define EV6__C_STAT__SOURCE__S		(0)
+#define EV6__C_STAT__SOURCE__M 		(0x07)
+#define EV6__C_STAT__ISTREAM__S		(3)
+#define EV6__C_STAT__ISTREAM__M		(0x01)
+#define EV6__C_STAT__DOUBLE__S		(4)
+#define EV6__C_STAT__DOUBLE__M		(0x01)
+#define EV6__C_STAT__ERRMASK		(0x1F)
+#define EV6__C_STS__SHARED		(1 << 0)
+#define EV6__C_STS__DIRTY		(1 << 1)
+#define EV6__C_STS__VALID		(1 << 2)
+#define EV6__C_STS__PARITY		(1 << 3)
+
+	if (!(c_stat & EV6__C_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	source = EXTRACT(c_stat, EV6__C_STAT__SOURCE);
+	stream = EXTRACT(c_stat, EV6__C_STAT__ISTREAM);
+	bits = EXTRACT(c_stat, EV6__C_STAT__DOUBLE);
+
+	if (c_stat & EV6__C_STAT__BC_PERR) {
+		printk("%s    Bcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat & EV6__C_STAT__DC_PERR) {
+		printk("%s    Dcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat == EV6__C_STAT__PROBE_BC_ERR0 ||
+	    c_stat == EV6__C_STAT__PROBE_BC_ERR1) {
+		printk("%s    Bcache single-bit error on a probe hit\n",
+		       err_print_prefix);
+		source = -1;
+	}
+
+	if (source != -1) 
+		printk("%s    %s-STREAM %s-BIT ECC error from %s\n",
+		       err_print_prefix,
+		       streamname[stream], bitsname[bits], sourcename[source]);
+
+	printk("%s    Address: 0x%016lx\n"
+	         "    Syndrome[upper.lower]: %02lx.%02lx\n", 
+	       err_print_prefix,
+	       c_addr,
+	       c2_syn, c1_syn);
+
+	if (source == EV6__C_STAT__SOURCE_MEMORY ||
+	    source == EV6__C_STAT__SOURCE_BCACHE) 
+		printk("%s    Block status: %s%s%s%s\n",
+		       err_print_prefix,
+		       (c_sts & EV6__C_STS__SHARED) ? "SHARED " : "",
+		       (c_sts & EV6__C_STS__DIRTY)  ? "DIRTY "  : "",
+		       (c_sts & EV6__C_STS__VALID)  ? "VALID "  : "",
+		       (c_sts & EV6__C_STS__PARITY) ? "PARITY " : "");
+		
+	return status;
+}
+
+int
+ev6_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
+	status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT, 
+				 ev6mchk->C_STAT, print);
+	status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME,
+				 ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT,
+				 ev6mchk->C_STS, print);
+
+	if (!print)
+		return status;
+
+	if (status != MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+
+		/*
+		 * Dump some additional information from the frame
+		 */
+		printk("%s    EXC_ADDR: 0x%016lx   IER_CM: 0x%016lx"
+		            "   ISUM: 0x%016lx\n"
+		         "    PAL_BASE: 0x%016lx   I_CTL:  0x%016lx"
+		            "   PCTX: 0x%016lx\n",
+		       err_print_prefix,
+		       ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+		       ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+
+		if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
+			printk("%s    UNKNOWN error, frame follows:\n",
+			       err_print_prefix);
+		} else {
+			/* had decode -- downgrade print level for frame */
+			err_print_prefix = KERN_NOTICE;
+		}
+
+		mchk_dump_logout_frame(mchk_header);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	return status;
+}
+
+void
+ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	if (ev6_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+		ev6_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV6 */
+
+
+/*
+ * Console Data Log
+ */
+/* Data */
+static struct el_subpacket_handler *subpacket_handler_list = NULL;
+static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
+
+static void
+el_print_timestamp(union el_timestamp timestamp)
+{
+	if (timestamp.as_int)
+		printk("%s  TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n", 
+		       err_print_prefix,
+		       timestamp.b.month, timestamp.b.day,
+		       timestamp.b.year, timestamp.b.hour,
+		       timestamp.b.minute, timestamp.b.second);
+}
+
+static struct el_subpacket *
+el_process_header_subpacket(struct el_subpacket *header)
+{
+	union el_timestamp timestamp;
+	char *name = "UNKNOWN EVENT";
+	int packet_count = 0;
+	int length = 0;
+
+	if (header->class != EL_CLASS__HEADER) {
+		printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
+		name = "SYSTEM ERROR";
+		length = header->by_type.sys_err.frame_length;
+		packet_count = 
+			header->by_type.sys_err.frame_packet_count;
+		timestamp.as_int = 0;
+		break;
+	case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
+		name = "SYSTEM EVENT";
+		length = header->by_type.sys_event.frame_length;
+		packet_count = 
+			header->by_type.sys_event.frame_packet_count;
+		timestamp = header->by_type.sys_event.timestamp;
+		break;
+	case EL_TYPE__HEADER__HALT_FRAME:
+		name = "ERROR HALT";
+		length = header->by_type.err_halt.frame_length;
+		packet_count = 
+			header->by_type.err_halt.frame_packet_count;
+		timestamp = header->by_type.err_halt.timestamp;
+		break;
+	case EL_TYPE__HEADER__LOGOUT_FRAME:
+		name = "LOGOUT FRAME";
+		length = header->by_type.logout_header.frame_length;
+		packet_count = 1;
+		timestamp.as_int = 0;
+		break;
+	default: /* Unknown */
+		printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;		
+	}
+
+	printk("%s*** %s:\n"
+	         "  CLASS %d, TYPE %d\n", 
+	       err_print_prefix,
+	       name,
+	       header->class, header->type);
+	el_print_timestamp(timestamp);
+	
+	/*
+	 * Process the subpackets
+	 */
+	el_process_subpackets(header, packet_count);
+
+	/* return the next header */
+	header = (struct el_subpacket *)
+		((unsigned long)header + header->length + length);
+	return header;
+}
+
+static void
+el_process_subpackets(struct el_subpacket *header, int packet_count)
+{
+	struct el_subpacket *subpacket;
+	int i;
+
+	subpacket = (struct el_subpacket *)
+		((unsigned long)header + header->length);
+
+	for (i = 0; subpacket && i < packet_count; i++) {
+		printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
+		subpacket = el_process_subpacket(subpacket);
+	}
+}
+
+static struct el_subpacket *
+el_process_subpacket_reg(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	for (; h && h->class != header->class; h = h->next);
+	if (h) next = h->handler(header);
+
+	return next;
+}
+
+struct el_subpacket *
+el_process_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+
+	switch(header->class) {
+	case EL_CLASS__TERMINATION:
+		/* Termination packet, there are no more */
+		break;
+	case EL_CLASS__HEADER: 
+		next = el_process_header_subpacket(header);
+		break;
+	default:
+		if (NULL == (next = el_process_subpacket_reg(header))) {
+			printk("%s** Unexpected header CLASS %d TYPE %d"
+			       " -- aborting.\n",
+			       err_print_prefix,
+			       header->class, header->type);
+		}
+		break;
+	}
+
+	return next;
+}
+
+void 
+el_annotate_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket_annotation *a;
+	char **annotation = NULL;
+
+	for (a = subpacket_annotation_list; a; a = a->next) {
+		if (a->class == header->class &&
+		    a->type == header->type &&
+		    a->revision == header->revision) {
+			/*
+			 * We found the annotation
+			 */
+			annotation = a->annotation;
+			printk("%s  %s\n", err_print_prefix, a->description);
+			break;
+		}
+	}
+
+	mchk_dump_mem(header, header->length, annotation);
+}
+
+static void __init
+cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
+{
+	struct el_subpacket *header = (struct el_subpacket *)
+		(IDENT_ADDR | pcpu->console_data_log_pa);
+	int err;
+
+	printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
+	         "*** Error(s) were logged on a previous boot\n",
+	       err_print_prefix, cpu);
+	
+	for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
+		header = el_process_subpacket(header);
+
+	/* let the console know it's ok to clear the error(s) at restart */
+	pcpu->console_data_log_pa = 0;
+
+	printk("%s*** %d total error(s) logged\n"
+	         "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n", 
+	       err_print_prefix, err, cpu);
+}
+
+void __init
+cdl_check_console_data_log(void)
+{
+	struct percpu_struct *pcpu;
+	unsigned long cpu;
+
+	for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
+		pcpu = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset 
+			 + cpu * hwrpb->processor_size);
+		if (pcpu->console_data_log_pa)
+			cdl_process_console_data_log(cpu, pcpu);
+	}
+
+}
+
+int __init
+cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
+{
+	struct el_subpacket_annotation *a = subpacket_annotation_list;
+
+	if (a == NULL) subpacket_annotation_list = new;
+	else {
+		for (; a->next != NULL; a = a->next) {
+			if ((a->class == new->class && a->type == new->type) ||
+			    a == new) {
+				printk("Attempted to re-register "
+				       "subpacket annotation\n");
+				return -EINVAL;
+			}
+		}
+		a->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
+int __init
+cdl_register_subpacket_handler(struct el_subpacket_handler *new)
+{
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	if (h == NULL) subpacket_handler_list = new;
+	else {
+		for (; h->next != NULL; h = h->next) {
+			if (h->class == new->class || h == new) {
+				printk("Attempted to re-register "
+				       "subpacket handler\n");
+				return -EINVAL;
+			}
+		}
+		h->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_impl.h linux-2.4.21-rc3/arch/alpha/kernel/err_impl.h
--- linux-2.4.20/arch/alpha/kernel/err_impl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/err_impl.h	2003-05-22 22:06:43.000000000 +0000
@@ -0,0 +1,162 @@
+/*
+ *	linux/arch/alpha/kernel/err_impl.h
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Contains declarations and macros to support Alpha error handling
+ * 	implementations.
+ */
+
+/*
+ * SCB Vector definitions
+ */
+#define SCB_Q_SYSERR	0x620
+#define SCB_Q_PROCERR	0x630
+#define SCB_Q_SYSMCHK	0x660
+#define SCB_Q_PROCMCHK	0x670
+#define SCB_Q_SYSEVENT	0x680
+
+/*
+ * Disposition definitions for logout frame parser
+ */
+#define MCHK_DISPOSITION_UNKNOWN_ERROR		0x00
+#define MCHK_DISPOSITION_REPORT			0x01
+#define MCHK_DISPOSITION_DISMISS		0x02
+
+/*
+ * Error Log definitions
+ */
+/*
+ * Types
+ */
+
+#define EL_CLASS__TERMINATION		(0)
+#  define EL_TYPE__TERMINATION__TERMINATION		(0)
+#define EL_CLASS__HEADER		(5)
+#  define EL_TYPE__HEADER__SYSTEM_ERROR_FRAME		(1)
+#  define EL_TYPE__HEADER__SYSTEM_EVENT_FRAME		(2)
+#  define EL_TYPE__HEADER__HALT_FRAME			(3)
+#  define EL_TYPE__HEADER__LOGOUT_FRAME			(19)
+#define EL_CLASS__GENERAL_NOTIFICATION	(9)
+#define EL_CLASS__PCI_ERROR_FRAME	(11)
+#define EL_CLASS__REGATTA_FAMILY	(12)
+#  define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME	(1)
+#  define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME		(2)
+#  define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME		(3)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED	(8)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED	(9)
+#  define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED	(10)
+#  define EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT	(11)
+#  define EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT	(12)
+#define EL_CLASS__PAL                   (14)
+#  define EL_TYPE__PAL__LOGOUT_FRAME                    (1)
+#  define EL_TYPE__PAL__EV7_PROCESSOR			(4)
+#  define EL_TYPE__PAL__EV7_ZBOX			(5)
+#  define EL_TYPE__PAL__EV7_RBOX			(6)
+#  define EL_TYPE__PAL__EV7_IO				(7)
+
+union el_timestamp {
+	struct {
+		u8 second;
+		u8 minute;
+		u8 hour;
+		u8 day;
+		u8 month;
+		u8 year;
+	} b;
+	u64 as_int;
+};
+
+struct el_subpacket {
+	u16 length;		/* length of header (in bytes)	*/
+	u16 class;		/* header class and type...   	*/
+	u16 type;		/* ...determine content     	*/
+	u16 revision;		/* header revision 		*/
+	union {
+		struct {	/* Class 5, Type 1 - System Error	*/
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_err;			
+		struct {	/* Class 5, Type 2 - System Event 	*/
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_event;
+		struct {	/* Class 5, Type 3 - Double Error Halt	*/
+			u16 halt_code;
+			u16 reserved;
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;
+		} err_halt;
+		struct {	/* Clasee 5, Type 19 - Logout Frame Header */
+			u32 frame_length;
+			u32 frame_flags;
+			u32 cpu_offset;	
+			u32 system_offset;
+		} logout_header;
+		struct {	/* Class 12 - Regatta			*/
+			u64 cpuid;
+			u64 data_start[1];
+		} regatta_frame;
+		struct {	/* Raw 				        */
+			u64 data_start[1];
+		} raw;
+	} by_type;
+};
+
+struct el_subpacket_annotation {
+	struct el_subpacket_annotation *next;
+	u16 class;
+	u16 type;
+	u16 revision;
+	char *description;
+	char **annotation;
+};
+#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)}
+
+struct el_subpacket_handler {
+	struct el_subpacket_handler *next;
+	u16 class;
+	struct el_subpacket *(*handler)(struct el_subpacket *);
+};
+#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)}
+
+/*
+ * Extract a field from a register given it's name. defines
+ * for the LSB (__S - shift count) and bitmask (__M) are required
+ */
+#define EXTRACT(u, f) (((u) >> f##__S) & f##__M)
+
+/*
+ * err_common.c
+ */
+extern char *err_print_prefix;
+
+extern void mchk_dump_mem(void *, size_t, char **);
+extern void mchk_dump_logout_frame(struct el_common *);
+extern void ev7_register_error_handlers(void);
+extern void ev7_machine_check(u64, u64, struct pt_regs *);
+extern void ev6_register_error_handlers(void);
+extern int ev6_process_logout_frame(struct el_common *, int);
+extern void ev6_machine_check(u64, u64, struct pt_regs *);
+extern struct el_subpacket *el_process_subpacket(struct el_subpacket *);
+extern void el_annotate_subpacket(struct el_subpacket *);
+extern void cdl_check_console_data_log(void);
+extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
+extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
+
+/*
+ * err_marvel.c
+ */
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_register_error_handlers(void);
+
+/*
+ * err_titan.c
+ */
+extern int titan_process_logout_frame(struct el_common *, int);
+extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_register_error_handlers(void);
+extern int privateer_process_logout_frame(struct el_common *, int);
+extern void privateer_machine_check(u64, u64, struct pt_regs *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_marvel.c linux-2.4.21-rc3/arch/alpha/kernel/err_marvel.c
--- linux-2.4.20/arch/alpha/kernel/err_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/err_marvel.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,57 @@
+/*
+ *	linux/arch/alpha/kernel/err_marvel.c
+ *
+ *	Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/console.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+void
+marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	el_process_subpacket(el_ptr);
+
+	switch(vector) {
+	case SCB_Q_SYSEVENT:
+		printk(KERN_CRIT "MARVEL SYSEVENT %ld\n", vector);
+		break;
+	case SCB_Q_SYSMCHK:
+	case SCB_Q_SYSERR:
+		printk(KERN_CRIT "MARVEL SYSMCHK/ERR %ld\n", vector);
+		break;
+	default:
+		/* Don't know it - pass it up.  */
+		return ev7_machine_check(vector, la_ptr, regs);
+	}	
+
+        /* Release the logout frame.  */
+	wrmces(0x7);
+	mb();
+}
+
+void
+marvel_register_error_handlers(void)
+{
+	ev7_register_error_handlers();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_titan.c linux-2.4.21-rc3/arch/alpha/kernel/err_titan.c
--- linux-2.4.20/arch/alpha/kernel/err_titan.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/err_titan.c	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,747 @@
+/*
+ *	linux/arch/alpha/kernel/err_titan.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting TITAN systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/core_titan.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+static int
+titan_parse_c_misc(u64 c_misc, int print)
+{
+	char *src;
+	int nxs = 0;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define TITAN__CCHIP_MISC__NXM		(1UL << 28)
+#define TITAN__CCHIP_MISC__NXS__S	(29)
+#define TITAN__CCHIP_MISC__NXS__M	(0x7)
+
+	if (!(c_misc & TITAN__CCHIP_MISC__NXM))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	nxs = EXTRACT(c_misc, TITAN__CCHIP_MISC__NXS);
+	switch(nxs) {
+	case 0:	/* CPU 0 */
+	case 1:	/* CPU 1 */
+	case 2:	/* CPU 2 */
+	case 3:	/* CPU 3 */
+		src = "CPU";
+		/* num is already the CPU number */
+		break;
+	case 4:	/* Pchip 0 */
+	case 5:	/* Pchip 1 */
+		src = "Pchip";
+		nxs -= 4;
+		break;
+	default:/* reserved */
+		src = "Unknown, NXS =";
+		/* leave num untouched */
+		break;
+	}
+
+	printk("%s    Non-existent memory access from: %s %d\n", 
+	       err_print_prefix, src, nxs);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_serror(int which, u64 serror, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"};
+	char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_SERROR__LOST_UECC	(1UL << 0)
+#define TITAN__PCHIP_SERROR__UECC	(1UL << 1)
+#define TITAN__PCHIP_SERROR__CRE	(1UL << 2)
+#define TITAN__PCHIP_SERROR__NXIO	(1UL << 3)
+#define TITAN__PCHIP_SERROR__LOST_CRE	(1UL << 4)
+#define TITAN__PCHIP_SERROR__ECCMASK	(TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE)
+#define TITAN__PCHIP_SERROR__ERRMASK	(TITAN__PCHIP_SERROR__LOST_UECC | \
+					 TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE |	  \
+					 TITAN__PCHIP_SERROR__NXIO |	  \
+					 TITAN__PCHIP_SERROR__LOST_CRE)
+#define TITAN__PCHIP_SERROR__SRC__S	(52)
+#define TITAN__PCHIP_SERROR__SRC__M	(0x3)
+#define TITAN__PCHIP_SERROR__CMD__S	(54)
+#define TITAN__PCHIP_SERROR__CMD__M	(0x3)
+#define TITAN__PCHIP_SERROR__SYN__S	(56)
+#define TITAN__PCHIP_SERROR__SYN__M	(0xff)
+#define TITAN__PCHIP_SERROR__ADDR__S	(15)
+#define TITAN__PCHIP_SERROR__ADDR__M	(0xffffffffUL)
+
+	if (!(serror & TITAN__PCHIP_SERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	printk("%s  PChip %d SERROR: %016lx\n", 
+	       err_print_prefix, which, serror);
+	if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
+		printk("%s    %sorrectable ECC Error:\n"
+		       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
+		       "      Address: 0x%lx\n", 
+		       err_print_prefix,
+		       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
+		       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
+		       serror_cmd[EXTRACT(serror, TITAN__PCHIP_SERROR__CMD)],
+		       (unsigned)EXTRACT(serror, TITAN__PCHIP_SERROR__SYN),
+		       EXTRACT(serror, TITAN__PCHIP_SERROR__ADDR));
+	}
+	if (serror & TITAN__PCHIP_SERROR__NXIO)
+		printk("%s    Non Existent I/O Error\n", err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_UECC)
+		printk("%s    Lost Uncorrectable ECC Error\n", 
+		       err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_CRE)
+		printk("%s    Lost Correctable ECC Error\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int 
+titan_parse_p_perror(int which, int port, u64 perror, int print)
+{
+	int cmd;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle",
+			       "I/O Read",	       	"I/O Write",
+			       "Reserved",	       	"Reserved",
+			       "Memory Read",		"Memory Write",
+			       "Reserved",		"Reserved",
+			       "Configuration Read",	"Configuration Write",
+			       "Memory Read Multiple",	"Dual Address Cycle",
+			       "Memory Read Line","Memory Write and Invalidate"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_PERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_PERROR__SERR	(1UL << 1)
+#define TITAN__PCHIP_PERROR__PERR	(1UL << 2)
+#define TITAN__PCHIP_PERROR__DCRTO	(1UL << 3)
+#define TITAN__PCHIP_PERROR__SGE	(1UL << 4)
+#define TITAN__PCHIP_PERROR__APE	(1UL << 5)
+#define TITAN__PCHIP_PERROR__TA		(1UL << 6)
+#define TITAN__PCHIP_PERROR__DPE	(1UL << 7)
+#define TITAN__PCHIP_PERROR__NDS	(1UL << 8)
+#define TITAN__PCHIP_PERROR__IPTPR	(1UL << 9)
+#define TITAN__PCHIP_PERROR__IPTPW	(1UL << 10)
+#define TITAN__PCHIP_PERROR__ERRMASK	(TITAN__PCHIP_PERROR__LOST |	\
+					 TITAN__PCHIP_PERROR__SERR |	\
+					 TITAN__PCHIP_PERROR__PERR |	\
+					 TITAN__PCHIP_PERROR__DCRTO |	\
+					 TITAN__PCHIP_PERROR__SGE |	\
+					 TITAN__PCHIP_PERROR__APE |	\
+					 TITAN__PCHIP_PERROR__TA |	\
+					 TITAN__PCHIP_PERROR__DPE |	\
+					 TITAN__PCHIP_PERROR__NDS |	\
+					 TITAN__PCHIP_PERROR__IPTPR |	\
+					 TITAN__PCHIP_PERROR__IPTPW)
+#define TITAN__PCHIP_PERROR__DAC	(1UL << 47)
+#define TITAN__PCHIP_PERROR__MWIN	(1UL << 48)
+#define TITAN__PCHIP_PERROR__CMD__S	(52)
+#define TITAN__PCHIP_PERROR__CMD__M	(0x0f)
+#define TITAN__PCHIP_PERROR__ADDR__S	(14)
+#define TITAN__PCHIP_PERROR__ADDR__M	(0x1ffffffff)
+
+	if (!(perror & TITAN__PCHIP_PERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	cmd = EXTRACT(perror, TITAN__PCHIP_PERROR__CMD);
+	addr = EXTRACT(perror, TITAN__PCHIP_PERROR__ADDR) << 2;
+
+	/*
+	 * Initializing the BIOS on a video card on a bus without
+	 * a south bridge (subtractive decode agent) can result in 
+	 * master aborts as the BIOS probes the capabilities of the
+	 * card. XFree86 does such initialization. If the error
+	 * is a master abort (No DevSel as PCI Master) and the command
+	 * is an I/O read or write below the address where we start
+	 * assigning PCI I/O spaces (SRM uses 0x1000), then mark the
+	 * error as dismissable so starting XFree86 doesn't result
+	 * in a series of uncorrectable errors being reported. Also
+	 * dismiss master aborts to VGA frame buffer space
+	 * (0xA0000 - 0xC0000) and legacy BIOS space (0xC0000 - 0x100000)
+	 * for the same reason.
+	 *
+	 * Also mark the error dismissible if it looks like the right
+	 * error but only the Lost bit is set. Since the BIOS initialization
+	 * can cause multiple master aborts and the error interrupt can
+	 * be handled on a different CPU than the BIOS code is run on,
+	 * it is possible for a second master abort to occur between the
+	 * time the PALcode reads PERROR and the time it writes PERROR
+	 * to acknowledge the error. If this timing happens, a second
+	 * error will be signalled after the first, and if no additional
+	 * errors occur, will look like a Lost error with no additional 
+	 * errors on the same transaction as the previous error.
+	 */
+	if (((perror & TITAN__PCHIP_PERROR__NDS) || 
+	     ((perror & TITAN__PCHIP_PERROR__ERRMASK) == 
+	      TITAN__PCHIP_PERROR__LOST)) &&
+	    ((((cmd & 0xE) == 2) && (addr < 0x1000)) ||
+	     (((cmd & 0xE) == 6) && (addr >= 0xA0000) && (addr < 0x100000)))) {
+		status = MCHK_DISPOSITION_DISMISS;
+	}
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print) 
+		return status;
+
+	printk("%s  PChip %d %cPERROR: %016lx\n", 
+	       err_print_prefix, which, 
+	       port ? 'A' : 'G', perror);
+	if (perror & TITAN__PCHIP_PERROR__IPTPW)
+		printk("%s    Invalid Peer-to-Peer Write\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__IPTPR)
+		printk("%s    Invalid Peer-to-Peer Read\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__NDS)
+		printk("%s    No DEVSEL as PCI Master [Master Abort]\n",
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DPE)
+		printk("%s    Data Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__TA)
+		printk("%s    Target Abort\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__APE)
+		printk("%s    Address Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SGE)
+		printk("%s    Scatter-Gather Error, Invalid PTE\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DCRTO)
+		printk("%s    Delayed-Completion Retry Timeout\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__PERR)
+		printk("%s    PERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SERR)
+		printk("%s    SERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix,
+	       cmd, perror_cmd[cmd],
+	       addr);
+	if (perror & TITAN__PCHIP_PERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_agperror(int which, u64 agperror, int print)
+{
+	int cmd, len;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *agperror_cmd[] = { "Read (low-priority)",	"Read (high-priority)",
+				 "Write (low-priority)",
+				 "Write (high-priority)",
+				 "Reserved",		"Reserved",
+				 "Flush",		"Fence"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_AGPERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_AGPERROR__LPQFULL	(1UL << 1)
+#define TITAN__PCHIP_AGPERROR__HPQFULL	(1UL << 2)
+#define TITAN__PCHIP_AGPERROR__RESCMD	(1UL << 3)
+#define TITAN__PCHIP_AGPERROR__IPTE	(1UL << 4)
+#define TITAN__PCHIP_AGPERROR__PTP	(1UL << 5)
+#define TITAN__PCHIP_AGPERROR__NOWINDOW	(1UL << 6)
+#define TITAN__PCHIP_AGPERROR__ERRMASK	(TITAN__PCHIP_AGPERROR__LOST |    \
+					 TITAN__PCHIP_AGPERROR__LPQFULL | \
+					 TITAN__PCHIP_AGPERROR__HPQFULL | \
+					 TITAN__PCHIP_AGPERROR__RESCMD |  \
+					 TITAN__PCHIP_AGPERROR__IPTE |    \
+					 TITAN__PCHIP_AGPERROR__PTP |     \
+					 TITAN__PCHIP_AGPERROR__NOWINDOW)
+#define TITAN__PCHIP_AGPERROR__DAC	(1UL << 48)
+#define TITAN__PCHIP_AGPERROR__MWIN	(1UL << 49)
+#define TITAN__PCHIP_AGPERROR__FENCE	(1UL << 59)
+#define TITAN__PCHIP_AGPERROR__CMD__S	(50)
+#define TITAN__PCHIP_AGPERROR__CMD__M	(0x07)
+#define TITAN__PCHIP_AGPERROR__ADDR__S	(15)
+#define TITAN__PCHIP_AGPERROR__ADDR__M  (0xffffffffUL)
+#define TITAN__PCHIP_AGPERROR__LEN__S	(53)
+#define TITAN__PCHIP_AGPERROR__LEN__M	(0x3f)
+
+	if (!(agperror & TITAN__PCHIP_AGPERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	cmd = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__CMD);
+	addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
+	len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
+
+	printk("%s  PChip %d AGPERROR: %016lx\n", err_print_prefix,
+	       which, agperror);
+	if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
+		printk("%s    No Window\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__PTP)
+		printk("%s    Peer-to-Peer set\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__IPTE)
+		printk("%s    Invalid PTE\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__RESCMD)
+		printk("%s    Reserved Command\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__HPQFULL)
+		printk("%s    HP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LPQFULL)
+		printk("%s    LP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s, %d Quadwords%s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix, cmd, agperror_cmd[cmd], len,
+	       (agperror & TITAN__PCHIP_AGPERROR__FENCE) ? ", FENCE" : "",
+	       addr);
+	if (agperror & TITAN__PCHIP_AGPERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}	
+
+static int
+titan_parse_p_chip(int which, u64 serror, u64 gperror, 
+		   u64 aperror, u64 agperror, int print)
+{
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+	status |= titan_parse_p_serror(which, serror, print);
+	status |= titan_parse_p_perror(which, 0, gperror, print);
+	status |= titan_parse_p_perror(which, 1, aperror, print);
+	status |= titan_parse_p_agperror(which, agperror, print);
+	return status;
+}
+
+int
+titan_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= titan_parse_c_misc(tmchk->c_misc, print);
+	status |= titan_parse_p_chip(0, tmchk->p0_serror, tmchk->p0_gperror,
+				     tmchk->p0_aperror, tmchk->p0_agperror, 
+				     print);
+	status |= titan_parse_p_chip(1, tmchk->p1_serror, tmchk->p1_gperror,
+				     tmchk->p1_aperror, tmchk->p1_agperror, 
+				     print);
+
+	return status;
+}
+
+void
+titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	u64 irqmask;
+
+	/*
+	 * Mask of Titan interrupt sources which are reported as machine checks
+	 *
+	 * 63 - CChip Error
+	 * 62 - PChip 0 H_Error
+	 * 61 - PChip 1 H_Error
+	 * 60 - PChip 0 C_Error
+	 * 59 - PChip 1 C_Error
+	 */
+#define TITAN_MCHECK_INTERRUPT_MASK	0xF800000000000000UL
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+	
+	/*
+	 * Only handle system errors here 
+	 */
+	if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) 
+		return ev6_machine_check(vector, la_ptr, regs);
+
+	/* 
+	 * It's a system error, handle it here
+	 *
+	 * The PALcode has already cleared the error, so just parse it
+	 */
+	
+	/* 
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are classified as "dismissable", then just dismiss them and
+	 * don't print any message
+	 */
+	if (titan_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s"
+		       "*System %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_SYSERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+#ifdef CONFIG_VERBOSE_MCHECK
+		titan_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+		err_print_prefix = saved_err_prefix;
+
+		/*
+		 * Convert any pending interrupts which report as system
+		 * machine checks to interrupts
+		 */
+		irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
+		titan_dispatch_irqs(irqmask, regs);
+	}	
+
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+/*
+ * Subpacket Annotations
+ */
+static char *el_titan_pchip0_extended_annotation[] = {
+	"Subpacket Header", 	"P0_SCTL",	"P0_SERREN",
+	"P0_APCTL",		"P0_APERREN",	"P0_AGPERREN",
+	"P0_ASPRST",		"P0_AWSBA0",	"P0_AWSBA1",
+	"P0_AWSBA2",		"P0_AWSBA3",	"P0_AWSM0",
+	"P0_AWSM1",		"P0_AWSM2",	"P0_AWSM3",
+	"P0_ATBA0",		"P0_ATBA1",	"P0_ATBA2",
+	"P0_ATBA3",		"P0_GPCTL",	"P0_GPERREN",
+	"P0_GSPRST",		"P0_GWSBA0",	"P0_GWSBA1",
+	"P0_GWSBA2",		"P0_GWSBA3",	"P0_GWSM0",
+	"P0_GWSM1",		"P0_GWSM2",	"P0_GWSM3",
+	"P0_GTBA0",		"P0_GTBA1",	"P0_GTBA2",
+	"P0_GTBA3",		NULL 
+};
+static char *el_titan_pchip1_extended_annotation[] = {
+	"Subpacket Header", 	"P1_SCTL",	"P1_SERREN",
+	"P1_APCTL",		"P1_APERREN",	"P1_AGPERREN",
+	"P1_ASPRST",		"P1_AWSBA0",	"P1_AWSBA1",
+	"P1_AWSBA2",		"P1_AWSBA3",	"P1_AWSM0",
+	"P1_AWSM1",		"P1_AWSM2",	"P1_AWSM3",
+	"P1_ATBA0",		"P1_ATBA1",	"P1_ATBA2",
+	"P1_ATBA3",		"P1_GPCTL",	"P1_GPERREN",
+	"P1_GSPRST",		"P1_GWSBA0",	"P1_GWSBA1",
+	"P1_GWSBA2",		"P1_GWSBA3",	"P1_GWSM0",
+	"P1_GWSM1",		"P1_GWSM2",	"P1_GWSM3",
+	"P1_GTBA0",		"P1_GTBA1",	"P1_GTBA2",
+	"P1_GTBA3",		NULL 
+};
+static char *el_titan_memory_extended_annotation[] = {
+	"Subpacket Header", 	"AAR0",		"AAR1",
+	"AAR2",			"AAR3",		"P0_SCTL",
+	"P0_GPCTL",		"P0_APCTL",	"P1_SCTL",
+	"P1_GPCTL",		"P1_SCTL",	NULL 
+};
+
+static struct el_subpacket_annotation el_titan_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED,
+			     1,
+			     "Titan PChip 0 Extended Frame",
+			     el_titan_pchip0_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED,
+			     1,
+			     "Titan PChip 1 Extended Frame",
+			     el_titan_pchip1_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED,
+			     1,
+			     "Titan Memory Extended Frame",
+			     el_titan_memory_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__TERMINATION__TERMINATION,
+			     1,
+			     "Termination Subpacket",
+			     NULL)
+};
+
+static struct el_subpacket *
+el_process_regatta_subpacket(struct el_subpacket *header)
+{
+	int status;
+
+	if (header->class != EL_CLASS__REGATTA_FAMILY) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
+	case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
+	case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
+	case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
+	case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
+		printk("%s  ** Occurred on CPU %d:\n", 
+		       err_print_prefix,
+		       (int)header->by_type.regatta_frame.cpuid);
+		status = privateer_process_logout_frame((struct el_common *)
+			header->by_type.regatta_frame.data_start, 1);
+		break;
+	default:
+		printk("%s  ** REGATTA TYPE %d SUBPACKET\n", 
+		       err_print_prefix, header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+
+
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+} 
+
+static struct el_subpacket_handler titan_subpacket_handler = 
+	SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY, 
+			       el_process_regatta_subpacket);
+
+void
+titan_register_error_handlers(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE (el_titan_annotations); i++)
+		cdl_register_subpacket_annotation(&el_titan_annotations[i]);
+
+	cdl_register_subpacket_handler(&titan_subpacket_handler);
+}
+
+
+/*
+ * Privateer
+ */
+
+static int
+privateer_process_680_frame(struct el_common *mchk_header, int print)
+{
+	struct el_PRIVATEER_envdata_mcheck *emchk =
+		(struct el_PRIVATEER_envdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/* TODO - catagorize errors, for now, no error */
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	/* TODO - decode instead of just dumping... */
+	printk("%s  Summary Flags:         %016lx\n"
+ 	         "  CChip DIRx:            %016lx\n"
+		 "  System Management IR:  %016lx\n"
+		 "  CPU IR:                %016lx\n"
+		 "  Power Supply IR:       %016lx\n"
+		 "  LM78 Fault Status:     %016lx\n"
+		 "  System Doors:          %016lx\n"
+		 "  Temperature Warning:   %016lx\n"
+		 "  Fan Control:           %016lx\n"
+		 "  Fatal Power Down Code: %016lx\n",
+	       err_print_prefix,
+	       emchk->summary,
+	       emchk->c_dirx,
+	       emchk->smir,
+	       emchk->cpuir,
+	       emchk->psir,
+	       emchk->fault,
+	       emchk->sys_doors,
+	       emchk->temp_warn,
+	       emchk->fan_ctrl,
+	       emchk->code);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+int
+privateer_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/*
+	 * Machine check codes
+	 */
+#define PRIVATEER_MCHK__CORR_ECC		0x86	/* 630 */
+#define PRIVATEER_MCHK__DC_TAG_PERR		0x9E	/* 630 */
+#define PRIVATEER_MCHK__PAL_BUGCHECK		0x8E	/* 670 */
+#define PRIVATEER_MCHK__OS_BUGCHECK		0x90	/* 670 */
+#define PRIVATEER_MCHK__PROC_HRD_ERR		0x98	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_PRX	0xA0	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_FLT	0xA2	/* 670 */
+#define PRIVATEER_MCHK__SYS_HRD_ERR		0x202	/* 660 */
+#define PRIVATEER_MCHK__SYS_CORR_ERR		0x204	/* 620 */
+#define PRIVATEER_MCHK__SYS_ENVIRON		0x206	/* 680 */
+
+	switch(ev6mchk->MCHK_Code) {
+	/*
+	 * Vector 630 - Processor, Correctable
+	 */
+	case PRIVATEER_MCHK__CORR_ECC:
+	case PRIVATEER_MCHK__DC_TAG_PERR:
+		/*
+		 * Fall through to vector 670 for processing...
+		 */
+	/*
+	 * Vector 670 - Processor, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__PAL_BUGCHECK:
+	case PRIVATEER_MCHK__OS_BUGCHECK:
+	case PRIVATEER_MCHK__PROC_HRD_ERR:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_PRX:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_FLT:
+		status |= ev6_process_logout_frame(mchk_header, print);
+		break;
+
+	/*
+	 * Vector 620 - System, Correctable
+	 */
+	case PRIVATEER_MCHK__SYS_CORR_ERR:
+		/*
+		 * Fall through to vector 660 for processing...
+		 */
+	/*
+	 * Vector 660 - System, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__SYS_HRD_ERR:
+		status |= titan_process_logout_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Vector 680 - System, Environmental
+	 */
+	case PRIVATEER_MCHK__SYS_ENVIRON:	/* System, Environmental */
+		status |= privateer_process_680_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Unknown
+	 */
+	default:
+		status |= MCHK_DISPOSITION_REPORT;
+		if (print) {
+			printk("%s** Unknown Error, frame follows\n", 
+			       err_print_prefix);
+			mchk_dump_logout_frame(mchk_header);
+		}
+
+	}
+
+	return status;
+}
+
+void
+privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		(la_ptr + mchk_header->sys_offset);
+	u64 irqmask;
+	char *saved_err_prefix = err_print_prefix;
+
+#define PRIVATEER_680_INTERRUPT_MASK		(0xE00UL)
+#define PRIVATEER_HOTPLUG_INTERRUPT_MASK	(0xE00UL)
+
+	/*
+	 * Sync the processor.
+	 */
+	mb();
+	draina();
+
+	/* 
+	 * Only handle system events here.
+	 */
+	if (vector != SCB_Q_SYSEVENT) 
+		return titan_machine_check(vector, la_ptr, regs);
+
+	/*
+	 * Report the event - System Events should be reported even if no
+	 * error is indicated since the event could indicate the return
+	 * to normal status.
+	 */
+	err_print_prefix = KERN_CRIT;
+	printk("%s*System Event (Vector 0x%x) reported on CPU %d:\n", 
+	       err_print_prefix,
+	       (unsigned int)vector, (int)smp_processor_id());
+	privateer_process_680_frame(mchk_header, 1);
+	err_print_prefix = saved_err_prefix;
+	
+	/* 
+	 * Convert any pending interrupts which report as 680 machine
+	 * checks to interrupts.
+	 */
+	irqmask = tmchk->c_dirx & PRIVATEER_680_INTERRUPT_MASK;
+
+	/*
+	 * Dispatch the interrupt(s).
+	 */
+	titan_dispatch_irqs(irqmask, regs);
+
+	/* 
+	 * Release the logout frame.
+	 */
+	wrmces(0x7);
+	mb();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/gct.c linux-2.4.21-rc3/arch/alpha/kernel/gct.c
--- linux-2.4.20/arch/alpha/kernel/gct.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/gct.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,48 @@
+/*
+ *	linux/arch/alpha/kernel/gct.c
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+
+int
+gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
+{
+	gct6_search_struct *wanted;
+	int status = 0;
+
+	/* First check the magic number.  */
+	if (node->magic != GCT_NODE_MAGIC) {
+		printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
+		return -EINVAL;
+	}
+
+	/* Check against the search struct.  */
+	for (wanted = search; 
+	     wanted && (wanted->type | wanted->subtype); 
+	     wanted++) {
+		if (node->type != wanted->type)
+			continue;
+		if (node->subtype != wanted->subtype)
+			continue;
+
+		/* Found it -- call out.  */
+		if (wanted->callout)
+			wanted->callout(node);
+	}
+
+	/* Now walk the tree, siblings first.  */
+	if (node->next) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);
+
+	/* Then the children.  */
+	if (node->child) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);
+
+	return status;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/irq.c linux-2.4.21-rc3/arch/alpha/kernel/irq.c
--- linux-2.4.20/arch/alpha/kernel/irq.c	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/irq.c	2003-05-22 22:06:51.000000000 +0000
@@ -374,15 +374,17 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 #ifdef CONFIG_SMP
-	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+	if (irq_desc[irq].handler->set_affinity) {
+		/* create /proc/irq/1234/smp_affinity */
+		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+		entry->nlink = 1;
+		entry->data = (void *)(long)irq;
+		entry->read_proc = irq_affinity_read_proc;
+		entry->write_proc = irq_affinity_write_proc;
 
-	entry->nlink = 1;
-	entry->data = (void *)(long)irq;
-	entry->read_proc = irq_affinity_read_proc;
-	entry->write_proc = irq_affinity_write_proc;
-
-	smp_affinity_entry[irq] = entry;
+		smp_affinity_entry[irq] = entry;
+	}
 #endif
 }
 
@@ -410,12 +412,16 @@
 #endif
 
 	/*
-	 * Create entries for all existing IRQs.
+	 * Create entries for all existing IRQs. If the number of IRQs
+	 * is greater the 1/4 the total dynamic inode space for /proc,
+	 * don't pollute the inode space
 	 */
-	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_desc[i].handler == &no_irq_type)
-			continue;
-		register_irq_proc(i);
+	if (ACTUAL_NR_IRQS < (PROC_NDYNAMIC / 4)) {
+		for (i = 0; i < ACTUAL_NR_IRQS; i++) {
+			if (irq_desc[i].handler == &no_irq_type)
+				continue;
+			register_irq_proc(i);
+		}
 	}
 }
 
@@ -534,7 +540,7 @@
 	*p++ = '\n';
 #endif
 
-	for (i = 0; i < NR_IRQS; i++) {
+	for (i = 0; i < ACTUAL_NR_IRQS; i++) {
 		action = irq_desc[i].action;
 		if (!action) 
 			continue;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/irq_alpha.c linux-2.4.21-rc3/arch/alpha/kernel/irq_alpha.c
--- linux-2.4.20/arch/alpha/kernel/irq_alpha.c	2001-10-05 01:47:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/irq_alpha.c	2003-05-22 22:06:38.000000000 +0000
@@ -152,7 +152,7 @@
 
 	mchk_header = (struct el_common *)la_ptr;
 
-	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n",
+	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
 	       machine, vector, regs->pc, mchk_header->code);
 
 	switch ((unsigned int) mchk_header->code) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/machvec_impl.h linux-2.4.21-rc3/arch/alpha/kernel/machvec_impl.h
--- linux-2.4.20/arch/alpha/kernel/machvec_impl.h	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/machvec_impl.h	2003-05-22 22:06:28.000000000 +0000
@@ -9,10 +9,12 @@
 #include <linux/config.h>
 #include <asm/pgalloc.h>
 
-/* Whee.  IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE.
+/* Whee.  These systems don't have an HAE:
+       IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
    Fix things up for the GENERIC kernel by defining the HAE address
    to be that of the cache. Now we can read and write it as we like.  ;-)  */
 #define IRONGATE_HAE_ADDRESS	(&alpha_mv.hae_cache)
+#define MARVEL_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TSUNAMI_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TITAN_HAE_ADDRESS	(&alpha_mv.hae_cache)
@@ -32,7 +34,6 @@
 #define T2_IACK_SC		1
 #define WILDFIRE_IACK_SC	1 /* FIXME */
 
-
 /*
  * Some helpful macros for filling in the blanks.
  */
@@ -63,6 +64,13 @@
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
 
+#define DO_EV7_MMU							\
+	max_asn:			EV6_MAX_ASN,			\
+	mv_switch_mm:			ev5_switch_mm,			\
+	mv_activate_mm:			ev5_activate_mm,		\
+	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
+	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
+
 #define IO_LITE(UP,low)							\
 	hae_register:		(unsigned long *) CAT(UP,_HAE_ADDRESS),	\
 	iack_sc:		CAT(UP,_IACK_SC),			\
@@ -91,6 +99,7 @@
 #define DO_CIA_IO	IO(CIA,cia)
 #define DO_IRONGATE_IO	IO(IRONGATE,irongate)
 #define DO_LCA_IO	IO(LCA,lca)
+#define DO_MARVEL_IO	IO(MARVEL,marvel)
 #define DO_MCPCIA_IO	IO(MCPCIA,mcpcia)
 #define DO_POLARIS_IO	IO(POLARIS,polaris)
 #define DO_T2_IO	IO(T2,t2)
@@ -109,6 +118,7 @@
 #define DO_CIA_BUS	BUS(cia)
 #define DO_IRONGATE_BUS	BUS(irongate)
 #define DO_LCA_BUS	BUS(lca)
+#define DO_MARVEL_BUS	BUS(marvel)
 #define DO_MCPCIA_BUS	BUS(mcpcia)
 #define DO_POLARIS_BUS	BUS(polaris)
 #define DO_T2_BUS	BUS(t2)
@@ -116,7 +126,6 @@
 #define DO_TITAN_BUS	BUS(titan)
 #define DO_WILDFIRE_BUS	BUS(wildfire)
 
-
 /*
  * In a GENERIC kernel, we have lots of these vectors floating about,
  * all but one of which we want to go away.  In a non-GENERIC kernel,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/osf_sys.c linux-2.4.21-rc3/arch/alpha/kernel/osf_sys.c
--- linux-2.4.20/arch/alpha/kernel/osf_sys.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/osf_sys.c	2003-05-22 22:06:24.000000000 +0000
@@ -462,13 +462,8 @@
 
 asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
 {
-	int ret;
-
 	/* for now, simply ignore lowat and hiwat... */
-	lock_kernel();
-	ret = sys_swapon(path, flags);
-	unlock_kernel();
-	return ret;
+	return sys_swapon(path, flags);
 }
 
 asmlinkage unsigned long sys_getpagesize(void)
@@ -529,18 +524,13 @@
 	unsigned long raddr;
 	long err;
 
-	lock_kernel();
 	err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
-	if (err)
-		goto out;
+
 	/*
 	 * This works because all user-level addresses are
 	 * non-negative longs!
 	 */
-	err = raddr;
-out:
-	unlock_kernel();
-	return err;
+	return err ? err : (long)raddr;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci.c linux-2.4.21-rc3/arch/alpha/kernel/pci.c
--- linux-2.4.20/arch/alpha/kernel/pci.c	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/pci.c	2003-05-22 22:06:26.000000000 +0000
@@ -41,6 +41,8 @@
 
 const char pci_hae0_name[] = "HAE0";
 
+/* Indicate whether we respect the PCI setup left by console. */
+int __initdata pci_probe_only;
 
 /*
  * The PCI controller list.
@@ -66,17 +68,6 @@
 }
 
 static void __init
-quirk_ali_ide_ports(struct pci_dev *dev)
-{
-	if (dev->resource[0].end == 0xffff)
-		dev->resource[0].end = dev->resource[0].start + 7;
-	if (dev->resource[2].end == 0xffff)
-		dev->resource[2].end = dev->resource[2].start + 7;
-	if (dev->resource[3].end == 0xffff)
-		dev->resource[3].end = dev->resource[3].start + 7;
-}
-
-static void __init
 quirk_cypress(struct pci_dev *dev)
 {
 	/* The Notorious Cy82C693 chip.  */
@@ -114,8 +105,6 @@
 	  quirk_eisa_bridge },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378,
 	  quirk_isa_bridge },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
-	  quirk_ali_ide_ports },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693,
 	  quirk_cypress },
 	{ 0 }
@@ -243,10 +232,25 @@
 	struct pci_dev *dev = bus->self;
 
 	if (!dev) {
-		/* Root bus */
+		/* Root bus. */
+		u32 pci_mem_end;
+		u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
+		unsigned long end;
+
 		bus->resource[0] = hose->io_space;
 		bus->resource[1] = hose->mem_space;
-	}
+
+		/* Adjust hose mem_space limit to prevent PCI allocations
+		   in the iommu windows. */
+		pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
+		end = hose->mem_space->start + pci_mem_end;
+		if (hose->mem_space->end > end)
+			hose->mem_space->end = end;
+ 	} else if (pci_probe_only &&
+ 		   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ 		pci_read_bridge_bases(bus);
+ 		pcibios_fixup_device_resources(dev, bus);
+	} 
 
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
@@ -311,7 +315,7 @@
 			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
 			/* Move up the chain of bridges. */
 			dev = dev->bus->self;
-		} while (dev->bus->self);
+		} while (dev->bus->parent);
 		*pinp = pin;
 
 		/* The slot is the slot of the last bridge. */
@@ -359,6 +363,40 @@
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 }
 
+static void __init
+pcibios_claim_one_bus(struct pci_bus *b)
+{
+	struct list_head *ld;
+	struct pci_bus *child_bus;
+
+	for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
+		struct pci_dev *dev = pci_dev_b(ld);
+		int i;
+
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+
+			if (r->parent || !r->start || !r->flags)
+				continue;
+			pci_claim_resource(dev, i);
+		}
+	}
+
+	list_for_each_entry(child_bus, &b->children, node)
+		pcibios_claim_one_bus(child_bus);
+}
+
+static void __init
+pcibios_claim_console_setup(void)
+{
+	struct list_head *lb;
+
+	for(lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) {
+		struct pci_bus *b = pci_bus_b(lb);
+		pcibios_claim_one_bus(b);
+	}
+}
+
 void __init
 common_init_pci(void)
 {
@@ -376,7 +414,12 @@
 		next_busno += 1;
 	}
 
-	pci_assign_unassigned_resources();
+	if (pci_probe_only)
+		pcibios_claim_console_setup();
+	else	/* FIXME: `else' will be removed when
+		   pci_assign_unassigned_resources() is able to work
+		   correctly with [partially] allocated PCI tree. */
+		pci_assign_unassigned_resources();
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_impl.h linux-2.4.21-rc3/arch/alpha/kernel/pci_impl.h
--- linux-2.4.20/arch/alpha/kernel/pci_impl.h	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/pci_impl.h	2003-05-22 22:06:52.000000000 +0000
@@ -52,15 +52,16 @@
 #define APECS_AND_LCA_DEFAULT_MEM_BASE ((16+2)*1024*1024)
 
 /*
- * Because the MCPCIA core logic supports more bits for physical addresses,
- * it should allow an expanded range of SPARSE memory addresses.
- * However, we do not use them all, in order to avoid the HAE manipulation
- * that would be needed.
+ * Because MCPCIA and T2 core logic support more bits for
+ * physical addresses, they should allow an expanded range of SPARSE
+ * memory addresses.  However, we do not use them all, in order to
+ * avoid the HAE manipulation that would be needed.
  */
 #define MCPCIA_DEFAULT_MEM_BASE ((32+2)*1024*1024)
+#define T2_DEFAULT_MEM_BASE ((16+1)*1024*1024)
 
 /*
- * Because CIA and PYXIS and T2 have more bits for physical addresses,
+ * Because CIA and PYXIS have more bits for physical addresses,
  * they support an expanded range of SPARSE memory addresses.
  */
 #define DEFAULT_MEM_BASE ((128+16)*1024*1024)
@@ -70,6 +71,8 @@
 
 #define IRONGATE_DEFAULT_MEM_BASE ((256*8-16)*1024*1024)
 
+#define DEFAULT_AGP_APER_SIZE	(64*1024*1024)
+
 /* 
  * A small note about bridges and interrupts.  The DECchip 21050 (and
  * later) adheres to the PCI-PCI bridge specification.  This says that
@@ -149,16 +152,23 @@
 extern struct pci_controller *hose_head, **hose_tail;
 extern struct pci_controller *pci_isa_hose;
 
+/* Indicate that we trust the console to configure things properly.  */
+extern int pci_probe_only;
+
+extern unsigned long alpha_agpgart_size;
+
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
 extern struct pci_controller *alloc_pci_controller(void);
 extern struct resource *alloc_resource(void);
 
+extern struct pci_iommu_arena *iommu_arena_new_node(int,
+						    struct pci_controller *,
+					            dma_addr_t, unsigned long,
+					            unsigned long);
 extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *,
 					       dma_addr_t, unsigned long,
 					       unsigned long);
-extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n);
-
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_iommu.c linux-2.4.21-rc3/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.20/arch/alpha/kernel/pci_iommu.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/pci_iommu.c	2003-05-22 22:06:52.000000000 +0000
@@ -30,10 +30,9 @@
 #define DEBUG_NODIRECT 0
 #define DEBUG_FORCEDAC 0
 
-/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and
-   Nautilus (see asm/dma.h for details). */
-#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \
-			 MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff)
+/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian,
+   Sable, and Alcor (see asm-alpha/dma.h for details). */
+#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1)
 
 static inline unsigned long
 mk_iommu_pte(unsigned long paddr)
@@ -61,8 +60,8 @@
 }
 
 struct pci_iommu_arena *
-iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
-		unsigned long window_size, unsigned long align)
+iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
+		     unsigned long window_size, unsigned long align)
 {
 	unsigned long mem_size;
 	struct pci_iommu_arena *arena;
@@ -76,9 +75,36 @@
 	if (align < mem_size)
 		align = mem_size;
 
+
+#ifdef CONFIG_DISCONTIGMEM
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena = alloc_bootmem_node(NODE_DATA(nid),
+                                                 sizeof(*arena))))) {
+                printk("%s: couldn't allocate arena from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena = alloc_bootmem(sizeof(*arena));
+        }
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena->ptes = __alloc_bootmem_node(NODE_DATA(nid),
+                                                         mem_size,
+                                                         align,
+                                                         0)))) {
+                printk("%s: couldn't allocate arena ptes from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena->ptes = __alloc_bootmem(mem_size, align, 0);
+        }
+
+#else /* CONFIG_DISCONTIGMEM */
+
 	arena = alloc_bootmem(sizeof(*arena));
 	arena->ptes = __alloc_bootmem(mem_size, align, 0);
 
+#endif /* CONFIG_DISCONTIGMEM */
+
 	spin_lock_init(&arena->lock);
 	arena->hose = hose;
 	arena->dma_base = base;
@@ -92,6 +118,13 @@
 	return arena;
 }
 
+struct pci_iommu_arena *
+iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
+		unsigned long window_size, unsigned long align)
+{
+	return iommu_arena_new_node(0, hose, base, window_size, align);
+}
+
 /* Must be called with the arena lock held */
 static long
 iommu_arena_find_pages(struct pci_iommu_arena *arena, long n, long mask)
@@ -133,8 +166,8 @@
 	return p;
 }
 
-long
-iommu_arena_alloc(struct pci_iommu_arena *arena, long n)
+static long
+iommu_arena_alloc(struct pci_iommu_arena *arena, long n, unsigned int align)
 {
 	unsigned long flags;
 	unsigned long *ptes;
@@ -144,7 +177,7 @@
 
 	/* Search for N empty ptes */
 	ptes = arena->ptes;
-	mask = arena->align_entry - 1;
+	mask = max(align, arena->align_entry) - 1;
 	p = iommu_arena_find_pages(arena, n, mask);
 	if (p < 0) {
 		spin_unlock_irqrestore(&arena->lock, flags);
@@ -233,7 +266,8 @@
 		arena = hose->sg_isa;
 
 	npages = calc_npages((paddr & ~PAGE_MASK) + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	/* Force allocation to 64KB boundary for all ISA devices. */
+	dma_ofs = iommu_arena_alloc(arena, npages, pdev ? 0 : 8);
 	if (dma_ofs < 0) {
 		printk(KERN_WARNING "pci_map_single failed: "
 		       "could not allocate dma page tables\n");
@@ -361,8 +395,10 @@
 {
 	void *cpu_addr;
 	long order = get_order(size);
+	int gfp = GFP_ATOMIC;
 
-	cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order);
+try_again:
+	cpu_addr = (void *)__get_free_pages(gfp, order);
 	if (! cpu_addr) {
 		printk(KERN_INFO "pci_alloc_consistent: "
 		       "get_free_pages failed from %p\n",
@@ -376,7 +412,12 @@
 	*dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0);
 	if (*dma_addrp == 0) {
 		free_pages((unsigned long)cpu_addr, order);
-		return NULL;
+		if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA))
+			return NULL;
+		/* The address doesn't fit required mask and we
+		   do not have iommu. Try again with GFP_DMA. */
+		gfp |= GFP_DMA;
+		goto try_again;
 	}
 		
 	DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
@@ -505,7 +546,7 @@
 
 	paddr &= ~PAGE_MASK;
 	npages = calc_npages(paddr + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	dma_ofs = iommu_arena_alloc(arena, npages, 0);
 	if (dma_ofs < 0) {
 		/* If we attempted a direct map above but failed, die.  */
 		if (leader->dma_address == 0)
@@ -742,6 +783,10 @@
 	if (arena && arena->dma_base + arena->size - 1 <= mask)
 		return 1;
 
+	/* As last resort try ZONE_DMA.  */
+	if (!__direct_map_base && MAX_DMA_ADDRESS - IDENT_ADDR - 1 <= mask)
+		return 1;
+
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/process.c linux-2.4.21-rc3/arch/alpha/kernel/process.c
--- linux-2.4.20/arch/alpha/kernel/process.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/process.c	2003-05-22 22:06:40.000000000 +0000
@@ -336,7 +336,7 @@
 }
 
 /*
- * fill in the user structure for a core dump..
+ * Fill in the user structure for an ECOFF core dump.
  */
 void
 dump_thread(struct pt_regs * pt, struct user * dump)
@@ -396,6 +396,55 @@
 	memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
 }
 
+/*
+ * Fill in the user structure for a ELF core dump.
+ */
+void
+dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+		struct task_struct *task)
+{
+	/* switch stack follows right below pt_regs: */
+	struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
+
+	dest[ 0] = pt->r0;
+	dest[ 1] = pt->r1;
+	dest[ 2] = pt->r2;
+	dest[ 3] = pt->r3;
+	dest[ 4] = pt->r4;
+	dest[ 5] = pt->r5;
+	dest[ 6] = pt->r6;
+	dest[ 7] = pt->r7;
+	dest[ 8] = pt->r8;
+	dest[ 9] = sw->r9;
+	dest[10] = sw->r10;
+	dest[11] = sw->r11;
+	dest[12] = sw->r12;
+	dest[13] = sw->r13;
+	dest[14] = sw->r14;
+	dest[15] = sw->r15;
+	dest[16] = pt->r16;
+	dest[17] = pt->r17;
+	dest[18] = pt->r18;
+	dest[19] = pt->r19;
+	dest[20] = pt->r20;
+	dest[21] = pt->r21;
+	dest[22] = pt->r22;
+	dest[23] = pt->r23;
+	dest[24] = pt->r24;
+	dest[25] = pt->r25;
+	dest[26] = pt->r26;
+	dest[27] = pt->r27;
+	dest[28] = pt->r28;
+	dest[29] = pt->gp;
+	dest[30] = rdusp();
+	dest[31] = pt->pc;
+
+	/* Once upon a time this was the PS value.  Which is stupid
+	   since that is always 8 for usermode.  Usurped for the more
+	   useful value of the thread's UNIQUE field.  */
+	dest[32] = task->thread.unique;
+}
+
 int
 dump_fpu(struct pt_regs * regs, elf_fpregset_t *r)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/proto.h linux-2.4.21-rc3/arch/alpha/kernel/proto.h
--- linux-2.4.20/arch/alpha/kernel/proto.h	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/proto.h	2003-05-22 22:06:38.000000000 +0000
@@ -1,4 +1,6 @@
 #include <linux/config.h>
+
+
 /* Prototypes of functions used across modules here in this directory.  */
 
 #define vucp	volatile unsigned char  *
@@ -24,6 +26,7 @@
 extern void cia_init_pci(void);
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
+extern void cia_kill_arch(int);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
 extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
@@ -40,6 +43,21 @@
 extern void lca_machine_check(u64, u64, struct pt_regs *);
 extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
+/* core_marvel.c */
+extern struct pci_ops marvel_pci_ops;
+extern void marvel_init_arch(void);
+extern void marvel_kill_arch(int);
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int marvel_pa_to_nid(unsigned long);
+extern int marvel_cpuid_to_nid(int);
+extern unsigned long marvel_node_mem_start(int);
+extern unsigned long marvel_node_mem_size(int);
+extern struct _alpha_agp_info *marvel_agp_info(void);
+struct io7 *marvel_find_io7(int pe);
+struct io7 *marvel_next_io7(struct io7 *prev);
+void io7_clear_errors(struct io7 *io7);
+
 /* core_mcpcia.c */
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
@@ -59,7 +77,7 @@
 extern struct pci_ops t2_pci_ops;
 extern void t2_init_arch(void);
 extern void t2_machine_check(u64, u64, struct pt_regs *);
-#define t2_pci_tbi ((void *)0)
+extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_titan.c */
 extern struct pci_ops titan_pci_ops;
@@ -67,6 +85,7 @@
 extern void titan_kill_arch(int);
 extern void titan_machine_check(u64, u64, struct pt_regs *);
 extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern struct _alpha_agp_info *titan_agp_info(void);
 
 /* core_tsunami.c */
 extern struct pci_ops tsunami_pci_ops;
@@ -81,13 +100,23 @@
 extern void wildfire_kill_arch(int);
 extern void wildfire_machine_check(u64, u64, struct pt_regs *);
 extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int wildfire_pa_to_nid(unsigned long);
+extern int wildfire_cpuid_to_nid(int);
+extern unsigned long wildfire_node_mem_start(int);
+extern unsigned long wildfire_node_mem_size(int);
 
 /* setup.c */
 extern unsigned long srm_hae;
 extern int boot_cpuid;
-extern int srmcons_output;
+
+/* srmcons.c */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 extern void register_srm_console(void);
 extern void unregister_srm_console(void);
+#else
+#define register_srm_console()
+#define unregister_srm_console()
+#endif
 
 /* smp.c */
 extern void setup_smp(void);
@@ -148,6 +177,10 @@
 extern void switch_to_system_map(void);
 extern void srm_paging_stop(void);
 
+/* ../mm/remap.c */
+extern int __alpha_remap_area_pages(unsigned long, unsigned long, 
+				    unsigned long, unsigned long);
+
 /* irq.c */
 
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/ptrace.c linux-2.4.21-rc3/arch/alpha/kernel/ptrace.c
--- linux-2.4.20/arch/alpha/kernel/ptrace.c	2001-09-19 00:03:51.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/ptrace.c	2003-05-22 22:06:51.000000000 +0000
@@ -102,7 +102,9 @@
 
 	if (regno == 30) {
 		addr = &task->thread.usp;
-	} else if (regno == 31 || regno > 64) {
+	} else if (regno == 65) {
+		addr = &task->thread.unique;
+	} else if (regno == 31 || regno > 65) {
 		zero = 0;
 		addr = &zero;
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/setup.c linux-2.4.21-rc3/arch/alpha/kernel/setup.c
--- linux-2.4.20/arch/alpha/kernel/setup.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/setup.c	2003-05-22 22:06:28.000000000 +0000
@@ -71,18 +71,25 @@
 
  * "srmcons" specified in the boot command arguments allows us to
  * see kernel messages during the period of time before the true
- * console device is "registered" during console_init(). As of this
- * version (2.4.10), time_init() is the last Alpha-specific code
- * called before console_init(), so we put "unregister" code
- * there to prevent schizophrenic console behavior later... ;-}
+ * console device is "registered" during console_init(). 
+ * As of this version (2.4.20), console_init() will call
+ * disable_early_printk() as the last action before initializing
+ * the console drivers. That's the last possible time srmcons can be 
+ * unregistered without interfering with console behavior.
  *
- * By default, OFF; set it with a bootcommand arg of "srmcons".
+ * By default, OFF; set it with a bootcommand arg of "srmcons" or 
+ * "console=srm". The meaning of these two args is:
+ *     "srmcons"     - early callback prints 
+ *     "console=srm" - full callback based console, including early prints
  */
 int srmcons_output = 0;
 
 /* Enforce a memory size limit; useful for testing. By default, none. */
 unsigned long mem_size_limit = 0;
 
+/* Set AGP GART window size (0 means disabled). */
+unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE;
+
 #ifdef CONFIG_ALPHA_GENERIC
 struct alpha_machine_vector alpha_mv;
 int alpha_using_srm;
@@ -147,6 +154,7 @@
 WEAK(eiger_mv);
 WEAK(jensen_mv);
 WEAK(lx164_mv);
+WEAK(marvel_ev7_mv);
 WEAK(miata_mv);
 WEAK(mikasa_mv);
 WEAK(mikasa_primo_mv);
@@ -166,6 +174,7 @@
 WEAK(shark_mv);
 WEAK(sx164_mv);
 WEAK(takara_mv);
+WEAK(titan_mv);
 WEAK(webbrick_mv);
 WEAK(wildfire_mv);
 WEAK(xl_mv);
@@ -243,6 +252,27 @@
         return end >> PAGE_SHIFT; /* Return the PFN of the limit. */
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void * __init
+move_initrd(unsigned long mem_limit)
+{
+	void *start;
+	unsigned long size;
+
+	size = initrd_end - initrd_start;
+	start = __alloc_bootmem(size, PAGE_SIZE, 0);
+	if (!start || __pa(start) + size > mem_limit) {
+		initrd_start = initrd_end = 0;
+		return NULL;
+	}
+	memmove(start, (void *)initrd_start, size);
+	initrd_start = (unsigned long)start;
+	initrd_end = initrd_start + size;
+	printk(KERN_INFO "initrd moved to %p\n", start);
+	return start;
+}
+#endif
+
 #ifndef CONFIG_DISCONTIGMEM
 static void __init
 setup_memory(void *kernel_end)
@@ -274,6 +304,24 @@
 			max_low_pfn = end;
 	}
 
+	/*
+	 * Except for the NUMA systems (wildfire, marvel) all of the 
+	 * Alpha systems we run on support 32GB of memory or less.
+	 * Since the NUMA systems introduce large holes in memory addressing,
+	 * we can get into a situation where there is not enough contiguous
+	 * memory for the memory map. 
+	 *
+	 * Limit memory to the first 32GB to limit the NUMA systems to 
+	 * memory on their first node (wildfire) or 2 (marvel) to avoid 
+	 * not being able to produce the memory map. In order to access 
+	 * all of the memory on the NUMA systems, build with discontiguous
+	 * memory support.
+	 *
+	 * If the user specified a memory limit, let that memory limit stand.
+	 */
+	if (!mem_size_limit) 
+		mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT;
+
 	if (mem_size_limit && max_low_pfn >= mem_size_limit)
 	{
 		printk("setup: forcing memory size to %ldK (from %ldK).\n",
@@ -371,11 +419,11 @@
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem(virt_to_phys((void *)initrd_start),
 					INITRD_SIZE);
@@ -412,57 +460,6 @@
 #undef PFN_PHYS
 #undef PFN_MAX
 
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
-/*
- *      Manage the SRM callbacks as a "console".
- */
-static struct console srmcons;
-
-void __init register_srm_console(void)
-{
-        register_console(&srmcons);
-}
-
-void __init unregister_srm_console(void)
-{
-        unregister_console(&srmcons);
-}
-
-static void srm_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-	srm_printk(s);
-}
-
-static kdev_t srm_console_device(struct console *c)
-{
-  /* Huh? */
-        return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static int __init srm_console_setup(struct console *co, char *options)
-{
-	return 1;
-}
-
-static struct console srmcons = {
-	name:		"srm0",
-	write:		srm_console_write,
-	device:		srm_console_device,
-	setup:		srm_console_setup,
-	flags:		CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
-	index:		-1,
-};
-
-#else
-void __init register_srm_console(void)
-{
-}
-void __init unregister_srm_console(void)
-{
-}
-#endif
-
 void __init
 setup_arch(char **cmdline_p)
 {
@@ -523,7 +520,16 @@
 			continue;
 		}
 		if (strncmp(p, "srmcons", 7) == 0) {
-			srmcons_output = 1;
+			srmcons_output |= 1;
+			continue;
+		}
+		if (strncmp(p, "console=srm", 11) == 0) {
+			srmcons_output |= 2;
+			continue;
+		}
+		if (strncmp(p, "gartsize=", 9) == 0) {
+			alpha_agpgart_size =
+				get_mem_size_limit(p+9) << PAGE_SHIFT;
 			continue;
 		}
 	}
@@ -534,6 +540,13 @@
 	/* If we want SRM console printk echoing early, do it now. */
 	if (alpha_using_srm && srmcons_output) {
 		register_srm_console();
+
+		/*
+		 * If "console=srm" was specified, clear the srmcons_output
+		 * flag now so that time.c won't unregister_srm_console
+		 */
+		if (srmcons_output & 2)
+			srmcons_output = 0;
 	}
 
 	/*
@@ -628,6 +641,15 @@
 	paging_init();
 }
 
+void __init
+disable_early_printk(void)
+{
+	if (alpha_using_srm && srmcons_output) {
+		unregister_srm_console();
+		srmcons_output = 0;
+	}
+}
+
 static char sys_unknown[] = "Unknown";
 static char systype_names[][16] = {
 	"0",
@@ -637,7 +659,7 @@
 	"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
 	"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
 	"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
-	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan"
+	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel"
 };
 
 static char unofficial_names[][8] = {"100", "Ruffian"};
@@ -656,15 +678,20 @@
 static char eb66_names[][8] = {"EB66", "EB66+"};
 static int eb66_indices[] = {0,0,1};
 
+static char marvel_names[][16] = {
+	"Marvel/EV7"
+};
+static int marvel_indices[] = { 0 };
+
 static char rawhide_names[][16] = {
 	"Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
 };
 static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
 
 static char titan_names[][16] = {
-	"0", "Privateer"
+	"DEFAULT", "Privateer", "Falcon", "Granite"
 };
-static int titan_indices[] = {0,1};
+static int titan_indices[] = {0,1,2,2,3};
 
 static char tsunami_names[][16] = {
 	"0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper",
@@ -717,6 +744,7 @@
 		NULL,		/* CUSCO */
 		&eiger_mv,	/* Eiger */
 		NULL,		/* Titan */
+		NULL,		/* Marvel */
 	};
 
 	static struct alpha_machine_vector *unofficial_vecs[] __initdata =
@@ -754,10 +782,17 @@
 		&eb66p_mv
 	};
 
+	static struct alpha_machine_vector *marvel_vecs[] __initdata =
+	{
+		&marvel_ev7_mv,
+	};
+
 	static struct alpha_machine_vector *titan_vecs[] __initdata =
 	{
-		NULL,
+		&titan_mv,		/* default   */
 		&privateer_mv,		/* privateer */
+		&titan_mv,		/* falcon    */
+		&privateer_mv,		/* granite   */
 	};
 
 	static struct alpha_machine_vector *tsunami_vecs[]  __initdata =
@@ -826,7 +861,12 @@
 			if (member < N(eb66_indices))
 				vec = eb66_vecs[eb66_indices[member]];
 			break;
+		case ST_DEC_MARVEL:
+			if (member < N(marvel_indices))
+				vec = marvel_vecs[marvel_indices[member]];
+			break;
 		case ST_DEC_TITAN:
+			vec = titan_vecs[0];	/* default */
 			if (member < N(titan_indices))
 				vec = titan_vecs[titan_indices[member]];
 			break;
@@ -968,11 +1008,16 @@
 		if (member < N(eb66_indices))
 			*variation_name = eb66_names[eb66_indices[member]];
 		break;
+	case ST_DEC_MARVEL:
+		if (member < N(marvel_indices))
+			*variation_name = marvel_names[marvel_indices[member]];
+		break;
 	case ST_DEC_RAWHIDE:
 		if (member < N(rawhide_indices))
 			*variation_name = rawhide_names[rawhide_indices[member]];
 		break;
 	case ST_DEC_TITAN:
+		*variation_name = titan_names[0];	/* default */
 		if (member < N(titan_indices))
 			*variation_name = titan_names[titan_indices[member]];
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/smp.c linux-2.4.21-rc3/arch/alpha/kernel/smp.c
--- linux-2.4.20/arch/alpha/kernel/smp.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/smp.c	2003-05-22 22:06:39.000000000 +0000
@@ -77,11 +77,10 @@
 /* cpus reported in the hwrpb */
 static unsigned long hwrpb_cpu_present_mask __initdata = 0;
 
-static int max_cpus = -1;	/* Command-line limitation.  */
+static int max_cpus = NR_CPUS;	/* Command-line limitation.  */
 int smp_num_probed;		/* Internal processor count */
 int smp_num_cpus = 1;		/* Number that came online.  */
 int smp_threads_ready;		/* True once the per process idle is forked. */
-cycles_t cacheflush_time;
 
 int __cpu_number_map[NR_CPUS];
 int __cpu_logical_map[NR_CPUS];
@@ -104,7 +103,7 @@
 	return 1;
 }
 
-__setup("maxcpus", maxcpus);
+__setup("maxcpus=", maxcpus);
 
 
 /*
@@ -175,6 +174,9 @@
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer(cpuid);
 
+	/* Call platform-specific callin, if specified */
+	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
+
 	/* Must have completely accurate bogos.  */
 	__sti();
 
@@ -184,20 +186,20 @@
 	 */
 	wait_boot_cpu_to_stop(cpuid);
 	mb();
- try_again:
+
 	calibrate_delay();
 
 	smp_store_cpu_info(cpuid);
 
 	{
 #define LPJ(c) ((long)cpu_data[c].loops_per_jiffy)
-	  static int tries = 3;
 	  long diff = LPJ(boot_cpuid) - LPJ(cpuid);
 	  if (diff < 0) diff = -diff;
 				
-	  if (diff > LPJ(boot_cpuid)/10 && --tries) {
-	    printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid);
-	    goto try_again;
+	  if (diff > LPJ(boot_cpuid)/10) {
+	  	printk("Bogus BogoMIPS for cpu %d - trusting boot CPU\n",
+		       cpuid);
+		loops_per_jiffy = LPJ(cpuid) = LPJ(boot_cpuid);
 	  }
 	}
 
@@ -225,64 +227,6 @@
 	cpu_idle();
 }
 
-
-/*
- * Rough estimation for SMP scheduling, this is the number of cycles it
- * takes for a fully memory-limited process to flush the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-static void __init
-smp_tune_scheduling (int cpuid)
-{
-	struct percpu_struct *cpu;
-	unsigned long on_chip_cache;
-	unsigned long freq;
-
-	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
-				      + cpuid * hwrpb->processor_size);
-	switch (cpu->type)
-	{
-	case EV45_CPU:
-		on_chip_cache = 16 + 16;
-		break;
-
-	case EV5_CPU:
-	case EV56_CPU:
-		on_chip_cache = 8 + 8 + 96;
-		break;
-
-	case PCA56_CPU:
-		on_chip_cache = 16 + 8;
-		break;
-
-	case EV6_CPU:
-	case EV67_CPU:
-		on_chip_cache = 64 + 64;
-		break;
-
-	default:
-		on_chip_cache = 8 + 8;
-		break;
-	}
-
-	freq = hwrpb->cycle_freq ? : est_cycle_freq;
-
-#if 0
-	/* Magic estimation stolen from x86 port.  */
-	cacheflush_time = freq / 1024L * on_chip_cache / 5000L;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#else
-	/* Magic value to force potential preemption of other CPUs.  */
-	cacheflush_time = INT_MAX;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#endif
-}
-
 /*
  * Send a message to a secondary's console.  "START" is one such
  * interesting message.  ;-)
@@ -622,7 +566,6 @@
 	current->processor = boot_cpuid;
 
 	smp_store_cpu_info(boot_cpuid);
-	smp_tune_scheduling(boot_cpuid);
 	smp_setup_percpu_timer(boot_cpuid);
 
 	init_idle();
@@ -641,6 +584,9 @@
 
 	cpu_count = 1;
 	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_count >= max_cpus)
+			break;
+
 		if (i == boot_cpuid)
 			continue;
 
@@ -666,8 +612,8 @@
 	}
 	printk(KERN_INFO "SMP: Total of %d processors activated "
 	       "(%lu.%02lu BogoMIPS).\n",
-	       cpu_count, (bogosum + 2500) / (500000/HZ),
-	       ((bogosum + 2500) / (5000/HZ)) % 100);
+	       cpu_count, bogosum / (500000/HZ),
+	       (bogosum / (5000/HZ)) % 100);
 
 	smp_num_cpus = cpu_count;
 }
@@ -922,11 +868,36 @@
 	       && time_before (jiffies, timeout))
 		barrier();
 
-	/* We either got one or timed out -- clear the lock.  */
+	/* If there's no response yet, log a message but allow a longer
+	 * timeout period -- if we get a response this time, log
+	 * a message saying when we got it.. 
+	 */
+	if (atomic_read(&data.unstarted_count) > 0) {
+		long start_time = jiffies;
+		printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
+		       __FUNCTION__);
+		timeout = jiffies + 30 * HZ;
+		while (atomic_read(&data.unstarted_count) > 0
+		       && time_before(jiffies, timeout))
+			barrier();
+		if (atomic_read(&data.unstarted_count) <= 0) {
+			long delta = jiffies - start_time;
+			printk(KERN_ERR 
+			       "%s: response %ld.%ld seconds into long wait\n",
+			       __FUNCTION__, delta / HZ,
+			       (100 * (delta - ((delta / HZ) * HZ))) / HZ);
+		}
+	}
+
+	/* We either got one or timed out -- clear the lock. */
 	mb();
 	smp_call_function_data = 0;
-	if (atomic_read (&data.unstarted_count) > 0)
-		return -ETIMEDOUT;
+
+	/* 
+	 * If after both the initial and long timeout periods we still don't
+	 * have a response, something is very wrong...
+	 */
+	BUG_ON(atomic_read (&data.unstarted_count) > 0);
 
 	/* Wait for a complete response, if needed.  */
 	if (wait) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/srmcons.c linux-2.4.21-rc3/arch/alpha/kernel/srmcons.c
--- linux-2.4.20/arch/alpha/kernel/srmcons.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/srmcons.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,361 @@
+/*
+ *	linux/arch/alpha/kernel/srmcons.c
+ *
+ * Callback based driver for SRM Console console device.
+ * (TTY driver and console driver)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <asm/console.h>
+#include <asm/uaccess.h>
+
+
+static spinlock_t srmcons_callback_lock = SPIN_LOCK_UNLOCKED;
+static int srm_is_registered_console = 0;
+
+/* 
+ * The TTY driver
+ */
+#define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
+
+static int srmcons_refcount;
+static struct tty_struct *srmcons_table[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios_locked[MAX_SRM_CONSOLE_DEVICES];
+
+struct srmcons_private {
+	struct tty_struct *tty;
+	struct timer_list timer;
+	spinlock_t lock;
+};
+
+typedef union _srmcons_result {
+	struct {
+		unsigned long c :61;
+		unsigned long status :3;
+	} bits;
+	long as_long;
+} srmcons_result;
+
+/* called with callback_lock held */
+static int
+srmcons_do_receive_chars(struct tty_struct *tty)
+{
+	srmcons_result result;
+	int count = 0, loops = 0;
+
+	do {
+		result.as_long = callback_getc(0);
+		if (result.bits.status < 2) {
+			tty_insert_flip_char(tty, (char)result.bits.c, 0);
+			count++;
+		}
+	} while((result.bits.status & 1) && (++loops < 10));
+
+	if (count)
+		tty_schedule_flip(tty);
+
+	return count;
+}
+
+static void
+srmcons_receive_chars(unsigned long data)
+{
+	struct srmcons_private *srmconsp = (struct srmcons_private *)data;
+	unsigned long flags;
+	int incr = 10;
+
+	local_irq_save(flags);
+	if (spin_trylock(&srmcons_callback_lock)) {
+		if (!srmcons_do_receive_chars(srmconsp->tty))
+			incr = 100;
+		spin_unlock(&srmcons_callback_lock);
+	} 
+
+	spin_lock(&srmconsp->lock);
+	if (srmconsp->tty) {
+		srmconsp->timer.expires = jiffies + incr;
+		add_timer(&srmconsp->timer);
+	}
+	spin_unlock(&srmconsp->lock);
+
+	local_irq_restore(flags);
+}
+
+/* called with callback_lock held */
+static int
+srmcons_do_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	unsigned char *str_cr = "\r";
+	long c, remaining = count;
+	srmcons_result result;
+	unsigned char *cur;
+	int need_cr;
+
+	for (cur = (unsigned char *)buf; remaining > 0; ) {
+		need_cr = 0;
+		/* 
+		 * Break it up into reasonable size chunks to allow a chance
+		 * for input to get in
+		 */
+		for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
+			if (cur[c] == '\n')
+				need_cr = 1;
+		
+		while (c > 0) {
+			result.as_long = callback_puts(0, cur, c);
+			c -= result.bits.c;
+			remaining -= result.bits.c;
+			cur += result.bits.c;
+
+			/*
+			 * Check for pending input iff a tty was provided
+			 */
+			if (tty)
+				srmcons_do_receive_chars(tty);
+		}
+
+		while (need_cr) {
+			result.as_long = callback_puts(0, str_cr, 1);
+			if (result.bits.c > 0)
+				need_cr = 0;
+		}
+	}
+	return count;
+}
+
+static int
+srmcons_write(struct tty_struct *tty, int from_user,
+	      const unsigned char *buf, int count)
+{
+	unsigned long flags;
+
+	if (from_user) {
+		unsigned char tmp[512];
+		int ret = 0;
+		size_t c;
+
+		while ((c = count) > 0) {
+			if (c > sizeof(tmp))
+				c = sizeof(tmp);
+			
+			c -= copy_from_user(tmp, buf, c);
+
+			if (!c) { 
+				printk("%s: EFAULT (count %d)\n",
+				       __FUNCTION__, count);
+				return -EFAULT;
+			}
+
+			spin_lock_irqsave(&srmcons_callback_lock, flags);
+			srmcons_do_write(tty, tmp, c);
+			spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+
+		return ret;
+	}
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(tty, buf, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+	return count;
+}
+
+static int
+srmcons_write_room(struct tty_struct *tty)
+{
+	return 512;
+}
+
+static int
+srmcons_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;
+}
+
+static int
+srmcons_get_private_struct(struct srmcons_private **ps)
+{
+	static struct srmcons_private *srmconsp = NULL;
+	static spinlock_t srmconsp_lock = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+	int retval = 0;
+
+	spin_lock_irqsave(&srmconsp_lock, flags);
+
+	do {
+		if (srmconsp != NULL) {
+			*ps = srmconsp;
+			break;
+		}
+
+		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
+		if (srmconsp == NULL) {
+			retval = -ENOMEM;
+			break;
+		}
+
+		srmconsp->tty = NULL;
+		srmconsp->lock = SPIN_LOCK_UNLOCKED;
+		init_timer(&srmconsp->timer);
+
+		*ps = srmconsp;
+	} while(0);
+
+	spin_unlock_irqrestore(&srmconsp_lock, flags);
+
+	return retval;
+}
+
+static int
+srmcons_open(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp;
+	unsigned long flags;
+	int retval;
+
+	retval = srmcons_get_private_struct(&srmconsp);
+	if (retval)
+		return retval;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (!srmconsp->tty) {
+		tty->driver_data = srmconsp;
+
+		srmconsp->tty = tty;
+		srmconsp->timer.function = srmcons_receive_chars;
+		srmconsp->timer.data = (unsigned long)srmconsp;
+		srmconsp->timer.expires = jiffies + 10;
+		add_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+
+	return 0;
+}
+
+static void
+srmcons_close(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp = tty->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (tty->count == 1) {
+		srmconsp->tty = NULL;
+		del_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+}
+
+
+static struct tty_driver srmcons_driver = {
+	.driver_name	= "srm",
+	.name		= "srm",
+	.magic		= TTY_DRIVER_MAGIC,
+	.major		= 0, 	/* dynamic */
+	.minor_start	= 0,
+	.num		= MAX_SRM_CONSOLE_DEVICES,
+	.type		= TTY_DRIVER_TYPE_SYSTEM,
+	.subtype	= SYSTEM_TYPE_SYSCONS,
+
+	.table		= srmcons_table,
+	.termios	= srmcons_termios,
+	.termios_locked	= srmcons_termios_locked,
+	.refcount	= &srmcons_refcount,
+
+	.open		= srmcons_open,
+	.close		= srmcons_close,
+	.write		= srmcons_write,
+	.write_room	= srmcons_write_room,
+	.chars_in_buffer= srmcons_chars_in_buffer,
+};
+
+static int __init
+srmcons_init(void)
+{
+	if (srm_is_registered_console) {
+		srmcons_driver.init_termios = tty_std_termios;
+		return tty_register_driver(&srmcons_driver);
+	}
+
+	return -ENODEV;
+}
+
+module_init(srmcons_init);
+
+
+/*
+ * The console driver
+ */
+static void
+srm_console_write(struct console *co, const char *s, unsigned count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(NULL, s, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+}
+
+static kdev_t
+srm_console_device(struct console *co)
+{
+	return mk_kdev(srmcons_driver.major,
+		       srmcons_driver.minor_start + co->index);
+}
+
+static int __init
+srm_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+static struct console srmcons = {
+	.name		= "srm",
+	.write		= srm_console_write,
+	.device		= srm_console_device,
+	.setup		= srm_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+void __init
+register_srm_console(void)
+{
+	if (!srm_is_registered_console) {
+		callback_open_console();
+		register_console(&srmcons);
+		srm_is_registered_console = 1;
+	}
+}
+
+void __init
+unregister_srm_console(void)
+{
+	if (srm_is_registered_console) {
+		callback_close_console();
+		unregister_console(&srmcons);
+		srm_is_registered_console = 0;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_alcor.c linux-2.4.21-rc3/arch/alpha/kernel/sys_alcor.c
--- linux-2.4.20/arch/alpha/kernel/sys_alcor.c	2001-06-27 23:18:13.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_alcor.c	2003-05-22 22:06:42.000000000 +0000
@@ -220,6 +220,8 @@
 static void
 alcor_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineer's have no sense of humor? ;-)  */
@@ -250,7 +252,7 @@
 	DO_CIA_IO,
 	DO_CIA_BUS,
 	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_ALCOR_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_cabriolet.c linux-2.4.21-rc3/arch/alpha/kernel/sys_cabriolet.c
--- linux-2.4.20/arch/alpha/kernel/sys_cabriolet.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_cabriolet.c	2003-05-22 22:06:39.000000000 +0000
@@ -365,6 +365,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_cab_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		cabriolet_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -416,6 +417,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -441,6 +443,7 @@
 	init_irq:		pc164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_marvel.c linux-2.4.21-rc3/arch/alpha/kernel/sys_marvel.c
--- linux-2.4.20/arch/alpha/kernel/sys_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_marvel.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,499 @@
+/*
+ * linux/arch/alpha/kernel/sys_marvel.c
+ *
+ * Marvel / IO7 support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+
+#include "proto.h"
+#include "err_impl.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+
+#if NR_IRQS < MARVEL_NR_IRQS
+# error NR_IRQS < MARVEL_NR_IRQS !!!
+#endif
+
+
+/*
+ * Interrupt handling.
+ */
+static void 
+io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+	unsigned int pid;
+	unsigned int irq;
+
+	/*
+	 * Vector is 0x800 + (interrupt)
+	 *
+	 * where (interrupt) is:
+	 *
+	 *	...16|15 14|13     4|3 0
+	 *	-----+-----+--------+---
+	 *	  PE |  0  |   irq  | 0
+	 *
+	 * where (irq) is 
+	 *
+	 *       0x0800 - 0x0ff0	 - 0x0800 + (LSI id << 4)
+	 *	 0x1000 - 0x2ff0	 - 0x1000 + (MSI_DAT<8:0> << 4)
+	 */
+	pid = vector >> 16;
+	irq = ((vector & 0xffff) - 0x800) >> 4;
+
+	irq += 16;				/* offset for legacy */
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;		/* not too many bits */
+	irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	handle_irq(irq, regs);
+}
+
+static volatile unsigned long *
+io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
+{
+	volatile unsigned long *ctl;
+	unsigned int pid;
+	struct io7 *io7;
+
+	pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
+
+	if (!(io7 = marvel_find_io7(pid))) {
+		printk(KERN_ERR 
+		       "%s for nonexistent io7 -- vec %x, pid %d\n",
+		       __FUNCTION__, irq, pid);
+		return NULL;
+	}
+
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;	/* isolate the vector    */
+	irq -= 16;			/* subtract legacy bias  */
+
+	if (irq >= 0x180) {
+		printk(KERN_ERR 
+		       "%s for invalid irq -- pid %d adjusted irq %x\n",
+		       __FUNCTION__, pid, irq);
+		return NULL;
+	}
+
+	ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
+	if (irq >= 0x80)	     	/* MSI */
+		ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
+
+	if (pio7) *pio7 = io7;
+	return ctl;
+}
+
+static void
+io7_enable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl |= 1UL << 24;
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static void
+io7_disable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl &= ~(1UL << 24);
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static unsigned int
+io7_startup_irq(unsigned int irq)
+{
+	io7_enable_irq(irq);
+	return 0;	/* never anything pending */
+}
+
+static void
+io7_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		io7_enable_irq(irq);
+}
+
+static void
+marvel_irq_noop(unsigned int irq) 
+{ 
+	return; 
+}
+
+static unsigned int
+marvel_irq_noop_return(unsigned int irq) 
+{ 
+	return 0; 
+}
+
+static struct hw_interrupt_type marvel_legacy_irq_type = {
+	typename:	"LEGACY",
+	startup:	marvel_irq_noop_return,
+	shutdown:	marvel_irq_noop,
+	enable:		marvel_irq_noop,
+	disable:	marvel_irq_noop,
+	ack:		marvel_irq_noop,
+	end:		marvel_irq_noop,
+};
+
+static struct hw_interrupt_type io7_lsi_irq_type = {
+	typename:	"LSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		io7_disable_irq,
+	end:		io7_end_irq,
+};
+
+static struct hw_interrupt_type io7_msi_irq_type = {
+	typename:	"MSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		marvel_irq_noop,
+	end:		io7_end_irq,
+};
+
+static void
+io7_redirect_irq(struct io7 *io7, 
+		 volatile unsigned long *csr, 
+		 unsigned int where)
+{
+	unsigned long val;
+	
+	val = *csr;
+	val &= ~(0x1ffUL << 24);		/* clear the target pid   */
+	val |= ((unsigned long)where << 24);	/* set the new target pid */
+	
+	*csr = val;
+	mb();
+	*csr;
+}
+
+static void 
+io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_LSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_LSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void 
+io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_MSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_MSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_io7_irqs(struct io7 *io7, 
+	      struct hw_interrupt_type *lsi_ops,
+	      struct hw_interrupt_type *msi_ops)
+{
+	long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
+	long i;
+
+	printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
+		io7->pe, base);
+
+	/*
+	 * Where should interrupts from this IO7 go?
+	 *
+	 * They really should be sent to the local CPU to avoid having to
+	 * traverse the mesh, but if it's not an SMP kernel, they have to
+	 * go to the boot CPU. Send them all to the boot CPU for now,
+	 * as each secondary starts, it can redirect it's local device
+	 * interrupts.
+	 */
+	printk("  Interrupts reported to CPU at PE %u\n", boot_cpuid);
+
+	spin_lock(&io7->irq_lock);
+
+	/* set up the error irqs */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
+
+	/* Set up the lsi irqs.  */
+	for (i = 0; i < 128; ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = lsi_ops;
+	}
+
+	/* Disable the implemented irqs in hardware.  */
+	for (i = 0; i < 0x60; ++i) 
+		init_one_io7_lsi(io7, i, boot_cpuid);
+
+	init_one_io7_lsi(io7, 0x74, boot_cpuid);
+	init_one_io7_lsi(io7, 0x75, boot_cpuid);
+
+
+	/* Set up the msi irqs.  */
+	for (i = 128; i < (128 + 512); ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = msi_ops;
+	}
+
+	for (i = 0; i < 16; ++i)
+		init_one_io7_msi(io7, i, boot_cpuid);
+
+	spin_unlock(&io7->irq_lock);
+}
+
+static void __init
+marvel_init_irq(void)
+{
+	int i;
+	struct io7 *io7 = NULL;
+
+	/* Reserve the legacy irqs.  */
+	for (i = 0; i < 16; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &marvel_legacy_irq_type;
+	}
+
+	/* Init the io7 irqs.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
+		init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
+}
+
+static int 
+marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pci_controller *hose = dev->sysdata;
+	struct io7_port *io7_port = hose->sysdata;
+	struct io7 *io7 = io7_port->io7;
+	int msi_loc, msi_data_off;
+	u16 msg_ctl;
+	u16 msg_dat;
+	u8 intline; 
+	int irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+	msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	msg_ctl = 0;
+	if (msi_loc) 
+		pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
+
+	if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
+ 		msi_data_off = PCI_MSI_DATA_32;
+		if (msg_ctl & PCI_MSI_FLAGS_64BIT) 
+			msi_data_off = PCI_MSI_DATA_64;
+		pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
+
+		irq = msg_dat & 0x1ff;		/* we use msg_data<8:0> */
+		irq += 0x80;			/* offset for lsi       */
+
+#if 1
+		printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
+		       dev->bus->number, 
+		       PCI_SLOT(dev->devfn), 
+		       PCI_FUNC(dev->devfn),
+		       hose->index,
+		       dev->name);
+		printk("  %d message(s) from 0x%04x\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       msg_dat);
+		printk("  reporting on %d IRQ(s) from %d (0x%x)\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
+#endif
+
+#if 0
+		pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
+				      msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+		irq = intline;
+
+		printk("  forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
+#endif
+	}
+
+	irq += 16;					/* offset for legacy */
+	irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	return irq; 
+}
+
+static void __init
+marvel_init_pci(void)
+{
+	struct io7 *io7;
+
+	marvel_register_error_handlers();
+
+	pci_probe_only = 1;
+	common_init_pci();
+
+#ifdef CONFIG_VGA_HOSE
+	locate_and_init_vga(NULL);
+#endif
+
+	/* Clear any io7 errors.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) 
+		io7_clear_errors(io7);
+}
+
+static void
+marvel_init_rtc(void)
+{
+	init_rtc_irq();
+}
+
+static void
+marvel_smp_callin(void)
+{
+	int cpuid = hard_smp_processor_id();
+	struct io7 *io7 = marvel_find_io7(cpuid);
+	unsigned int i;
+
+	if (!io7)
+		return;
+
+	/* 
+	 * There is a local IO7 - redirect all of it's interrupts here.
+	 */
+	printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
+
+	/* Redirect the error IRQS here.  */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
+
+	/* Redirect the implemented LSIs here.  */
+	for (i = 0; i < 0x60; ++i) 
+		io7_redirect_one_lsi(io7, i, cpuid);
+
+	io7_redirect_one_lsi(io7, 0x74, cpuid);
+	io7_redirect_one_lsi(io7, 0x75, cpuid);
+
+	/* Redirect the MSIs here.  */
+	for (i = 0; i < 16; ++i)
+		io7_redirect_one_msi(io7, i, cpuid);
+}
+
+/*
+ * System Vectors
+ */
+struct alpha_machine_vector marvel_ev7_mv __initmv = {
+	vector_name:		"MARVEL/EV7",
+	DO_EV7_MMU,
+	DO_DEFAULT_RTC,
+	DO_MARVEL_IO,
+	DO_MARVEL_BUS,
+	machine_check:		marvel_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		IO7_DAC_OFFSET,
+
+	nr_irqs:		MARVEL_NR_IRQS,
+	device_interrupt:	io7_device_interrupt,
+
+	agp_info:		marvel_agp_info,
+
+	smp_callin:		marvel_smp_callin,
+	init_arch:		marvel_init_arch,
+	init_irq:		marvel_init_irq,
+	init_rtc:		marvel_init_rtc,
+	init_pci:		marvel_init_pci,
+	kill_arch:		marvel_kill_arch,
+	pci_map_irq:		marvel_map_irq,
+	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		marvel_pa_to_nid,
+	cpuid_to_nid:		marvel_cpuid_to_nid,
+	node_mem_start:		marvel_node_mem_start,
+	node_mem_size:		marvel_node_mem_size,
+};
+ALIAS_MV(marvel_ev7)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_miata.c linux-2.4.21-rc3/arch/alpha/kernel/sys_miata.c
--- linux-2.4.20/arch/alpha/kernel/sys_miata.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_miata.c	2003-05-22 22:06:47.000000000 +0000
@@ -245,6 +245,8 @@
 static void
 miata_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineers have no sense of humor? ;-)  */ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_mikasa.c linux-2.4.21-rc3/arch/alpha/kernel/sys_mikasa.c
--- linux-2.4.20/arch/alpha/kernel/sys_mikasa.c	2000-10-27 17:55:01.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_mikasa.c	2003-05-22 22:06:51.000000000 +0000
@@ -259,6 +259,7 @@
 	init_irq:		mikasa_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		mikasa_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_nautilus.c linux-2.4.21-rc3/arch/alpha/kernel/sys_nautilus.c
--- linux-2.4.20/arch/alpha/kernel/sys_nautilus.c	2001-05-21 20:40:39.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_nautilus.c	2003-05-22 22:06:41.000000000 +0000
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/reboot.h>
+#include <linux/bootmem.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -45,6 +46,7 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
+#include "err_impl.h"
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
@@ -99,324 +101,12 @@
 	}
 }
 
-/* Machine check handler code
- *
- * Perform analysis of a machine check that was triggered by the EV6
- * CPU's fault-detection mechanism.
- */
-
-/* IPR structures for EV6, containing the necessary data for the
- * machine check handler to unpick the logout frame
- */
-
-/* I_STAT */
-
-#define EV6__I_STAT__PAR                ( 1 << 29 )
-
-/* MM_STAT */
-
-#define EV6__MM_STAT__DC_TAG_PERR       ( 1 << 10 )
-
-/* DC_STAT */
-
-#define EV6__DC_STAT__SEO               ( 1 << 4 )
-#define EV6__DC_STAT__ECC_ERR_LD        ( 1 << 3 )
-#define EV6__DC_STAT__ECC_ERR_ST        ( 1 << 2 )
-#define EV6__DC_STAT__TPERR_P1          ( 1 << 1 )
-#define EV6__DC_STAT__TPERR_P0          ( 1      )
-
-/* C_STAT */
-
-#define EV6__C_STAT__BC_PERR            ( 0x01 )
-#define EV6__C_STAT__DC_PERR            ( 0x02 )
-#define EV6__C_STAT__DSTREAM_MEM_ERR    ( 0x03 )
-#define EV6__C_STAT__DSTREAM_BC_ERR     ( 0x04 )
-#define EV6__C_STAT__DSTREAM_DC_ERR     ( 0x05 )
-#define EV6__C_STAT__PROBE_BC_ERR0      ( 0x06 )
-#define EV6__C_STAT__PROBE_BC_ERR1      ( 0x07 )
-#define EV6__C_STAT__ISTREAM_MEM_ERR    ( 0x0B )
-#define EV6__C_STAT__ISTREAM_BC_ERR     ( 0x0C )
-#define EV6__C_STAT__DSTREAM_MEM_DBL    ( 0x13 )
-#define EV6__C_STAT__DSTREAM_BC_DBL     ( 0x14 )
-#define EV6__C_STAT__ISTREAM_MEM_DBL    ( 0x1B )
-#define EV6__C_STAT__ISTREAM_BC_DBL     ( 0x1C )
-
-
-/* Take the two syndromes from the CBOX error chain and convert them
- * into a bit number.  */
-
-/* NOTE - since I don't know of any difference between C0 and C1 I
-   just ignore C1, since in all cases I've seen so far they are
-   identical.  */
-
-static const unsigned char ev6_bit_to_syndrome[72] =
-{
-	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,     /* 0 */
-	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,     /* 8 */
-	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,     /* 16 */
-	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,     /* 24 */
-	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,     /* 32 */
-	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,     /* 40 */
-	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,     /* 48 */
-	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,     /* 56 */
-	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80      /* 64 */
-};
-
-
-static int ev6_syn2bit(unsigned long c0, unsigned long c1)
-{
-	int bit;
-
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c0)	return bit;
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c1)	return bit + 64;
-
-	return -1;                  /* not found */
-}
-
-
-/* Single bit ECC errors are categorized here.  */
-
-#if 0
-static const char *interr = "CPU internal error";
-static const char *slotb= "Slot-B error";
-static const char *membus= "Memory/EV6-bus error";
-#else
-static const char *interr = "";
-static const char *slotb = "";
-static const char *membus = "";
-#endif
-
-static void
-ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Icache data or tag parity error.  */
-	if (L->I_STAT & EV6__I_STAT__PAR) {
-		sprintf(interp, "%s: I_STAT[PAR]\n "
-			"Icache data or tag parity error", interr);
-		return;
-	}
-
-	/* Dcache tag parity error (on issue) (DFAULT).  */
-	if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) {
-		sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n "
-			"Dcache tag parity error(on issue)", interr);
-		return;
-	}
-
-	/* Errors relating to D-stream set non-zero DC_STAT.
-	   Mask CRD bits.  */
-	switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST
-			      | EV6__DC_STAT__ECC_ERR_LD)) {
-	case EV6__DC_STAT__ECC_ERR_ST:
-		/* Dcache single-bit ECC error on small store */
-		sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n "
-			"Dcache single-bit ECC error on small store", interr);
-		return;
-
-	case EV6__DC_STAT__ECC_ERR_LD:
-		switch (L->C_STAT) {
-		case 0:
-			/* Dcache single-bit error on speculative load */
-			/* Bcache victim read on Dcache/Bcache miss */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n "
-				"Dcache single-bit ECC error on speculative load",
-				slotb);
-			return;
-
-		case EV6__C_STAT__DSTREAM_DC_ERR:
-			/* Dcache single bit error on load */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n"
-				" Dcache single-bit ECC error on speculative load, bit %d",
-				interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_BC_ERR:
-			/* Bcache single-bit error on Dcache fill */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n"
-				" Bcache single-bit error on Dcache fill, bit %d",
-				slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_MEM_ERR:
-			/* Memory single-bit error on Dcache fill */
-			sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] "
-				"C_STAT[DSTREAM_MEM_ERR]\n "
-				"Memory single-bit error on Dcache fill, "
-				"Address 0x%lX, bit %d",
-				membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-							       L->DC1_SYNDROME));
-			return;
-		}
-	}
-
-	/* I-stream, other misc errors go on C_STAT alone */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill, bit %d",
-			slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill "
-			"addr 0x%lX, bit %d",
-			membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						       L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__PROBE_BC_ERR0:
-	case EV6__C_STAT__PROBE_BC_ERR1:
-		/* Bcache single-bit error on a probe hit */
-		sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n "
-			"Bcache single-bit error on a probe hit, "
-			"addr 0x%lx, bit %d",
-			slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						      L->DC1_SYNDROME));
-		return;
-	}
-}
-
-static void
-ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Machine check errors described by DC_STAT */
-	switch (L->DC_STAT) {
-	case EV6__DC_STAT__TPERR_P0:
-	case EV6__DC_STAT__TPERR_P1:
-		/* Dcache tag parity error (on retry) */
-		sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n "
-			"Dcache tag parity error(on retry)", interr);
-		return;
-
-	case EV6__DC_STAT__SEO:
-		/* Dcache second error on store */
-		sprintf(interp, "%s: DC_STAT[SEO]\n "
-			"Dcache second error during mcheck", interr);
-		return;
-	}
-
-	/* Machine check errors described by C_STAT */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__DC_PERR:
-		/* Dcache duplicate tag parity error */
-		sprintf(interp, "%s: C_STAT[DC_PERR]\n "
-			"Dcache duplicate tag parity error at 0x%lX",
-			interr, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__BC_PERR:
-		/* Bcache tag parity error */
-		sprintf(interp, "%s: C_STAT[BC_PERR]\n "
-			"Bcache tag parity error at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill 0x%lX bit %d",
-			slotb, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill 0x%lX, bit %d",
-			membus, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_BC_DBL:
-		/* Bcache double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Icache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-	case EV6__C_STAT__DSTREAM_BC_DBL:
-		/* Bcache double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Dcache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_DBL:
-		/* Memory double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Icache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__DSTREAM_MEM_DBL:
-		/* Memory double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Dcache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-	}
-}
-
-static void
-ev6_cpu_machine_check(unsigned long vector, struct el_common_EV6_mcheck *L,
-		      struct pt_regs *regs)
-{
-	char interp[80];
-
-	/* This is verbose and looks intimidating.  Should it be printed for
-	   corrected (CRD) machine checks? */
-
-	printk(KERN_CRIT "PALcode logout frame:  "
-	       "MCHK_Code       %d  "
-	       "MCHK_Frame_Rev  %d\n"
-	       "I_STAT  %016lx  "
-	       "DC_STAT %016lx  "
-	       "C_ADDR  %016lx\n"
-	       "SYND1   %016lx  "
-	       "SYND0   %016lx  "
-	       "C_STAT  %016lx\n"
-	       "C_STS   %016lx  "
-	       "RES     %016lx  "
-	       "EXC_ADDR%016lx\n"
-	       "IER_CM  %016lx  "
-	       "ISUM    %016lx  "
-	       "MM_STAT %016lx\n"
-	       "PALBASE %016lx  "
-	       "I_CTL   %016lx  "
-	       "PCTX    %016lx\n"
-	       "CPU registers: "
-	       "PC      %016lx  "
-	       "Return  %016lx\n",
-	       L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT,
-	       L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT,
-	       L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM,
-	       L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX,
-	       regs->pc, regs->r26);
-
-	/* Attempt an interpretation on the meanings of the fields above.  */
-	sprintf(interp, "No interpretation available!" );
-	if (vector == SCB_Q_PROCERR)
-		ev6_crd_interp(interp, L);
-	else if (vector == SCB_Q_PROCMCHK)
-		ev6_mchk_interp(interp, L);
-
-	printk(KERN_CRIT "interpretation: %s\n\n", interp);
-}
-
-
 /* Perform analysis of a machine check that arrived from the system (NMI) */
 
 static void
 naut_sys_machine_check(unsigned long vector, unsigned long la_ptr,
 		       struct pt_regs *regs)
 {
-	printk("xtime %lx\n", CURRENT_TIME);
 	printk("PC %lx RA %lx\n", regs->pc, regs->r26);
 	irongate_pci_clr_err();
 }
@@ -429,7 +119,6 @@
 		       struct pt_regs *regs)
 {
 	char *mchk_class;
-	unsigned cpu_analysis=0, sys_analysis=0;
 
 	/* Now for some analysis.  Machine checks fall into two classes --
 	   those picked up by the system, and those picked up by the CPU.
@@ -462,39 +151,20 @@
 		return;
 	}
 
-	switch (vector) {
-	case SCB_Q_SYSERR:
-		mchk_class = "Correctable System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-	case SCB_Q_SYSMCHK:
-		mchk_class = "Fatal System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-
-	case SCB_Q_PROCERR:
-		mchk_class = "Correctable Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-	case SCB_Q_PROCMCHK:
-		mchk_class = "Fatal Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-
-	default:
-		mchk_class = "Unknown vector!";
-		break;
+	if (vector == SCB_Q_SYSERR)
+		mchk_class = "Correctable";
+	else if (vector == SCB_Q_SYSMCHK)
+		mchk_class = "Fatal";
+	else {
+		ev6_machine_check(vector, la_ptr, regs);
+		return;
 	}
 
-	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx [%s]\n",
+	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx "
+			 "[%s System Machine Check (NMI)]\n",
 	       vector, mchk_class);
 
-	if (cpu_analysis)
-		ev6_cpu_machine_check(vector,
-				      (struct el_common_EV6_mcheck *)la_ptr,
-				      regs);
-	if (sys_analysis)
-		naut_sys_machine_check(vector, la_ptr, regs);
+	naut_sys_machine_check(vector, la_ptr, regs);
 
 	/* Tell the PALcode to clear the machine check */
 	draina();
@@ -503,6 +173,69 @@
 }
 
 
+extern void free_reserved_mem(void *, void *);
+extern void pbus_size_bridges(struct pci_bus *);
+extern void pbus_assign_resources(struct pci_bus *);
+
+static struct resource irongate_mem = {
+	.name	= "Irongate PCI MEM",
+	.flags	= IORESOURCE_MEM,
+};
+
+void __init
+nautilus_init_pci(void)
+{
+	struct pci_controller *hose = hose_head;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	unsigned long bus_align, bus_size, pci_mem;
+	unsigned long memtop = max_low_pfn << PAGE_SHIFT;
+
+	/* Scan our single hose.  */
+	bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
+	hose->bus = bus;
+	hose->last_busno = bus->subordinate;
+
+	bus->self = pci_find_slot(0, 0);
+	bus->resource[1] = &irongate_mem;
+
+	pbus_size_bridges(bus);
+
+	/* IO port range. */
+	bus->resource[0]->start = 0;
+	bus->resource[0]->end = 0xffff;
+
+	/* Set up PCI memory range - limit is hardwired to 0xffffffff,
+	   base must be at aligned to 16Mb. */
+	bus_align = bus->resource[1]->start;
+	bus_size = bus->resource[1]->end + 1 - bus_align;
+	if (bus_align < 0x1000000UL)
+		bus_align = 0x1000000UL;
+
+	pci_mem = (0x100000000UL - bus_size) & -bus_align;
+
+	bus->resource[1]->start = pci_mem;
+	bus->resource[1]->end = 0xffffffffUL;
+	if (request_resource(&iomem_resource, bus->resource[1]) < 0)
+		printk(KERN_ERR "Failed to request MEM on hose 0\n");
+
+	if (pci_mem < memtop && pci_mem > alpha_mv.min_mem_address) {
+		free_reserved_mem(__va(alpha_mv.min_mem_address),
+				  __va(pci_mem));
+		printk("nautilus_init_pci: %ldk freed\n",
+			(pci_mem - alpha_mv.min_mem_address) >> 10);
+	}
+
+	if ((IRONGATE0->dev_vendor >> 16) > 0x7006)	/* Albacore? */
+		IRONGATE0->pci_mem = pci_mem;
+
+	pbus_assign_resources(bus);
+
+	pci_for_each_dev(dev) {
+		pdev_enable_device(dev);
+	}
+	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
+}
 
 /*
  * The System Vectors
@@ -525,7 +258,7 @@
 	init_arch:		irongate_init_arch,
 	init_irq:		nautilus_init_irq,
 	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
+	init_pci:		nautilus_init_pci,
 	kill_arch:		nautilus_kill_arch,
 	pci_map_irq:		nautilus_map_irq,
 	pci_swizzle:		common_swizzle,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_ruffian.c linux-2.4.21-rc3/arch/alpha/kernel/sys_ruffian.c
--- linux-2.4.20/arch/alpha/kernel/sys_ruffian.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_ruffian.c	2003-05-22 22:06:48.000000000 +0000
@@ -84,6 +84,7 @@
 static void
 ruffian_kill_arch (int mode)
 {
+	cia_kill_arch(mode);
 #if 0
 	/* This only causes re-entry to ARCSBIOS */
 	/* Perhaps this works for other PYXIS as well?  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_sable.c linux-2.4.21-rc3/arch/alpha/kernel/sys_sable.c
--- linux-2.4.20/arch/alpha/kernel/sys_sable.c	2001-06-12 18:44:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_sable.c	2003-05-22 22:06:26.000000000 +0000
@@ -289,9 +289,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
@@ -321,9 +321,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_sx164.c linux-2.4.21-rc3/arch/alpha/kernel/sys_sx164.c
--- linux-2.4.20/arch/alpha/kernel/sys_sx164.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_sx164.c	2003-05-22 22:06:43.000000000 +0000
@@ -171,7 +171,7 @@
 	init_irq:		sx164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		sx164_init_pci,
-	kill_arch:		NULL,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		sx164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_titan.c linux-2.4.21-rc3/arch/alpha/kernel/sys_titan.c
--- linux-2.4.20/arch/alpha/kernel/sys_titan.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_titan.c	2003-05-22 22:06:52.000000000 +0000
@@ -8,6 +8,8 @@
  *
  * Code supporting TITAN systems (EV6+TITAN), currently:
  *      Privateer
+ *	Falcon
+ *	Granite
  */
 
 #include <linux/config.h>
@@ -33,12 +35,26 @@
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
+#include "err_impl.h"
 
-/* Note mask bit is true for ENABLED irqs. */
-static unsigned long cached_irq_mask;
-/* Titan boards handle at most four CPUs.  */
-static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
+
+/*
+ * Titan generic
+ */
+
+/*
+ * Titan supports up to 4 CPUs
+ */
+static unsigned long titan_cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
 
+/*
+ * Mask is set (1) if enabled
+ */
+static unsigned long titan_cached_irq_mask;
+
+/*
+ * Need SMP-safe access to interrupt CSRs
+ */
 spinlock_t titan_irq_lock = SPIN_LOCK_UNLOCKED;
 
 static void
@@ -54,10 +70,10 @@
 	unsigned long mask0, mask1, mask2, mask3, dummy;
 
 	mask &= ~isa_enable;
-	mask0 = mask & cpu_irq_affinity[0];
-	mask1 = mask & cpu_irq_affinity[1];
-	mask2 = mask & cpu_irq_affinity[2];
-	mask3 = mask & cpu_irq_affinity[3];
+	mask0 = mask & titan_cpu_irq_affinity[0];
+	mask1 = mask & titan_cpu_irq_affinity[1];
+	mask2 = mask & titan_cpu_irq_affinity[2];
+	mask3 = mask & titan_cpu_irq_affinity[3];
 
 	if (bcpu == 0) mask0 |= isa_enable;
 	else if (bcpu == 1) mask1 |= isa_enable;
@@ -84,8 +100,8 @@
 	*dim3;
 #else
 	volatile unsigned long *dimB;
-	if (bcpu == 0) dimB = &cchip->dim0.csr;
-	else if (bcpu == 1) dimB = &cchip->dim1.csr;
+	dimB = &cchip->dim0.csr;
+	if (bcpu == 1) dimB = &cchip->dim1.csr;
 	else if (bcpu == 2) dimB = &cchip->dim2.csr;
 	else if (bcpu == 3) dimB = &cchip->dim3.csr;
 
@@ -96,79 +112,68 @@
 }
 
 static inline void
-privateer_enable_irq(unsigned int irq)
+titan_enable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask |= 1UL << (irq - 16);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask |= 1UL << (irq - 16);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static inline void
-privateer_disable_irq(unsigned int irq)
+titan_disable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask &= ~(1UL << (irq - 16));
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask &= ~(1UL << (irq - 16));
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static unsigned int
-privateer_startup_irq(unsigned int irq)
+titan_startup_irq(unsigned int irq)
 {
-	privateer_enable_irq(irq);
+	titan_enable_irq(irq);
 	return 0;	/* never anything pending */
 }
 
 static void
-privateer_end_irq(unsigned int irq)
+titan_end_irq(unsigned int irq)
 {
 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		privateer_enable_irq(irq);
+		titan_enable_irq(irq);
 }
 
 static void
-cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
+titan_cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
 {
 	int cpu;
 
 	for (cpu = 0; cpu < 4; cpu++) {
 		if (affinity & (1UL << cpu))
-			cpu_irq_affinity[cpu] |= 1UL << irq;
+			titan_cpu_irq_affinity[cpu] |= 1UL << irq;
 		else
-			cpu_irq_affinity[cpu] &= ~(1UL << irq);
+			titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
 	}
 
 }
 
 static void
-privateer_set_affinity(unsigned int irq, unsigned long affinity)
+titan_set_irq_affinity(unsigned int irq, unsigned long affinity)
 { 
 	spin_lock(&titan_irq_lock);
-	cpu_set_irq_affinity(irq - 16, affinity);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cpu_set_irq_affinity(irq - 16, affinity);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
-static struct hw_interrupt_type privateer_irq_type = {
-	typename:	"PRIVATEER",
-	startup:	privateer_startup_irq,
-	shutdown:	privateer_disable_irq,
-	enable:		privateer_enable_irq,
-	disable:	privateer_disable_irq,
-	ack:		privateer_disable_irq,
-	end:		privateer_end_irq,
-	set_affinity:	privateer_set_affinity,
-};
-
 static void
-privateer_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	printk("privateer_device_interrupt: NOT IMPLEMENTED YET!! \n");
+	printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n");
 }
 
 static void 
-privateer_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq;
 
@@ -181,192 +186,209 @@
 init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
 {
 	long i;
-	for(i = imin; i <= imax; ++i) {
+	for (i = imin; i <= imax; ++i) {
 		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
 		irq_desc[i].handler = ops;
 	}
 }
 
+static struct hw_interrupt_type titan_irq_type = {
+	typename:	"TITAN",
+	startup:	titan_startup_irq,
+	shutdown:	titan_disable_irq,
+	enable:		titan_enable_irq,
+	disable:	titan_disable_irq,
+	ack:		titan_disable_irq,
+	end:		titan_end_irq,
+	set_affinity:	titan_set_irq_affinity,
+};
+
+static void
+titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 * This is a NOP interrupt handler for the purposes of
+	 * event counting -- just return.
+	 */
+}
+
 static void __init
-privateer_init_irq(void)
+titan_init_irq(void)
 {
-	extern asmlinkage void entInt(void);
-	int cpu;
+	if (alpha_using_srm && !alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_srm_device_interrupt;
+	if (!alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_device_interrupt;
 
+	titan_update_irq_hw(0);
+
+	init_titan_irqs(&titan_irq_type, 16, 63 + 16);
+}
+
+static void __init
+titan_legacy_init_irq(void)
+{
+	/* init the legacy dma controller */
 	outb(0, DMA1_RESET_REG);
 	outb(0, DMA2_RESET_REG);
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
 	outb(0, DMA2_MASK_REG);
 
-	if (alpha_using_srm)
-		alpha_mv.device_interrupt = privateer_srm_device_interrupt;
+	/* init the legacy irq controller */
+	init_i8259a_irqs();
 
-	titan_update_irq_hw(0UL);
+	/* init the titan irqs */
+	titan_init_irq();
+}
 
-	init_i8259a_irqs();
-	init_titan_irqs(&privateer_irq_type, 16, 63 + 16);
+void
+titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
+{
+	unsigned long vector;
+
+	/*
+	 * Mask down to those interrupts which are enable on this processor
+	 */
+	mask &= titan_cpu_irq_affinity[smp_processor_id()];
+
+	/*
+	 * Dispatch all requested interrupts 
+	 */
+	while (mask) {
+		/* convert to SRM vector... priority is <63> -> <0> */
+		__asm__("ctlz %1, %0" : "=r"(vector) : "r"(mask));
+		vector = 63 - vector;
+		mask &= ~(1UL << vector);	/* clear it out 	 */
+		vector = 0x900 + (vector << 4);	/* convert to SRM vector */
+		
+		/* dispatch it */
+		alpha_mv.device_interrupt(vector, regs);
+	}
 }
 
+
 /*
- * Privateer PCI Fixup configuration.
- *
- * PCHIP 0 BUS 0 (Hose 0)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	18	 7	Embedded Southbridge
- *	19	 8	Slot 0 
- *	20	 9	Slot 1
- *	21	10	Slot 2 
- *	22	11	Slot 3
- *	23	12	Embedded HotPlug controller
- *	27	16	Embedded Southbridge IDE
- *	29	18     	Embedded Southbridge PMU
- *	31	20	Embedded Southbridge USB
- *
- * PCHIP 1 BUS 0 (Hose 1)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * PCHIP 0 BUS 1 (Hose 2)
- *
- *     IDSEL	What
- *     -----	----
- *	NONE	AGP
- *
- * PCHIP 1 BUS 1 (Hose 3)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * Summary @ TITAN_CSR_DIM0:
- * Bit      Meaning
- *  0-7     Unused
- *  8       PCHIP 0 BUS 1 YUKON (if present)
- *  9       PCHIP 1 BUS 1 YUKON
- * 10       PCHIP 1 BUS 0 YUKON
- * 11       PCHIP 0 BUS 0 YUKON
- * 12       PCHIP 0 BUS 0 SLOT 2 INT A
- * 13       PCHIP 0 BUS 0 SLOT 2 INT B
- * 14       PCHIP 0 BUS 0 SLOT 2 INT C
- * 15       PCHIP 0 BUS 0 SLOT 2 INT D
- * 16       PCHIP 0 BUS 0 SLOT 3 INT A
- * 17       PCHIP 0 BUS 0 SLOT 3 INT B
- * 18       PCHIP 0 BUS 0 SLOT 3 INT C
- * 19       PCHIP 0 BUS 0 SLOT 3 INT D
- * 20       PCHIP 0 BUS 0 SLOT 0 INT A
- * 21       PCHIP 0 BUS 0 SLOT 0 INT B
- * 22       PCHIP 0 BUS 0 SLOT 0 INT C
- * 23       PCHIP 0 BUS 0 SLOT 0 INT D
- * 24       PCHIP 0 BUS 0 SLOT 1 INT A
- * 25       PCHIP 0 BUS 0 SLOT 1 INT B
- * 26       PCHIP 0 BUS 0 SLOT 1 INT C
- * 27       PCHIP 0 BUS 0 SLOT 1 INT D
- * 28       PCHIP 1 BUS 0 SLOT 0 INT A
- * 29       PCHIP 1 BUS 0 SLOT 0 INT B
- * 30       PCHIP 1 BUS 0 SLOT 0 INT C
- * 31       PCHIP 1 BUS 0 SLOT 0 INT D
- * 32       PCHIP 1 BUS 0 SLOT 1 INT A
- * 33       PCHIP 1 BUS 0 SLOT 1 INT B
- * 34       PCHIP 1 BUS 0 SLOT 1 INT C
- * 35       PCHIP 1 BUS 0 SLOT 1 INT D
- * 36       PCHIP 1 BUS 1 SLOT 0 INT A
- * 37       PCHIP 1 BUS 1 SLOT 0 INT B
- * 38       PCHIP 1 BUS 1 SLOT 0 INT C
- * 39       PCHIP 1 BUS 1 SLOT 0 INT D
- * 40       PCHIP 1 BUS 1 SLOT 1 INT A
- * 41       PCHIP 1 BUS 1 SLOT 1 INT B
- * 42       PCHIP 1 BUS 1 SLOT 1 INT C
- * 43       PCHIP 1 BUS 1 SLOT 1 INT D
- * 44       AGP INT A
- * 45       AGP INT B
- * 46-47    Unused
- * 49       Reserved for Sleep mode
- * 50       Temperature Warning (optional)
- * 51       Power Warning (optional)
- * 52       Reserved
- * 53       South Bridge NMI
- * 54       South Bridge SMI INT
- * 55       South Bridge ISA Interrupt
- * 56-58    Unused
- * 59       PCHIP1_C_ERROR
- * 60       PCHIP0_C_ERROR 
- * 61       PCHIP1_H_ERROR
- * 62       PCHIP0_H_ERROR
- * 63       Reserved
- *
+ * Titan Family
  */
-static int __init
-privateer_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static void __init
+titan_late_init(void)
 {
-	u8 irq;
-	
-	pcibios_read_config_byte(dev->bus->number,
-				 dev->devfn,
-				 PCI_INTERRUPT_LINE,
-				 &irq);
-
-	/* is it routed through ISA? */
-	if ((irq & 0xF0) == 0xE0)
-		return (int)irq;
+	/*
+	 * Enable the system error interrupts. These interrupts are 
+	 * all reported to the kernel as machine checks, so the handler
+	 * is a nop so it can be called to count the individual events.
+	 */
+	request_irq(63+16, titan_intr_nop, SA_INTERRUPT, 
+		    "CChip Error", NULL);
+	request_irq(62+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 H_Error", NULL);
+	request_irq(61+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 H_Error", NULL);
+	request_irq(60+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 C_Error", NULL);
+	request_irq(59+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 C_Error", NULL);
+
+	/* 
+	 * Register our error handlers.
+	 */
+	titan_register_error_handlers();
+
+	/*
+	 * Check if the console left us any error logs.
+	 */
+	cdl_check_console_data_log();
 
-	return (int)irq + 16;	/* HACK -- this better only be called once */
 }
 
-#ifdef CONFIG_VGA_HOSE
-static struct pci_controller * __init
-privateer_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
+static int __devinit
+titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-	struct pci_controller *hose = h1;
-	int agp1, agp2;
-
-	/* which hose(s) are agp? */
-	agp1 = (0 != (TITAN_agp & (1 << h1->index)));
-	agp2 = (0 != (TITAN_agp & (1 << h2->index)));
-       
-	hose = h1;			/* default to h1 */
-	if (agp1 ^ agp2) {
-		if (agp2) hose = h2;	/* take agp if only one */
-	} else if (h2->index < h1->index)
-		hose = h2;		/* first hose if 2xpci or 2xagp */
+	u8 intline;
+	int irq;
 
-	return hose;
+ 	/* Get the current intline.  */
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+ 	/* Is it explicitly routed through ISA?  */
+ 	if ((irq & 0xF0) == 0xE0)
+ 		return irq;
+ 
+ 	/* Offset by 16 to make room for ISA interrupts 0 - 15.  */
+ 	return irq + 16;
 }
-#endif
 
 static void __init
-privateer_init_pci(void)
+titan_init_pci(void)
 {
+ 	/*
+ 	 * This isn't really the right place, but there's some init
+ 	 * that needs to be done after everything is basically up.
+ 	 */
+ 	titan_late_init();
+ 
+	pci_probe_only = 1;
 	common_init_pci();
 	SMC669_Init(0);
 #ifdef CONFIG_VGA_HOSE
-	locate_and_init_vga(privateer_vga_hose_select);
+	locate_and_init_vga(NULL);
 #endif
 }
 
-void
-privateer_machine_check(unsigned long vector, unsigned long la_ptr,
-			struct pt_regs * regs)
+
+/*
+ * Privateer
+ */
+static void __init
+privateer_init_pci(void)
 {
-	/* only handle system events here */
-	if (vector != SCB_Q_SYSEVENT) 
-		return titan_machine_check(vector, la_ptr, regs);
-
-	/* it's a system event, handle it here */
-	printk("PRIVATEER 680 Machine Check on CPU %d\n", smp_processor_id());
+	/*
+	 * Hook a couple of extra err interrupts that the
+	 * common titan code won't.
+	 */
+	request_irq(53+16, titan_intr_nop, SA_INTERRUPT, 
+		    "NMI", NULL);
+	request_irq(50+16, titan_intr_nop, SA_INTERRUPT, 
+		    "Temperature Warning", NULL);
+
+	/*
+	 * Finish with the common version.
+	 */
+	return titan_init_pci();
 }
 
-
+
 /*
- * The System Vectors
+ * The System Vectors.
  */
+struct alpha_machine_vector titan_mv __initmv = {
+	vector_name:		"TITAN",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_TITAN_IO,
+	DO_TITAN_BUS,
+	machine_check:		titan_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TITAN_DAC_OFFSET,
+
+	nr_irqs:		80,	/* 64 + 16 */
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
+
+	init_arch:		titan_init_arch,
+	init_irq:		titan_legacy_init_irq,
+	init_rtc:		common_init_rtc,
+	init_pci:		titan_init_pci,
+
+	kill_arch:		titan_kill_arch,
+	pci_map_irq:		titan_map_irq,
+	pci_swizzle:		common_swizzle,
+};
+ALIAS_MV(titan)
 
 struct alpha_machine_vector privateer_mv __initmv = {
 	vector_name:		"PRIVATEER",
@@ -381,14 +403,18 @@
 	pci_dac_offset:		TITAN_DAC_OFFSET,
 
 	nr_irqs:		80,	/* 64 + 16 */
-	device_interrupt:	privateer_device_interrupt,
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
 
 	init_arch:		titan_init_arch,
-	init_irq:		privateer_init_irq,
+	init_irq:		titan_legacy_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		privateer_init_pci,
+
 	kill_arch:		titan_kill_arch,
-	pci_map_irq:		privateer_map_irq,
+	pci_map_irq:		titan_map_irq,
 	pci_swizzle:		common_swizzle,
 };
-ALIAS_MV(privateer)
+/* No alpha_mv alias for privateer since we compile it
+   in unconditionally with titan; setup_arch knows how to cope. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_wildfire.c linux-2.4.21-rc3/arch/alpha/kernel/sys_wildfire.c
--- linux-2.4.20/arch/alpha/kernel/sys_wildfire.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/sys_wildfire.c	2003-05-22 22:06:41.000000000 +0000
@@ -352,5 +352,10 @@
 	kill_arch:		wildfire_kill_arch,
 	pci_map_irq:		wildfire_map_irq,
 	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		wildfire_pa_to_nid,
+	cpuid_to_nid:		wildfire_cpuid_to_nid,
+	node_mem_start:		wildfire_node_mem_start,
+	node_mem_size:		wildfire_node_mem_size,
 };
 ALIAS_MV(wildfire)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/time.c linux-2.4.21-rc3/arch/alpha/kernel/time.c
--- linux-2.4.20/arch/alpha/kernel/time.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/time.c	2003-05-22 22:06:47.000000000 +0000
@@ -143,7 +143,9 @@
 
 	/* Reset periodic interrupt frequency.  */
 	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
-	if (x != 0x26 && x != 0x19 && x != 0x06) {
+	/* Test includes known working values on various platforms
+	   where 0x26 is wrong; we refuse to change those. */
+	if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) {
 		printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x);
 		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 	}
@@ -183,8 +185,8 @@
 		unsigned int min, max;
 	} cpu_hz[] __initdata = {
 		[EV3_CPU]    = {   50000000,  200000000 },	/* guess */
-		[EV4_CPU]    = {  150000000,  300000000 },
-		[LCA4_CPU]   = {  150000000,  300000000 },	/* guess */
+		[EV4_CPU]    = {  100000000,  300000000 },
+		[LCA4_CPU]   = {  100000000,  300000000 },	/* guess */
 		[EV45_CPU]   = {  200000000,  300000000 },
 		[EV5_CPU]    = {  250000000,  433000000 },
 		[EV56_CPU]   = {  333000000,  667000000 },
@@ -255,12 +257,12 @@
 
 	cc = rpcc();
 	do {
-		count++;
+	  count += 100; /* by 1 takes too long to timeout from 0 */
 	} while ((inb(0x61) & 0x20) == 0 && count > 0);
 	cc = rpcc() - cc;
 
 	/* Error: ECTCNEVERSET or ECPUTOOFAST.  */
-	if (count <= 1)
+	if (count <= 100)
 		return 0;
 
 	/* Error: ECPUTOOSLOW.  */
@@ -378,21 +380,6 @@
 
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
-
-	/*
-	 * If we had wanted SRM console printk echoing early, undo it now.
-	 *
-	 * "srmcons" specified in the boot command arguments allows us to
-	 * see kernel messages during the period of time before the true
-	 * console device is "registered" during console_init(). As of this
-	 * version (2.4.10), time_init() is the last Alpha-specific code
-	 * called before console_init(), so we put this "unregister" code
-	 * here to prevent schizophrenic console behavior later... ;-}
-	 */
-	if (alpha_using_srm && srmcons_output) {
-		unregister_srm_console();
-		srmcons_output = 0;
-	}
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/traps.c linux-2.4.21-rc3/arch/alpha/kernel/traps.c
--- linux-2.4.20/arch/alpha/kernel/traps.c	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/kernel/traps.c	2003-05-22 22:06:39.000000000 +0000
@@ -29,6 +29,7 @@
 */
 static int opDEC_testing = 0;
 static int opDEC_fix = 0;
+static int opDEC_checked = 0;
 static unsigned long opDEC_test_pc = 0;
 
 static void
@@ -36,6 +37,8 @@
 {
 	unsigned long test_pc;
 
+	if (opDEC_checked) return;
+
 	lock_kernel();
 	opDEC_testing = 1;
 
@@ -48,6 +51,7 @@
 		: );
 
 	opDEC_testing = 0;
+	opDEC_checked = 1;
 	unlock_kernel();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/callback_srm.S linux-2.4.21-rc3/arch/alpha/lib/callback_srm.S
--- linux-2.4.20/arch/alpha/lib/callback_srm.S	2000-06-20 00:59:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/callback_srm.S	2003-05-22 22:06:41.000000000 +0000
@@ -78,6 +78,8 @@
 CALLBACK(open, CCB_OPEN, 3)
 CALLBACK(close, CCB_CLOSE, 2)
 CALLBACK(read, CCB_READ, 5)
+CALLBACK(open_console, CCB_OPEN_CONSOLE, 1)
+CALLBACK(close_console, CCB_CLOSE_CONSOLE, 1)
 CALLBACK(getenv, CCB_GET_ENV, 4)
 CALLBACK(setenv, CCB_SET_ENV, 4)
 CALLBACK(getc, CCB_GETC, 2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S linux-2.4.21-rc3/arch/alpha/lib/ev6-strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev6-strncpy_from_user.S	2003-05-22 22:06:53.000000000 +0000
@@ -27,7 +27,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S linux-2.4.21-rc3/arch/alpha/lib/ev6-stxcpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev6-stxcpy.S	2003-05-22 22:06:24.000000000 +0000
@@ -30,7 +30,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S linux-2.4.21-rc3/arch/alpha/lib/ev6-stxncpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev6-stxncpy.S	2003-05-22 22:06:51.000000000 +0000
@@ -25,7 +25,7 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  *
  * Much of the information about 21264 scheduling/coding comes from:
  *	Compiler Writer's Guide for the Alpha 21264
@@ -38,7 +38,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -324,7 +324,7 @@
 	extqh	t2, a1, t0	# U : extract low bits for last word (stall)
 	or	t1, t0, t1	# E : (stall)
 
-	cmpbge	zero, t1, t8	# E :
+1:	cmpbge	zero, t1, t8	# E :
 	mov	t1, t0		# E :
 
 $u_eocfin:			# end-of-count, final word
@@ -350,17 +350,17 @@
 	mskql	t6, a0, t6	# U :
 	nop
 	nop
-1:	subq	a1, t4, a1	# E : sub dest misalignment from src addr
+	subq	a1, t4, a1	# E : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# E :
+1:	cmplt	t4, t5, t12	# E :
 	extql	t1, a1, t1	# U : shift src into place
 	lda	t2, -1		# E : for creating masks later
 	beq	t12, $u_head	# U : (stall)
 
-	mskqh	t2, t5, t2	# U : begin src byte validity mask
+	nop
 	cmpbge	zero, t1, t8	# E : is there a zero?
 	extql	t2, a1, t2	# U :
 	or	t8, t10, t5	# E : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strchr.S linux-2.4.21-rc3/arch/alpha/lib/ev67-strchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strchr.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev67-strchr.S	2003-05-22 22:06:48.000000000 +0000
@@ -16,7 +16,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S linux-2.4.21-rc3/arch/alpha/lib/ev67-strlen_user.S
--- linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev67-strlen_user.S	2003-05-22 22:06:42.000000000 +0000
@@ -23,7 +23,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strrchr.S linux-2.4.21-rc3/arch/alpha/lib/ev67-strrchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strrchr.S	2000-12-30 19:13:36.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/ev67-strrchr.S	2003-05-22 22:06:48.000000000 +0000
@@ -19,7 +19,7 @@
  */
 
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strchr.S linux-2.4.21-rc3/arch/alpha/lib/strchr.S
--- linux-2.4.20/arch/alpha/lib/strchr.S	1996-10-18 08:53:20.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/strchr.S	2003-05-22 22:06:43.000000000 +0000
@@ -6,7 +6,7 @@
  * string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strlen_user.S linux-2.4.21-rc3/arch/alpha/lib/strlen_user.S
--- linux-2.4.20/arch/alpha/lib/strlen_user.S	1999-10-11 17:06:34.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/strlen_user.S	2003-05-22 22:06:47.000000000 +0000
@@ -12,7 +12,7 @@
  * boundary when doing so.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strncpy_from_user.S linux-2.4.21-rc3/arch/alpha/lib/strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/strncpy_from_user.S	1999-04-25 00:54:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/strncpy_from_user.S	2003-05-22 22:06:26.000000000 +0000
@@ -12,7 +12,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strrchr.S linux-2.4.21-rc3/arch/alpha/lib/strrchr.S
--- linux-2.4.20/arch/alpha/lib/strrchr.S	1997-11-19 22:07:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/strrchr.S	2003-05-22 22:06:51.000000000 +0000
@@ -6,7 +6,7 @@
  * within a null-terminated string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxcpy.S linux-2.4.21-rc3/arch/alpha/lib/stxcpy.S
--- linux-2.4.20/arch/alpha/lib/stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/stxcpy.S	2003-05-22 22:06:38.000000000 +0000
@@ -20,7 +20,7 @@
  * Furthermore, v0, a3-a5, t11, and t12 are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxncpy.S linux-2.4.21-rc3/arch/alpha/lib/stxncpy.S
--- linux-2.4.20/arch/alpha/lib/stxncpy.S	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/stxncpy.S	2003-05-22 22:06:53.000000000 +0000
@@ -25,10 +25,10 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -269,7 +269,7 @@
 	   t1 == the shifted high-order bits from the previous source word  */
 $u_eoc:
 	and	a1, 7, t6	# e1    :
-	sll	t12, t6, t6	# e0    :
+	sll	t10, t6, t6	# e0    :
 	and	t6, 0xff, t6	# e0    :
 	bne	t6, 1f		# .. e1 :
 
@@ -303,18 +303,17 @@
 	ldq_u	t0, 0(a0)	# e0    :
 	lda	t6, -1		# .. e1 :
 	mskql	t6, a0, t6	# e0    :
-1:
 	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# e1    :
+1:	cmplt	t4, t5, t12	# e1    :
 	extql	t1, a1, t1	# .. e0 : shift src into place
 	lda	t2, -1		# e0    : for creating masks later
-	beq	t12, $u_head	# e1    :
+	beq	t12, $u_head	# .. e1 :
 
-	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
+	nop			# e0    :
 	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
 	extql	t2, a1, t2	# e0    :
 	or	t8, t10, t5	# .. e1 : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/udelay.c linux-2.4.21-rc3/arch/alpha/lib/udelay.c
--- linux-2.4.20/arch/alpha/lib/udelay.c	2001-06-20 18:10:27.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/lib/udelay.c	2003-05-22 22:06:27.000000000 +0000
@@ -18,7 +18,8 @@
  * a 1GHz box, that's about 2 seconds.
  */
 
-void __delay(int loops)
+void
+__delay(int loops)
 {
 	int tmp;
 	__asm__ __volatile__(
@@ -30,18 +31,22 @@
 		: "=&r" (tmp), "=r" (loops) : "1"(loops));
 }
 
-void __udelay(unsigned long usecs, unsigned long lpj)
-{
-	usecs *= (((unsigned long)HZ << 32) / 1000000) * lpj;
-	__delay((long)usecs >> 32);
-}
-
-void udelay(unsigned long usecs)
-{
 #ifdef CONFIG_SMP
-	__udelay(usecs, cpu_data[smp_processor_id()].loops_per_jiffy);
+#define LPJ	cpu_data[smp_processor_id()].loops_per_jiffy
 #else
-	__udelay(usecs, loops_per_jiffy);
+#define LPJ	loops_per_jiffy
 #endif
+
+void
+ndelay(unsigned long nsecs)
+{
+	nsecs *= (((unsigned long)HZ << 32) / 1000000000) * LPJ;
+	__delay((long)nsecs >> 32);
 }
 
+void
+udelay(unsigned long usecs)
+{
+	usecs *= (((unsigned long)HZ << 32) / 1000000) * LPJ;
+	__delay((long)usecs >> 32);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/Makefile linux-2.4.21-rc3/arch/alpha/mm/Makefile
--- linux-2.4.20/arch/alpha/mm/Makefile	2001-05-24 22:20:18.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/mm/Makefile	2003-05-22 22:06:53.000000000 +0000
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y	:= init.o fault.o extable.o
+obj-y	:= init.o fault.o extable.o remap.o
 
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/init.c linux-2.4.21-rc3/arch/alpha/mm/init.c
--- linux-2.4.20/arch/alpha/mm/init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/mm/init.c	2003-05-22 22:06:41.000000000 +0000
@@ -368,18 +368,23 @@
 #endif /* CONFIG_DISCONTIGMEM */
 
 void
-free_initmem (void)
+free_reserved_mem(void *start, void *end)
 {
-	extern char __init_begin, __init_end;
-	unsigned long addr;
-
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(addr));
-		set_page_count(virt_to_page(addr), 1);
-		free_page(addr);
+	void *__start = start;
+	for (; __start < end; __start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(__start));
+		set_page_count(virt_to_page(__start), 1);
+		free_page((long)__start);
 		totalram_pages++;
 	}
+}
+
+void
+free_initmem(void)
+{
+	extern char __init_begin, __init_end;
+
+	free_reserved_mem(&__init_begin, &__init_end);
 	printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
@@ -388,14 +393,9 @@
 void
 free_initrd_mem(unsigned long start, unsigned long end)
 {
-	unsigned long __start = start;
-	for (; start < end; start += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(start));
-		set_page_count(virt_to_page(start), 1);
-		free_page(start);
-		totalram_pages++;
-	}
-	printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - __start) >> 10);
+	free_reserved_mem((void *)start, (void *)end);
+	printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+	       (end - start) >> 10);
 }
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/numa.c linux-2.4.21-rc3/arch/alpha/mm/numa.c
--- linux-2.4.20/arch/alpha/mm/numa.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/mm/numa.c	2003-05-22 22:06:25.000000000 +0000
@@ -64,20 +64,22 @@
 	unsigned long bootmap_size, bootmap_pages, bootmap_start;
 	unsigned long start, end;
 	unsigned long node_pfn_start, node_pfn_end;
+	unsigned long node_min_pfn, node_max_pfn;
 	int i;
 	unsigned long node_datasz = PFN_UP(sizeof(plat_pg_data_t));
 	int show_init = 0;
 
 	/* Find the bounds of current node */
-	node_pfn_start = (nid * NODE_MAX_MEM_SIZE) >> PAGE_SHIFT;
-	node_pfn_end = node_pfn_start + (NODE_MAX_MEM_SIZE >> PAGE_SHIFT);
+	node_pfn_start = (NODE_MEM_START(nid)) >> PAGE_SHIFT;
+	node_pfn_end = node_pfn_start + (NODE_MEM_SIZE(nid) >> PAGE_SHIFT);
 	
 	/* Find free clusters, and init and free the bootmem accordingly.  */
 	memdesc = (struct memdesc_struct *)
 	  (hwrpb->mddt_offset + (unsigned long) hwrpb);
 
-	/* find the bounds of this node (min_low_pfn/max_low_pfn) */
-	min_low_pfn = ~0UL;
+	/* find the bounds of this node (node_min_pfn/node_max_pfn) */
+	node_min_pfn = ~0UL;
+	node_max_pfn = 0UL;
 	for_each_mem_cluster(memdesc, cluster, i) {
 		/* Bit 0 is console/PALcode reserved.  Bit 1 is
 		   non-volatile memory -- we might want to mark
@@ -104,36 +106,46 @@
 		if (end > node_pfn_end)
 			end = node_pfn_end;
 
-		if (start < min_low_pfn)
-			min_low_pfn = start;
-		if (end > max_low_pfn)
-			max_low_pfn = end;
+		if (start < node_min_pfn)
+			node_min_pfn = start;
+		if (end > node_max_pfn)
+			node_max_pfn = end;
 	}
 
-	if (mem_size_limit && max_low_pfn >= mem_size_limit) {
-		printk("setup: forcing memory size to %ldK (from %ldK).\n",
-		       mem_size_limit << (PAGE_SHIFT - 10),
-		       max_low_pfn    << (PAGE_SHIFT - 10));
-		max_low_pfn = mem_size_limit;
+	if (mem_size_limit && node_max_pfn > mem_size_limit) {
+		static int msg_shown = 0;
+		if (!msg_shown) {
+			msg_shown = 1;
+			printk("setup: forcing memory size to %ldK (from %ldK).\n",
+			       mem_size_limit << (PAGE_SHIFT - 10),
+			       node_max_pfn   << (PAGE_SHIFT - 10));
+		}
+		node_max_pfn = mem_size_limit;
 	}
 
-	if (min_low_pfn >= max_low_pfn)
+	if (node_min_pfn >= node_max_pfn)
 		return;
 
-	num_physpages += max_low_pfn - min_low_pfn;
+	/* Update global {min,max}_low_pfn from node information. */
+	if (node_min_pfn < min_low_pfn)
+		min_low_pfn = node_min_pfn;
+	if (node_max_pfn > max_low_pfn)
+		max_low_pfn = node_max_pfn;
+
+	num_physpages += node_max_pfn - node_min_pfn;
 
 	/* Cute trick to make sure our local node data is on local memory */
-	PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
+	PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(node_min_pfn << PAGE_SHIFT));
 	/* Quasi-mark the plat_pg_data_t as in-use */
-	min_low_pfn += node_datasz;
-	if (min_low_pfn >= max_low_pfn) {
+	node_min_pfn += node_datasz;
+	if (node_min_pfn >= node_max_pfn) {
 		printk(" not enough mem to reserve PLAT_NODE_DATA");
 		return;
 	}
 	NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
 
 	printk(" Detected node memory:   start %8lu, end %8lu\n",
-	       min_low_pfn, max_low_pfn);
+	       node_min_pfn, node_max_pfn);
 
 	DBGDCONT(" DISCONTIG: plat_node_data[%d]   is at 0x%p\n", nid, PLAT_NODE_DATA(nid));
 	DBGDCONT(" DISCONTIG: NODE_DATA(%d)->bdata is at 0x%p\n", nid, NODE_DATA(nid)->bdata);
@@ -143,15 +155,15 @@
 	end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end));
 	bootmap_start = -1;
 
-	if (!nid && (max_low_pfn < end_kernel_pfn || min_low_pfn > start_kernel_pfn))
+	if (!nid && (node_max_pfn < end_kernel_pfn || node_min_pfn > start_kernel_pfn))
 		panic("kernel loaded out of ram");
 
 	/* Zone start phys-addr must be 2^(MAX_ORDER-1) aligned */
-	min_low_pfn = (min_low_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1);
+	node_min_pfn = (node_min_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1);
 
 	/* We need to know how many physically contiguous pages
 	   we'll need for the bootmap.  */
-	bootmap_pages = bootmem_bootmap_pages(max_low_pfn-min_low_pfn);
+	bootmap_pages = bootmem_bootmap_pages(node_max_pfn-node_min_pfn);
 
 	/* Now find a good region where to allocate the bootmap.  */
 	for_each_mem_cluster(memdesc, cluster, i) {
@@ -161,13 +173,13 @@
 		start = cluster->start_pfn;
 		end = start + cluster->numpages;
 
-		if (start >= max_low_pfn || end <= min_low_pfn)
+		if (start >= node_max_pfn || end <= node_min_pfn)
 			continue;
 
-		if (end > max_low_pfn)
-			end = max_low_pfn;
-		if (start < min_low_pfn)
-			start = min_low_pfn;
+		if (end > node_max_pfn)
+			end = node_max_pfn;
+		if (start < node_min_pfn)
+			start = node_min_pfn;
 
 		if (start < start_kernel_pfn) {
 			if (end > end_kernel_pfn
@@ -189,7 +201,7 @@
 
 	/* Allocate the bootmap and mark the whole MM as reserved.  */
 	bootmap_size = init_bootmem_node(NODE_DATA(nid), bootmap_start,
-					 min_low_pfn, max_low_pfn);
+					 node_min_pfn, node_max_pfn);
 	DBGDCONT(" bootmap_start %lu, bootmap_size %lu, bootmap_pages %lu\n",
 		 bootmap_start, bootmap_size, bootmap_pages);
 
@@ -201,13 +213,13 @@
 		start = cluster->start_pfn;
 		end = cluster->start_pfn + cluster->numpages;
 
-		if (start >= max_low_pfn || end <= min_low_pfn)
+		if (start >= node_max_pfn || end <= node_min_pfn)
 			continue;
 
-		if (end > max_low_pfn)
-			end = max_low_pfn;
-		if (start < min_low_pfn)
-			start = min_low_pfn;
+		if (end > node_max_pfn)
+			end = node_max_pfn;
+		if (start < node_min_pfn)
+			start = node_min_pfn;
 
 		if (start < start_kernel_pfn) {
 			if (end > end_kernel_pfn) {
@@ -243,22 +255,27 @@
 	show_mem_layout();
 
 	numnodes = 0;
+
+	min_low_pfn = ~0UL;
+	max_low_pfn = 0UL;
 	for (nid = 0; nid < MAX_NUMNODES; nid++)
 		setup_memory_node(nid, kernel_end);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	initrd_start = INITRD_START;
 	if (initrd_start) {
+		extern void *move_initrd(unsigned long);
+
 		initrd_end = initrd_start+INITRD_SIZE;
 		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem_node(NODE_DATA(KVADDR_TO_NID(initrd_start)),
 					     virt_to_phys((void *)initrd_start),
@@ -383,8 +400,8 @@
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
 	printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, "
-		"%luk data, %luk init)\n",
-	       nr_free_pages() << (PAGE_SHIFT-10),
+	       "%luk data, %luk init)\n",
+	       (unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
 	       num_physpages << (PAGE_SHIFT-10),
 	       codesize >> 10,
 	       reservedpages << (PAGE_SHIFT-10),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/remap.c linux-2.4.21-rc3/arch/alpha/mm/remap.c
--- linux-2.4.20/arch/alpha/mm/remap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/mm/remap.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,88 @@
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+
+/* called with the page_table_lock held */
+static inline void 
+remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
+	       unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, 
+			mk_pte_phys(phys_addr, 
+				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
+					     _PAGE_KRE | _PAGE_KWE | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+/* called with the page_table_lock held */
+static inline int 
+remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
+	       unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, 
+				     address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+int
+__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+			 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	int error = 0;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+			           phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	return error;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/vmlinux.lds.in linux-2.4.21-rc3/arch/alpha/vmlinux.lds.in
--- linux-2.4.20/arch/alpha/vmlinux.lds.in	2001-11-22 18:54:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/alpha/vmlinux.lds.in	2003-05-22 22:06:47.000000000 +0000
@@ -8,7 +8,7 @@
 #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
   . = 0xfffffc0000310000;
 #else
-  . = 0xfffffc0000810000;
+  . = 0xfffffc0001010000;
 #endif
 
   _text = .;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/config.in linux-2.4.21-rc3/arch/arm/config.in
--- linux-2.4.20/arch/arm/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/config.in	2003-05-22 22:06:28.000000000 +0000
@@ -83,7 +83,7 @@
    choice 'Cerf Flash available'  \
         "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
          16MB   CONFIG_SA1100_CERF_FLASH_16MB \
-         32MB   CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash
+         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
    bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
 fi
 dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
@@ -538,7 +538,7 @@
 endmenu
 
 if [ "$CONFIG_ARCH_CLPS711X" = "y" ]; then
-   source drivers/ssi/Config.in
+   source drivers/scsi/Config.in
 fi
 
 source drivers/ieee1394/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/badge4 linux-2.4.21-rc3/arch/arm/def-configs/badge4
--- linux-2.4.20/arch/arm/def-configs/badge4	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/def-configs/badge4	2003-05-22 22:06:51.000000000 +0000
@@ -798,6 +798,7 @@
 # CONFIG_RADIO_MIROPCM20 is not set
 # CONFIG_RADIO_MIROPCM20_RDS is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/empeg linux-2.4.21-rc3/arch/arm/def-configs/empeg
--- linux-2.4.20/arch/arm/def-configs/empeg	1999-10-20 23:29:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/def-configs/empeg	2003-05-22 22:06:39.000000000 +0000
@@ -119,6 +119,7 @@
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TYPHOON is not set
 # CONFIG_RADIO_ZOLTRIX is not set
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/footbridge linux-2.4.21-rc3/arch/arm/def-configs/footbridge
--- linux-2.4.20/arch/arm/def-configs/footbridge	2000-11-28 01:07:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/def-configs/footbridge	2003-05-22 22:06:40.000000000 +0000
@@ -599,6 +599,7 @@
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/arthur.c linux-2.4.21-rc3/arch/arm/kernel/arthur.c
--- linux-2.4.20/arch/arm/kernel/arthur.c	2001-09-10 20:04:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/arthur.c	2003-05-22 22:06:38.000000000 +0000
@@ -43,20 +43,48 @@
 	24,	25,	26,	27,	28,	29,	30,	31
 };
 
+/*
+ * Linux to Arthur signal map.
+ */
 static unsigned long linux_to_arthur_signals[32] = {
-	0,		-1,		ARTHUR_SIGINT,	-1,
-       	ARTHUR_SIGILL,	5,		ARTHUR_SIGABRT,	7,
-	ARTHUR_SIGFPE,	9,		ARTHUR_SIGUSR1,	ARTHUR_SIGSEGV,	
-	ARTHUR_SIGUSR2,	13,		14,		ARTHUR_SIGTERM,
-	16,		17,		18,		19,
-	20,		21,		22,		23,
-	24,		25,		26,		27,
-	28,		29,		30,		31
+	[0]		= 0,
+	[SIGHUP]	= -1,
+	[SIGINT]	= ARTHUR_SIGINT,
+	[SIGQUIT]	= -1,
+	[SIGILL]	= ARTHUR_SIGILL,
+	[SIGTRAP]	= 5,
+	[SIGABRT]	= ARTHUR_SIGABRT,
+	[SIGBUS]	= 7,
+	[SIGFPE]	= ARTHUR_SIGFPE,
+	[SIGKILL]	= 9,
+	[SIGUSR1]	= ARTHUR_SIGUSR1,
+	[SIGSEGV]	= ARTHUR_SIGSEGV,	
+	[SIGUSR2]	= ARTHUR_SIGUSR2,
+	[SIGPIPE]	= 13,
+	[SIGALRM]	= 14,
+	[SIGTERM]	= ARTHUR_SIGTERM,
+	[SIGSTKFLT]	= 16,
+	[SIGCHLD]	= 17,
+	[SIGCONT]	= 18,
+	[SIGSTOP]	= 19,
+	[SIGTSTP]	= 20,
+	[SIGTTIN]	= 21,
+	[SIGTTOU]	= 22,
+	[SIGURG]	= 23,
+	[SIGXCPU]	= 24,
+	[SIGXFSZ]	= 25,
+	[SIGVTALRM]	= 26,
+	[SIGPROF]	= 27,
+	[SIGWINCH]	= 28,
+	[SIGIO]		= 29,
+	[SIGPWR]	= 30,
+	[SIGSYS]	= 31
 };
 
 static void arthur_lcall7(int nr, struct pt_regs *regs)
 {
 	struct siginfo info;
+
 	info.si_signo = SIGSWI;
 	info.si_errno = nr;
 	/* Bounce it to the emulator */
@@ -64,13 +92,13 @@
 }
 
 static struct exec_domain arthur_exec_domain = {
-	"Arthur",	/* name */
-	arthur_lcall7,
-	PER_RISCOS, PER_RISCOS,
-	arthur_to_linux_signals,
-	linux_to_arthur_signals,
-	THIS_MODULE,
-	NULL		/* Nothing after this in the list. */
+	.name		= "Arthur",	/* name */
+	.handler	= arthur_lcall7,
+	.pers_low	= PER_RISCOS,
+	.pers_high	= PER_RISCOS,
+	.signal_map	= arthur_to_linux_signals,
+	.signal_invmap	= linux_to_arthur_signals,
+	.module		= THIS_MODULE,
 };
 
 /*
@@ -78,15 +106,18 @@
  * processes are using it.
  */
 
-int __init arthur_init(void)
+static int __init arthur_init(void)
 {
 	return register_exec_domain(&arthur_exec_domain);
 }
 
-void __exit arthur_exit(void)
+static void __exit arthur_exit(void)
 {
 	unregister_exec_domain(&arthur_exec_domain);
 }
 
 module_init(arthur_init);
 module_exit(arthur_exit);
+
+MODULE_AUTHOR("Philip Blundell");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-arc.c linux-2.4.21-rc3/arch/arm/kernel/dma-arc.c
--- linux-2.4.20/arch/arm/kernel/dma-arc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/dma-arc.c	2003-05-22 22:06:50.000000000 +0000
@@ -106,23 +106,23 @@
 }
 
 static struct dma_ops arc_floppy_data_dma_ops = {
-	type:		"FIQDMA",
-	enable:		arc_floppy_data_enable_dma,
-	disable:	arc_disable_dma,
-	residue:	arc_floppy_data_get_dma_residue,
+	.type		= "FIQDMA",
+	.enable		= arc_floppy_data_enable_dma,
+	.disable	= arc_disable_dma,
+	.residue	= arc_floppy_data_get_dma_residue,
 };
 
 static struct dma_ops arc_floppy_cmdend_dma_ops = {
-	type:		"FIQCMD",
-	enable:		arc_floppy_cmdend_enable_dma,
-	disable:	arc_disable_dma,
-	residue:	arc_floppy_cmdend_get_dma_residue,
+	.type		= "FIQCMD",
+	.enable		= arc_floppy_cmdend_enable_dma,
+	.disable	= arc_disable_dma,
+	.residue	= arc_floppy_cmdend_get_dma_residue,
 };
 #endif
 
 #ifdef CONFIG_ARCH_A5K
 static struct fiq_handler fh = {
-	name:	"floppydata"
+	.name		= "floppydata",
 };
 
 static int a5k_floppy_get_dma_residue(dmach_t channel, dma_t *dma)
@@ -168,10 +168,10 @@
 }
 
 static struct dma_ops a5k_floppy_dma_ops = {
-	type:		"FIQDMA",
-	enable:		a5k_floppy_enable_dma,
-	disable:	a5k_floppy_disable_dma,
-	residue:	a5k_floppy_get_dma_residue,
+	.type		= "FIQDMA",
+	.enable		= a5k_floppy_enable_dma,
+	.disable	= a5k_floppy_disable_dma,
+	.residue	= a5k_floppy_get_dma_residue,
 };
 #endif
 
@@ -183,9 +183,9 @@
 }
 
 static struct dma_ops sound_dma_ops = {
-	type:		"VIRTUAL",
-	enable:		sound_enable_disable_dma,
-	disable:	sound_enable_disable_dma,
+	.type		= "VIRTUAL",
+	.enable		= sound_enable_disable_dma,
+	.disable	= sound_enable_disable_dma,
 };
 
 void __init arch_dma_init(dma_t *dma)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-footbridge.c linux-2.4.21-rc3/arch/arm/kernel/dma-footbridge.c
--- linux-2.4.20/arch/arm/kernel/dma-footbridge.c	2000-09-18 22:15:24.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/dma-footbridge.c	2003-05-22 22:06:41.000000000 +0000
@@ -35,10 +35,10 @@
 }
 
 static struct dma_ops fb_dma_ops = {
-	type:		"fb",
-	request:	fb_dma_request,
-	enable:		fb_dma_enable,
-	disable:	fb_dma_disable,
+	.type		= "fb",
+	.request	= fb_dma_request,
+	.enable		= fb_dma_enable,
+	.disable	= fb_dma_disable,
 };
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-isa.c linux-2.4.21-rc3/arch/arm/kernel/dma-isa.c
--- linux-2.4.20/arch/arm/kernel/dma-isa.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/dma-isa.c	2003-05-22 22:06:45.000000000 +0000
@@ -133,10 +133,10 @@
 }
 
 static struct dma_ops isa_dma_ops = {
-	type:		"ISA",
-	enable:		isa_enable_dma,
-	disable:	isa_disable_dma,
-	residue:	isa_get_dma_residue,
+	.type		= "ISA",
+	.enable		= isa_enable_dma,
+	.disable	= isa_disable_dma,
+	.residue	= isa_get_dma_residue,
 };
 
 static struct resource dma_resources[] = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-rpc.c linux-2.4.21-rc3/arch/arm/kernel/dma-rpc.c
--- linux-2.4.20/arch/arm/kernel/dma-rpc.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/dma-rpc.c	2003-05-22 22:06:43.000000000 +0000
@@ -257,16 +257,16 @@
 }
 
 static struct dma_ops iomd_dma_ops = {
-	type:		"IOMD",
-	request:	iomd_request_dma,
-	free:		iomd_free_dma,
-	enable:		iomd_enable_dma,
-	disable:	iomd_disable_dma,
-	setspeed:	iomd_set_dma_speed,
+	.type		= "IOMD",
+	.request	= iomd_request_dma,
+	.free		= iomd_free_dma,
+	.enable		= iomd_enable_dma,
+	.disable	= iomd_disable_dma,
+	.setspeed	= iomd_set_dma_speed,
 };
 
 static struct fiq_handler fh = {
-	name: "floppydma"
+	.name		= "floppydma"
 };
 
 static void floppy_enable_dma(dmach_t channel, dma_t *dma)
@@ -313,10 +313,10 @@
 }
 
 static struct dma_ops floppy_dma_ops = {
-	type:		"FIQDMA",
-	enable:		floppy_enable_dma,
-	disable:	floppy_disable_dma,
-	residue:	floppy_get_residue,
+	.type		= "FIQDMA",
+	.enable		= floppy_enable_dma,
+	.disable	= floppy_disable_dma,
+	.residue	= floppy_get_residue,
 };
 
 /*
@@ -327,9 +327,9 @@
 }
 
 static struct dma_ops sound_dma_ops = {
-	type:		"VIRTUAL",
-	enable:		sound_enable_disable_dma,
-	disable:	sound_enable_disable_dma,
+	.type		= "VIRTUAL",
+	.enable		= sound_enable_disable_dma,
+	.disable	= sound_enable_disable_dma,
 };
 
 void __init arch_dma_init(dma_t *dma)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/ecard.c linux-2.4.21-rc3/arch/arm/kernel/ecard.c
--- linux-2.4.20/arch/arm/kernel/ecard.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/ecard.c	2003-05-22 22:06:51.000000000 +0000
@@ -420,7 +420,7 @@
 }
 
 static struct notifier_block ecard_reboot_notifier = {
-	notifier_call:	ecard_reboot,
+	.notifier_call	= ecard_reboot,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/fiq.c linux-2.4.21-rc3/arch/arm/kernel/fiq.c
--- linux-2.4.20/arch/arm/kernel/fiq.c	2001-06-27 21:12:04.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/fiq.c	2003-05-22 22:06:51.000000000 +0000
@@ -86,8 +86,8 @@
 }
 
 static struct fiq_handler default_owner = {
-	name:	"default",
-	fiq_op:	fiq_def_op,
+	.name	= "default",
+	.fiq_op	= fiq_def_op,
 };
 
 static struct fiq_handler *current_fiq = &default_owner;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/ftv-pci.c linux-2.4.21-rc3/arch/arm/kernel/ftv-pci.c
--- linux-2.4.20/arch/arm/kernel/ftv-pci.c	2000-09-18 22:15:25.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/ftv-pci.c	2003-05-22 22:06:47.000000000 +0000
@@ -44,8 +44,8 @@
 
 /* ftv host-specific stuff */
 struct hw_pci ftv_pci __initdata = {
-	init:		plx90x0_init,
-	swizzle:	ftv_swizzle,
-	map_irq:	ftv_map_irq,
+	.init		= plx90x0_init,
+	.swizzle	= ftv_swizzle,
+	.map_irq	= ftv_map_irq,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/process.c linux-2.4.21-rc3/arch/arm/kernel/process.c
--- linux-2.4.20/arch/arm/kernel/process.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/process.c	2003-05-22 22:06:40.000000000 +0000
@@ -366,7 +366,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	pid_t __ret;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/time.c linux-2.4.21-rc3/arch/arm/kernel/time.c
--- linux-2.4.20/arch/arm/kernel/time.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/kernel/time.c	2003-05-22 22:06:50.000000000 +0000
@@ -202,7 +202,7 @@
 }
 
 static struct irqaction timer_irq = {
-	name: "timer",
+	.name	= "timer",
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-anakin/irq.c linux-2.4.21-rc3/arch/arm/mach-anakin/irq.c
--- linux-2.4.20/arch/arm/mach-anakin/irq.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-anakin/irq.c	2003-05-22 22:06:25.000000000 +0000
@@ -49,9 +49,9 @@
 }
 
 static struct irqaction anakin_irq = {
-	name:		"Anakin IRQ",
-	handler:	anakin_interrupt,
-	flags:		SA_INTERRUPT
+	.name		= "Anakin IRQ",
+	.handler	= anakin_interrupt,
+	.flags		= SA_INTERRUPT,
 };
  
 void __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/cats-pci.c linux-2.4.21-rc3/arch/arm/mach-footbridge/cats-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/cats-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-footbridge/cats-pci.c	2003-05-22 22:06:27.000000000 +0000
@@ -32,9 +32,9 @@
 }
 
 struct hw_pci cats_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	swizzle:		no_swizzle,
-	map_irq:		cats_map_irq,
+	.setup_resources	= dc21285_setup_resources,
+	.init			= dc21285_init,
+	.mem_offset		= DC21285_PCI_MEM,
+	.swizzle		= no_swizzle,
+	.map_irq		= cats_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/ebsa285-pci.c linux-2.4.21-rc3/arch/arm/mach-footbridge/ebsa285-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/ebsa285-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-footbridge/ebsa285-pci.c	2003-05-22 22:06:53.000000000 +0000
@@ -34,9 +34,9 @@
 }
 
 struct hw_pci ebsa285_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	swizzle:		ebsa285_swizzle,
-	map_irq:		ebsa285_map_irq,
+	.setup_resources	= dc21285_setup_resources,
+	.init			= dc21285_init,
+	.mem_offset		= DC21285_PCI_MEM,
+	.swizzle		= ebsa285_swizzle,
+	.map_irq		= ebsa285_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/netwinder-pci.c linux-2.4.21-rc3/arch/arm/mach-footbridge/netwinder-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/netwinder-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-footbridge/netwinder-pci.c	2003-05-22 22:06:25.000000000 +0000
@@ -49,9 +49,9 @@
 }
 
 struct hw_pci netwinder_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	swizzle:		no_swizzle,
-	map_irq:		netwinder_map_irq,
+	.setup_resources	= dc21285_setup_resources,
+	.init			= dc21285_init,
+	.mem_offset		= DC21285_PCI_MEM,
+	.swizzle		= no_swizzle,
+	.map_irq		= netwinder_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/personal-pci.c linux-2.4.21-rc3/arch/arm/mach-footbridge/personal-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/personal-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-footbridge/personal-pci.c	2003-05-22 22:06:41.000000000 +0000
@@ -38,9 +38,9 @@
 }
 
 struct hw_pci personal_server_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	swizzle:		no_swizzle,
-	map_irq:		personal_server_map_irq,
+	.setup_resources	= dc21285_setup_resources,
+	.init			= dc21285_init,
+	.mem_offset		= DC21285_PCI_MEM,
+	.swizzle		= no_swizzle,
+	.map_irq		= personal_server_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/arch.c linux-2.4.21-rc3/arch/arm/mach-integrator/arch.c
--- linux-2.4.20/arch/arm/mach-integrator/arch.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-integrator/arch.c	2003-05-22 22:06:50.000000000 +0000
@@ -36,17 +36,17 @@
 
 #ifdef CONFIG_KMI_KEYB
 static struct kmi_info integrator_keyboard __initdata = {
-	base:	IO_ADDRESS(KMI0_BASE),
-	irq:	IRQ_KMIINT0,
-	divisor: 24 / 8 - 1,
-	type:	KMI_KEYBOARD,
+	.base		= IO_ADDRESS(KMI0_BASE),
+	.irq		= IRQ_KMIINT0,
+	.divisor	= 24 / 8 - 1,
+	.type		= KMI_KEYBOARD,
 };
 
 static struct kmi_info integrator_mouse __initdata = {
-	base:	IO_ADDRESS(KMI1_BASE),
-	irq:	IRQ_KMIINT1,
-	divisor: 24 / 8 - 1,
-	type:	KMI_MOUSE,
+	.base		= IO_ADDRESS(KMI1_BASE),
+	.irq		= IRQ_KMIINT1,
+	.divisor	= 24 / 8 - 1,
+	.type		= KMI_MOUSE,
 };
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/pci.c linux-2.4.21-rc3/arch/arm/mach-integrator/pci.c
--- linux-2.4.20/arch/arm/mach-integrator/pci.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-integrator/pci.c	2003-05-22 22:06:46.000000000 +0000
@@ -114,9 +114,9 @@
 extern void pci_v3_init(void *);
 
 struct hw_pci integrator_pci __initdata = {
-	setup_resources:	pci_v3_setup_resources,
-	init:			pci_v3_init,
-	mem_offset:		0x40000000,
-	swizzle:		integrator_swizzle,
-	map_irq:		integrator_map_irq,
+	.setup_resources	= pci_v3_setup_resources,
+	.init			= pci_v3_init,
+	.mem_offset		= 0x40000000,
+	.swizzle		= integrator_swizzle,
+	.map_irq		= integrator_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/pci_v3.c linux-2.4.21-rc3/arch/arm/mach-integrator/pci_v3.c
--- linux-2.4.20/arch/arm/mach-integrator/pci_v3.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-integrator/pci_v3.c	2003-05-22 22:06:27.000000000 +0000
@@ -390,26 +390,26 @@
 }
 
 static struct pci_ops pci_v3_ops = {
-	read_byte:	v3_read_config_byte,
-	read_word:	v3_read_config_word,
-	read_dword:	v3_read_config_dword,
-	write_byte:	v3_write_config_byte,
-	write_word:	v3_write_config_word,
-	write_dword:	v3_write_config_dword,
+	.read_byte	= v3_read_config_byte,
+	.read_word	= v3_read_config_word,
+	.read_dword	= v3_read_config_dword,
+	.write_byte	= v3_write_config_byte,
+	.write_word	= v3_write_config_word,
+	.write_dword	= v3_write_config_dword,
 };
 
 static struct resource non_mem = {
-	name:	"PCI non-prefetchable",
-	start:	0x40000000 + PCI_BUS_NONMEM_START,
-	end:	0x40000000 + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
-	flags:	IORESOURCE_MEM,
+	.name	= "PCI non-prefetchable",
+	.start	= 0x40000000 + PCI_BUS_NONMEM_START,
+	.end	= 0x40000000 + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM,
 };
 
 static struct resource pre_mem = {
-	name:	"PCI prefetchable",
-	start:	0x40000000 + PCI_BUS_PREMEM_START,
-	end:	0x40000000 + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
-	flags:	IORESOURCE_MEM | IORESOURCE_PREFETCH,
+	.name	= "PCI prefetchable",
+	.start	= 0x40000000 + PCI_BUS_PREMEM_START,
+	.end	= 0x40000000 + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
 int __init pci_v3_setup_resources(struct resource **resource)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/adsbitsy.c linux-2.4.21-rc3/arch/arm/mach-sa1100/adsbitsy.c
--- linux-2.4.20/arch/arm/mach-sa1100/adsbitsy.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/adsbitsy.c	2003-05-22 22:06:25.000000000 +0000
@@ -149,7 +149,7 @@
 }
 
 static struct sa1100_port_fns adsbitsy_port_fns __initdata = {
-	open:	adsbitsy_uart_open,
+	.open	= adsbitsy_uart_open,
 };
 
 static void __init adsbitsy_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/assabet.c linux-2.4.21-rc3/arch/arm/mach-sa1100/assabet.c
--- linux-2.4.20/arch/arm/mach-sa1100/assabet.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/assabet.c	2003-05-22 22:06:25.000000000 +0000
@@ -285,9 +285,9 @@
 }
 
 static struct sa1100_port_fns assabet_port_fns __initdata = {
-	set_mctrl:	assabet_set_mctrl,
-	get_mctrl:	assabet_get_mctrl,
-	pm:		assabet_uart_pm,
+	.set_mctrl	= assabet_set_mctrl,
+	.get_mctrl	= assabet_get_mctrl,
+	.pm		= assabet_uart_pm,
 };
 
 static void __init assabet_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/badge4.c linux-2.4.21-rc3/arch/arm/mach-sa1100/badge4.c
--- linux-2.4.20/arch/arm/mach-sa1100/badge4.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/badge4.c	2003-05-22 22:06:52.000000000 +0000
@@ -14,6 +14,7 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/cpu-sa1100.c linux-2.4.21-rc3/arch/arm/mach-sa1100/cpu-sa1100.c
--- linux-2.4.20/arch/arm/mach-sa1100/cpu-sa1100.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/cpu-sa1100.c	2003-05-22 22:06:26.000000000 +0000
@@ -216,7 +216,7 @@
 
 
 static struct notifier_block sa1100_dram_block = {
-	notifier_call: sa1100_dram_notifier,
+	.notifier_call = sa1100_dram_notifier,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/h3600.c linux-2.4.21-rc3/arch/arm/mach-sa1100/h3600.c
--- linux-2.4.20/arch/arm/mach-sa1100/h3600.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/h3600.c	2003-05-22 22:06:38.000000000 +0000
@@ -144,11 +144,11 @@
 }
 
 static struct ipaq_model_ops h3100_model_ops __initdata = {
-	model	     : IPAQ_H3100,
-	generic_name : "3100",
-	initialize   : h3100_init_egpio,
-	control      : h3100_control_egpio,
-	read	     : h3100_read_egpio
+	.model		= IPAQ_H3100,
+	.generic_name	= "3100",
+	.initialize	= h3100_init_egpio,
+	.control	= h3100_control_egpio,
+	.read		= h3100_read_egpio
 };
 
 
@@ -223,11 +223,11 @@
 }
 
 static struct ipaq_model_ops h3600_model_ops __initdata = {
-	model	     : IPAQ_H3600,
-	generic_name : "3600",
-	initialize   : h3600_init_egpio,
-	control      : h3600_control_egpio,
-	read	     : h3600_read_egpio
+	.model		= IPAQ_H3600,
+	.generic_name	= "3600",
+	.initialize	= h3600_init_egpio,
+	.control	= h3600_control_egpio,
+	.read		= h3600_read_egpio
 };
 
 /************************* H3800 *************************/
@@ -331,11 +331,11 @@
 }
 
 static struct ipaq_model_ops h3800_model_ops __initdata = {
-	model	     : IPAQ_H3800,
-	generic_name : "3800",
-	initialize   : h3800_init_egpio,
-	control      : h3800_control_egpio,
-	read	     : h3800_read_egpio
+	.model		= IPAQ_H3800,
+	.generic_name	= "3800",
+	.initialize	= h3800_init_egpio,
+	.control	= h3800_control_egpio,
+	.read		= h3800_read_egpio
 };
 
 
@@ -468,12 +468,12 @@
 }
 
 static struct sa1100_port_fns h3600_port_fns __initdata = {
-	set_mctrl:	h3600_uart_set_mctrl,
-	get_mctrl:	h3600_uart_get_mctrl,
-	pm:		h3600_uart_pm,
-	set_wake:	h3600_uart_set_wake,
-	open:		h3600_uart_open,
-	close:		h3600_uart_close,
+	.set_mctrl	= h3600_uart_set_mctrl,
+	.get_mctrl	= h3600_uart_get_mctrl,
+	.pm		= h3600_uart_pm,
+	.set_wake	= h3600_uart_set_wake,
+	.open		= h3600_uart_open,
+	.close		= h3600_uart_close,
 };
 
 static struct map_desc h3600_io_desc[] __initdata = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/neponset.c linux-2.4.21-rc3/arch/arm/mach-sa1100/neponset.c
--- linux-2.4.20/arch/arm/mach-sa1100/neponset.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/neponset.c	2003-05-22 22:06:44.000000000 +0000
@@ -54,9 +54,9 @@
 }
 
 static struct irqaction neponset_irq = {
-	name:		"Neponset",
-	handler:	neponset_IRQ_demux,
-	flags:		SA_INTERRUPT
+	.name		= "Neponset",
+	.handler	= neponset_IRQ_demux,
+	.flags		= SA_INTERRUPT
 };
 
 static void __init neponset_init_irq(void)
@@ -214,8 +214,8 @@
 }
 
 static struct sa1100_port_fns neponset_port_fns __initdata = {
-	set_mctrl:	neponset_set_mctrl,
-	get_mctrl:	neponset_get_mctrl,
+	.set_mctrl	= neponset_set_mctrl,
+	.get_mctrl	= neponset_get_mctrl,
 };
 
 void __init neponset_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/sa1111.c linux-2.4.21-rc3/arch/arm/mach-sa1100/sa1111.c
--- linux-2.4.20/arch/arm/mach-sa1100/sa1111.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/sa1111.c	2003-05-22 22:06:52.000000000 +0000
@@ -35,7 +35,7 @@
 #include "sa1111.h"
 
 struct resource sa1111_resource = {
-	name:	"SA1111",
+	.name	= "SA1111",
 };
 
 EXPORT_SYMBOL(sa1111_resource);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/simpad.c linux-2.4.21-rc3/arch/arm/mach-sa1100/simpad.c
--- linux-2.4.20/arch/arm/mach-sa1100/simpad.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/simpad.c	2003-05-22 22:06:26.000000000 +0000
@@ -76,7 +76,7 @@
 }
 
 static struct sa1100_port_fns simpad_port_fns __initdata = {
-	pm:	simpad_uart_pm,
+	.pm	= simpad_uart_pm,
 };
 
 static void __init simpad_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/system3.c linux-2.4.21-rc3/arch/arm/mach-sa1100/system3.c
--- linux-2.4.20/arch/arm/mach-sa1100/system3.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-sa1100/system3.c	2003-05-22 22:06:24.000000000 +0000
@@ -107,19 +107,19 @@
 };
 
 static struct sa1100_port_fns system3_port_fns __initdata = {
-	set_mctrl:	system3_set_mctrl,
-	get_mctrl:	system3_get_mctrl,
-	pm:		system3_uart_pm,
+	.set_mctrl	= system3_set_mctrl,
+	.get_mctrl	= system3_get_mctrl,
+	.pm		= system3_uart_pm,
 };
 
 static struct irqaction system3_irq = {
-	name:		"PT Digital Board SA1111 IRQ",
-	handler:	system3_IRQ_demux,
-	flags:		SA_INTERRUPT
+	.name		= "PT Digital Board SA1111 IRQ",
+	.handler	= system3_IRQ_demux,
+	.flags		= SA_INTERRUPT
 };
 
 static struct notifier_block system3_clkchg_block = {
-	notifier_call:	sdram_notifier,
+	.notifier_call	= sdram_notifier,
 };
 
 /**********************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-shark/pci.c linux-2.4.21-rc3/arch/arm/mach-shark/pci.c
--- linux-2.4.20/arch/arm/mach-shark/pci.c	2000-09-19 15:31:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mach-shark/pci.c	2003-05-22 22:06:40.000000000 +0000
@@ -21,7 +21,7 @@
 }
 
 struct hw_pci shark_pci __initdata = {
-	init: via82c505_init,
-	swizzle: no_swizzle,
-	map_irq: shark_map_irq
+	.init		= via82c505_init,
+	.swizzle	= no_swizzle,
+	.map_irq	= shark_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mm/discontig.c linux-2.4.21-rc3/arch/arm/mm/discontig.c
--- linux-2.4.20/arch/arm/mm/discontig.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-rc3/arch/arm/mm/discontig.c	2003-05-22 22:06:51.000000000 +0000
@@ -20,7 +20,7 @@
 #endif
 
 /*
- * Our node_data structure for discontigous memory.
+ * Our node_data structure for discontiguous memory.
  */
 
 static bootmem_data_t node_bootmem_data[NR_NODES];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/compressed/decompress.ld linux-2.4.21-rc3/arch/cris/boot/compressed/decompress.ld
--- linux-2.4.20/arch/cris/boot/compressed/decompress.ld	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/boot/compressed/decompress.ld	2003-05-22 22:06:26.000000000 +0000
@@ -13,6 +13,7 @@
 		_stext = . ;
 		*(.text)
 		*(.rodata)
+		*(.rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/rescue/Makefile linux-2.4.21-rc3/arch/cris/boot/rescue/Makefile
--- linux-2.4.20/arch/cris/boot/rescue/Makefile	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/boot/rescue/Makefile	2003-05-22 22:06:42.000000000 +0000
@@ -53,7 +53,7 @@
 
 modules:
 
-modules-install:
+modules_install:
 
 depend:
 	$(CC) -M *.S > .depend
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/config.in linux-2.4.21-rc3/arch/cris/config.in
--- linux-2.4.20/arch/cris/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/config.in	2003-05-22 22:06:25.000000000 +0000
@@ -154,6 +154,11 @@
 
 source drivers/md/Config.in
 
+source drivers/pcmcia/Config.in
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+   define_bool CONFIG_VIRTUAL_BUS y
+fi
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Config.in linux-2.4.21-rc3/arch/cris/drivers/Config.in
--- linux-2.4.20/arch/cris/drivers/Config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/Config.in	2003-05-22 22:06:38.000000000 +0000
@@ -26,46 +26,150 @@
   bool '  Use fast timers for serial DMA flush (experimental)' CONFIG_ETRAX_SERIAL_FAST_TIMER
   if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then
     bool '  Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-    if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
+    if [ "$CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
       int '  Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
     fi
   fi
   bool '  Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0
   if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then
-    bool '  Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
-      int '    Ser0 RI  on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
-      int '    Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
-      int '    Ser0 CD  on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+  choice 'Ser0 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PA_BIT 4
+      int '    Ser0 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PA_BIT 5
+      int '    Ser0 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PA_BIT 6
+      int '    Ser0 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
+      int '    Ser0 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
+      int '    Ser0 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
+      int '    Ser0 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PB_BIT -1
     fi
   fi
 
   bool '  Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1
   if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then
-    bool '  Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
-      int '    Ser1 RI  on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
-      int '    Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
-      int '    Ser1 CD  on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+  choice 'Ser1 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PA_BIT 4
+      int '    Ser1 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PA_BIT 5
+      int '    Ser1 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PA_BIT 6
+      int '    Ser1 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
+      int '    Ser1 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
+      int '    Ser1 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
+      int '    Ser1 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PB_BIT -1
     fi
   fi
+
   if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \
        "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
     comment 'Make sure you dont have the same PB bits more than once!'
   fi
   bool '  Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2
   if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then
-    bool '    Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
-    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then
-      int '      Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
-      int '      Ser2 RI  on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
-      int '      Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
-      int '      Ser2 CD  on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
-    fi 
+  choice 'Ser2 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
+      int '    Ser2 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
+      int '    Ser2 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
+      int '    Ser2 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PB_BIT 4
+      int '    Ser2 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PB_BIT 5
+      int '    Ser2 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PB_BIT 6
+      int '    Ser2 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PB_BIT -1
+    fi
   fi
   bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
+  if [ "$CONFIG_ETRAX_SERIAL_PORT3" = "y" ]; then
+  choice 'Ser3 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      int '    Ser3 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      int '    Ser3 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      int '    Ser3 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      int '    Ser3 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      int '    Ser3 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      int '    Ser3 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    fi
+  fi
   bool '  RS-485 support' CONFIG_ETRAX_RS485
   if [ "$CONFIG_ETRAX_RS485" = "y" ]; then
     bool '    RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA
@@ -139,7 +243,6 @@
 	define_bool CONFIG_MTD y
 
 	define_bool CONFIG_MTD_CFI y
-	define_bool CONFIG_MTD_CFI_INTELEXT n
 	define_bool CONFIG_MTD_CFI_AMDSTD y
 
 	define_bool CONFIG_MTD_OBSOLETE_CHIPS y
@@ -148,6 +251,7 @@
 	define_bool CONFIG_MTD_CHAR y
 	define_bool CONFIG_MTD_BLOCK y
 	define_bool CONFIG_MTD_PARTITIONS y
+	define_bool CONFIG_MTD_CONCAT y
 fi
 
 bool 'I2C support' CONFIG_ETRAX_I2C
@@ -209,6 +313,7 @@
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
   int '  DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1
   int '  DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0
+  int '  DS1302 Trickle charger value' CONFIG_ETRAX_DS1302_TRICKLE_CHARGE 0
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Makefile linux-2.4.21-rc3/arch/cris/drivers/Makefile
--- linux-2.4.20/arch/cris/drivers/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/Makefile	2003-05-22 22:06:24.000000000 +0000
@@ -18,6 +18,7 @@
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)  += sync_serial.o
 obj-$(CONFIG_ETRAX_PARPORT)             += parport.o
 obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
+obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
 
 
 obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/axisflashmap.c linux-2.4.21-rc3/arch/cris/drivers/axisflashmap.c
--- linux-2.4.20/arch/cris/drivers/axisflashmap.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/axisflashmap.c	2003-05-22 22:06:51.000000000 +0000
@@ -11,6 +11,26 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.28  2002/10/01 08:08:43  jonashg
+ * The first partition ends at the start of the partition table.
+ *
+ * Revision 1.27  2002/08/21 09:23:13  jonashg
+ * Speling.
+ *
+ * Revision 1.26  2002/08/21 08:35:20  jonashg
+ * Cosmetic change to printouts.
+ *
+ * Revision 1.25  2002/08/21 08:15:42  jonashg
+ * Made it compile even without CONFIG_MTD_CONCAT defined.
+ *
+ * Revision 1.24  2002/08/20 13:12:35  jonashg
+ * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
+ *   the results.
+ * * Removed compile time tests concerning how the mtdram driver has been
+ *   configured. The user will know about the misconfiguration at runtime
+ *   instead. (The old approach made it impossible to use mtdram for anything
+ *   else than RAM boot).
+ *
  * Revision 1.23  2002/05/13 12:12:28  johana
  * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
  * be informative at runtime.
@@ -98,13 +118,15 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 
-#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
 #include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
+#include <asm/sv_addr_ag.h>
 
 #ifdef CONFIG_CRIS_LOW_MAP
 #define FLASH_UNCACHED_ADDR  KSEG_8
@@ -114,63 +136,65 @@
 #define FLASH_CACHED_ADDR    KSEG_F
 #endif
 
-/*
- * WINDOW_SIZE is the total size where the flash chips may be mapped.
- * MTD probes should find all devices there and it does not matter
- * if there are unmapped gaps or aliases (mirrors of flash devices).
- * The MTD probes will ignore them.
- */
-
-#define WINDOW_SIZE  (128 * 1024 * 1024)
-
-extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
 
-/* 
- * Map driver
- *
- * We run into tricky coherence situations if we mix cached with uncached
- * accesses to we use the uncached version here.
- */
+/* Map driver functions. */
 
 static __u8 flash_read8(struct map_info *map, unsigned long ofs)
 {
-	return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u8 *)(map->map_priv_1 + ofs);
 }
 
 static __u16 flash_read16(struct map_info *map, unsigned long ofs)
 {
-	return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u16 *)(map->map_priv_1 + ofs);
 }
 
 static __u32 flash_read32(struct map_info *map, unsigned long ofs)
 {
-	return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(volatile unsigned int *)(map->map_priv_1 + ofs);
 }
 
 static void flash_copy_from(struct map_info *map, void *to,
 			    unsigned long from, ssize_t len)
 {
-	memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
 }
 
 static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u8 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u16 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
-	*(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u32 *)(map->map_priv_1 + adr) = d;
 }
 
-static struct map_info axis_map = {
-	name: "Axis flash",
-	size: WINDOW_SIZE,
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+	name: "cse0",
+	size: MEM_CSE0_SIZE,
 	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
 	read8: flash_read8,
 	read16: flash_read16,
@@ -179,15 +203,35 @@
 	write8: flash_write8,
 	write16: flash_write16,
 	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR
 };
 
-/* If no partition-table was found, we use this default-set.
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
  */
+static struct map_info map_cse1 = {
+	name: "cse1",
+	size: MEM_CSE1_SIZE,
+	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
+	read8: flash_read8,
+	read16: flash_read16,
+	read32: flash_read32,
+	copy_from: flash_copy_from,
+	write8: flash_write8,
+	write16: flash_write16,
+	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
 
+/* If no partition-table was found, we use this default-set. */
 #define MAX_PARTITIONS         7  
 #define NUM_DEFAULT_PARTITIONS 3
 
-/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+/*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
  * size of one flash block and "filesystem"-partition needs 5 blocks to be able
  * to use JFFS.
  */
@@ -209,10 +253,11 @@
 	}
 };
 
+/* Initialize the ones normally used. */
 static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	{
 		name: "part0",
-		size: 0,
+		size: CONFIG_ETRAX_PTABLE_SECTOR,
 		offset: 0
 	},
 	{
@@ -247,48 +292,118 @@
 	},
 };
 
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+	struct mtd_info *mtd_cs = NULL;
+
+	printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+	       map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+	mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+	if (!mtd_cs) {
+		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	}
+#endif
+
+	return mtd_cs;
+}
+
 /* 
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
  */
-static struct mtd_info *mymtd;
+static struct mtd_info *flash_probe(void)
+{
+	struct mtd_info *mtd_cse0;
+	struct mtd_info *mtd_cse1;
+	struct mtd_info *mtd_cse;
+
+	mtd_cse0 = probe_cs(&map_cse0);
+	mtd_cse1 = probe_cs(&map_cse1);
+
+	if (!mtd_cse0 && !mtd_cse1) {
+		/* No chip found. */
+		return NULL;
+	}
+
+	if (mtd_cse0 && mtd_cse1) {
+#ifdef CONFIG_MTD_CONCAT
+		struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
+		
+		/* Since the concatenation layer adds a small overhead we
+		 * could try to figure out if the chips in cse0 and cse1 are
+		 * identical and reprobe the whole cse0+cse1 window. But since
+		 * flash chips are slow, the overhead is relatively small.
+		 * So we use the MTD concatenation layer instead of further
+		 * complicating the probing procedure.
+		 */
+		mtd_cse = mtd_concat_create(mtds,
+					    sizeof(mtds) / sizeof(mtds[0]),
+					    "cse0+cse1");
+#else
+		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+		mtd_cse = NULL;
+#endif
+		if (!mtd_cse) {
+			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+			       map_cse0.name, map_cse1.name);
+
+			/* The best we can do now is to only use what we found
+			 * at cse0.
+			 */ 
+			mtd_cse = mtd_cse0;
+			map_destroy(mtd_cse1);
+		}
+	} else {
+		mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
+	}
+
+	return mtd_cse;
+}
 
-/* CFI-scan the flash, and if there was a chip, read the partition-table
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
  * and register the partitions with MTD.
  */
-
-static int __init
-init_axis_flash(void)
+static int __init init_axis_flash(void)
 {
+	struct mtd_info *mymtd;
 	int err = 0;
 	int pidx = 0;
 	struct partitiontable_head *ptable_head;
 	struct partitiontable_entry *ptable;
-	int use_default_ptable = 1; /* Until proven otherwise */
-	const char *pmsg = "  /dev/flash%d at 0x%x, size 0x%x\n";
-
-	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
-	       WINDOW_SIZE, FLASH_CACHED_ADDR);
-#ifdef CONFIG_MTD_AMDSTD
-	mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map);
-#endif
+	int use_default_ptable = 1; /* Until proven otherwise. */
+	const char *pmsg = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
 
-#ifdef CONFIG_MTD_CFI
-	if (!mymtd) {
-		mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map);
+	if (!(mymtd = flash_probe())) {
+		/* There's no reason to use this module if no flash chip can
+		 * be identified. Make sure that's understood.
+		 */
+		panic("axisflashmap found no flash chip!\n");
 	}
-#endif
 
-	if(!mymtd) {
-		printk("%s: No flash chip found!\n", axis_map.name);
-		return -ENXIO;
-	}
+	printk("%s: 0x%08x bytes of flash memory.\n",
+	       mymtd->name, mymtd->size);
 
 	mymtd->module = THIS_MODULE;
 
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
-		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
-	pidx++;  /* first partition is always set to the default */
+		      CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
+	pidx++;  /* First partition is always set to the default. */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
 	    && (ptable_head->size <
@@ -322,20 +437,17 @@
 			csum += *p++;
 			csum += *p++;
 		}
-		/* printk("  total csum: 0x%08X 0x%08X\n",
-		   csum, ptable_head->checksum); */
 		ptable_ok = (csum == ptable_head->checksum);
 
 		/* Read the entries and use/show the info.  */
-		printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
-		       (ptable_ok ? "valid" : "invalid"),
-		       (unsigned long)ptable_head,
-		       (unsigned long)max_addr);
+		printk(" Found a%s partition table at 0x%p-0x%p.\n",
+		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
+		       max_addr);
 
 		/* We have found a working bootblock.  Now read the
-		   partition table.  Scan the table.  It ends when
-		   there is 0xffffffff, that is, empty flash.  */
-		
+		 * partition table.  Scan the table.  It ends when
+		 * there is 0xffffffff, that is, empty flash.
+		 */
 		while (ptable_ok
 		       && ptable->offset != 0xffffffff
 		       && ptable < max_addr
@@ -352,59 +464,64 @@
 		use_default_ptable = !ptable_ok;
 	}
 
+	if (romfs_in_flash) {
+		/* Add an overlapping device for the root partition (romfs). */
+
+		axis_partitions[pidx].name = "romfs";
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+		printk(" Adding readonly flash partition for romfs image:\n");
+		printk(pmsg, pidx, axis_partitions[pidx].offset,
+		       axis_partitions[pidx].size);
+		pidx++;
+	}
+
 	if (use_default_ptable) {
-		printk(" Using default partition table\n");
+		printk(" Using default partition table.\n");
 		err = add_mtd_partitions(mymtd, axis_default_partitions,
 		                         NUM_DEFAULT_PARTITIONS);
 	} else {
-		if (romfs_in_flash) {
-			axis_partitions[pidx].name = "romfs";
-			axis_partitions[pidx].size = romfs_length;
-			axis_partitions[pidx].offset = romfs_start -
-						       FLASH_CACHED_ADDR;
-			axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
-
-			printk(" Adding readonly partition for romfs image:\n");
-			printk(pmsg, pidx, axis_partitions[pidx].offset,
-			       axis_partitions[pidx].size);
-			pidx++;
-		}
-
 		err = add_mtd_partitions(mymtd, axis_partitions, pidx);
 	}
-	if (!err && !romfs_in_flash) {
-#ifdef CONFIG_MTD_MTDRAM
-		/* Allocate, initialise and forget the mtd ram struct
-		 * when booting from RAM
-		 */
-		struct mtd_info *romfs_mtd = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-		printk("MTD RAM device romfs_start: 0x%08lX len %lu\n",
-		       romfs_start, romfs_length);
 
-#if (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
-#error "You must set CONFIG_MTDRAM_TOTAL_SIZE and CONFIG_MTDRAM_ABS_POS to 0"
-#endif
-		err = mtdram_init_device(romfs_mtd, (void*)romfs_start, 
-		                         romfs_length, "romfs in RAM");
+	if (err) {
+		panic("axisflashmap could not add MTD partitions!\n");
+	}
+
+	if (!romfs_in_flash) {
+		/* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+		/* No use trying to boot this kernel from RAM. Panic! */
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device due to kernel (mis)configuration!\n");
+		panic("This kernel cannot boot from RAM!\n");
 #else
-#warning ######################################
-#warning # You must enable CONFIG_MTD_MTDRAM  #
-#warning # with TOTAL_SIZE 0 and ABS_POS 0 to # 
-#warning # be able to boot with cramfs in RAM #
-#warning ######################################
-/* Maybe overkill to save these bytes in non debug builds, but let's do it..
- * (No point in printing if we don't have a debug port anyway...)
- */
-#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
-		printk("## Can't mount romfs in RAM using MTDRAM.\n");
-		printk("## You must enable MTD_MTDRAM with TOTAL_SIZE 0 and ABS_POS 0\n");
+		struct mtd_info *mtd_ram;
+
+		mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+						     GFP_KERNEL);
+		if (!mtd_ram) {
+			panic("axisflashmap couldn't allocate memory for "
+			      "mtd_info!\n");
+		}
+
+		printk(" Adding RAM partition for romfs image:\n");
+		printk(pmsg, pidx, romfs_start, romfs_length);
+
+		err = mtdram_init_device(mtd_ram, (void*)romfs_start, 
+		                         romfs_length, "romfs");
+		if (err) {
+			panic("axisflashmap could not initialize MTD RAM "
+			      "device!\n");
+		}
 #endif
-#endif /* CONFIG_MTD_MTDRAM */
 	}
+
 	return err;
 }
 
-/* This adds the above to the kernels init-call chain */
-
+/* This adds the above to the kernels init-call chain. */
 module_init(init_axis_flash);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/Makefile linux-2.4.21-rc3/arch/cris/drivers/bluetooth/Makefile
--- linux-2.4.20/arch/cris/drivers/bluetooth/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/bluetooth/Makefile	2003-05-22 22:06:48.000000000 +0000
@@ -1,19 +1,10 @@
-include $(APPS)/Rules.elinux
+include $(AXIS_TOP_DIR)/tools/build/Rules.axis
 
 all:
 
 install:	src/bluetooth.c include/btcommon.h
 	ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
-	if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
-	  echo '' >> ../Config.in; \
-	  echo '# The following if statement was added by arch/cris/drivers/bluetooth/Makefile' >> ../Config.in; \
-	  echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
-	  echo '  source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
-	  echo 'fi' >> ../Config.in; \
-	fi
-	if ! grep bluetooth/src/bt.o ../Makefile; then \
-	  perl -pi -e "s:include:\# The following two lines were added by arch/cris/drivers/bluetooth/Makefile\nobj-\\\$$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH)              += bluetooth/src\n\ninclude:" ../Makefile; \
-	fi
+	(cd .. && patch -N -r /tmp/bt.rej < bluetooth/bt.patch >/dev/null || true)
 
 clean:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch linux-2.4.21-rc3/arch/cris/drivers/bluetooth/bt.patch
--- linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/bluetooth/bt.patch	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,33 @@
+Index: Config.in
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Config.in,v
+retrieving revision 1.46
+diff -u -d -r1.46 Config.in
+--- Config.in	11 Oct 2002 16:14:33 -0000	1.46
++++ Config.in	31 Oct 2002 08:44:37 -0000
+@@ -317,3 +317,8 @@
+ fi
+ 
+ endmenu
++
++# The following if statement was added by arch/cris/drivers/bluetooth/Makefile
++if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
++  source arch/cris/drivers/bluetooth/src/Config.in
++fi
+Index: Makefile
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Makefile,v
+retrieving revision 1.20
+diff -u -d -r1.20 Makefile
+--- Makefile	14 Aug 2002 18:32:33 -0000	1.20
++++ Makefile	31 Oct 2002 08:44:37 -0000
+@@ -24,5 +24,9 @@
+ obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
+ subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave
+ 
++# The following two lines were added by arch/cris/drivers/bluetooth/Makefile
++obj-$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o
++subdir-$(CONFIG_BLUETOOTH)              += bluetooth/src
++
+ include $(TOPDIR)/Rules.make
+ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ds1302.c linux-2.4.21-rc3/arch/cris/drivers/ds1302.c
--- linux-2.4.20/arch/cris/drivers/ds1302.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/ds1302.c	2003-05-22 22:06:52.000000000 +0000
@@ -7,6 +7,13 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.15  2002/10/11 16:14:33  johana
+*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
+*! trcklecharge register.
+*!
+*! Revision 1.14  2002/10/10 12:15:38  magnusmn
+*! Added support for having the RST signal on bit g0
+*!
 *! Revision 1.13  2002/05/29 15:16:08  johana
 *! Removed unused variables.
 *!
@@ -88,7 +95,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
+*! $Id: ds1302.c,v 1.15 2002/10/11 16:14:33 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -493,17 +500,25 @@
 { 
 	if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#if CONFIG_ETRAX_DS1302_RSTBIT == 27
 		/*
 		 * The only way to set g27 to output is to enable ATA.
 		 *
 		 * Make sure that R_GEN_CONFIG is setup correct.
 		 */
     		genconfig_shadow = ((genconfig_shadow &
-				     ~IO_MASK(R_GEN_CONFIG, ata))
-				   | 
+				     ~IO_MASK(R_GEN_CONFIG, ata)) | 
 				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
     		*R_GEN_CONFIG = genconfig_shadow;
-    		if (!ds1302_probe())
+#elif CONFIG_ETRAX_DS1302_RSTBIT == 0
+		
+		/* Set the direction of this bit to out. */		
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
+				   (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#endif
+		if (!ds1302_probe())
       			return -1;
 #else
     		return -1;
@@ -515,5 +530,8 @@
 		       ds1302_name, RTC_MAJOR_NR);
 		return -1;
 	}
+	/* Initialise trickle charger */
+	ds1302_writereg(RTC_TRICKLECHARGER,
+			RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/eeprom.c linux-2.4.21-rc3/arch/cris/drivers/eeprom.c
--- linux-2.4.20/arch/cris/drivers/eeprom.c	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/eeprom.c	2003-05-22 22:06:41.000000000 +0000
@@ -808,7 +808,7 @@
       i2c_outbyte( eeprom.select_cmd | 1 );
     }
 
-    if(i2c_getack());
+    if(i2c_getack())
     {
       break;
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ethernet.c linux-2.4.21-rc3/arch/cris/drivers/ethernet.c
--- linux-2.4.20/arch/cris/drivers/ethernet.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/ethernet.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.30 2002/05/07 18:50:08 johana Exp $
+/* $Id: ethernet.c,v 1.34 2002/12/13 07:17:44 starvik Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,22 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.34  2002/12/13 07:17:44  starvik
+ * Basic ethtool and MII ioctls
+ * Handle out of memory when allocating new buffers
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
  * Revision 1.30  2002/05/07 18:50:08  johana
  * Correct spelling in comments.
  *
@@ -152,9 +168,12 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <linux/if.h>
+#include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
 #include <asm/io.h>         /* LED_* I/O functions */
@@ -163,6 +182,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/ethernet.h>
+#include <asm/cache.h>
+#include <asm/uaccess.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -264,10 +285,10 @@
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
@@ -304,12 +325,12 @@
 static int e100_open(struct net_device *dev);
 static int e100_set_mac_address(struct net_device *dev, void *addr);
 static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
 static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -324,6 +345,7 @@
 static void e100_negotiate(void);
 
 static unsigned short e100_get_mdio_reg(unsigned char reg_num);
+static void e100_set_mdio_reg(unsigned char reg, unsigned short data);
 static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
 static void e100_send_mdio_bit(unsigned char bit);
 static unsigned char e100_receive_mdio_bit(void);
@@ -399,11 +421,14 @@
 	/* Initialise receive descriptors */
 
 	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		/* Allocate two extra cachelines to make sure that buffer used by DMA
+		 * does not share cacheline with any other data (to avoid cache bug)
+		 */
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		RxDescList[i].descr.ctrl   = 0;
 		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
 		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].descr.buf    = virt_to_phys(RxDescList[i].skb->data);
+		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
 		RxDescList[i].descr.status = 0;
 		RxDescList[i].descr.hw_len = 0;
              
@@ -540,14 +565,14 @@
 
 	/* allocate the irq corresponding to the receiving DMA */
 
-	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit0;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
-	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit1;
 	}
@@ -685,9 +710,7 @@
 static void
 e100_negotiate(void)
 {
-	unsigned short cmd;
 	unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
-	int bitCounter;
 
 	/* Discard old speed and duplex settings */
 	data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
@@ -726,29 +749,13 @@
 			        MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
 	}
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_ADVERTISMENT_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}
+	e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data);
 
 	/* Renegotiate with link partner */
 	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
 	data |= MDIO_BC_NEGOTIATE;
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_BASE_CONTROL_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}  
+	e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data);
 }
 
 static void
@@ -816,6 +823,24 @@
 }
 
 static void
+e100_set_mdio_reg(unsigned char reg, unsigned short data)
+{
+	int bitCounter;
+	unsigned short cmd;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (reg << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+
+}
+
+static void
 e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
 {
 	int bitCounter;
@@ -958,21 +983,6 @@
 		*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
 		netif_stop_queue(dev);
 	}
-	else {
-	  /* Report any packets that have been sent */
-		while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		       myFirstTxDesc != myNextTxDesc)
-		{
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);				
-		}
-	}
 
 	spin_unlock_irq(&np->lock);
 
@@ -985,11 +995,13 @@
  */
 
 static void
-e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
  
+	/* Handle received packets */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 		/* acknowledge the eop interrupt */
 
@@ -1014,44 +1026,26 @@
 			   so we have to loop back and check if so */
 		}
 	}
-}
 
-/* the transmit dma channel interrupt
- *
- * this is supposed to free the skbuff which was pending during transmission,
- * and inform the kernel that we can send one more buffer
- */
+	/* Report any packets that have been sent */
+	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+	       myFirstTxDesc != myNextTxDesc)
+	{
+		np->stats.tx_bytes += myFirstTxDesc->skb->len;
+		np->stats.tx_packets++;
 
-static void
-e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	unsigned long irqbits = *R_IRQ_MASK2_RD;
-	struct net_local *np = (struct net_local *)dev->priv;
+		/* dma is ready with the transmission of the data in tx_skb, so now
+		   we can release the skb memory */
+		dev_kfree_skb_irq(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
 
-	/* check for a dma0_eop interrupt */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* Report all sent packets */
-		do {
-			/* acknowledge the eop interrupt */
-			*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-
-			np->stats.tx_bytes += myFirstTxDesc->skb->len;
-			np->stats.tx_packets++;
-
-			/* dma is ready with the transmission of the data in tx_skb, so now
-			   we can release the skb memory */
-			dev_kfree_skb_irq(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-
-			if (netif_queue_stopped(dev)) {
-			  	/* Queue is running, disable tx IRQ */
-			  	*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
-				netif_wake_queue(dev);
-			}
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-		} while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		         myFirstTxDesc != myNextTxDesc);
+		/* acknowledge the eop interrupt and wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+		*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
+		netif_wake_queue(dev);
 	}
 }
 
@@ -1140,11 +1134,24 @@
 		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
 	}
 	else {
-		/* Large packet, send directly to upper layers and allocate new memory */		 
+		/* Large packet, send directly to upper layers and allocate new 
+		 * memory (aligned to cache line boundary to avoid bug).
+		 * Before sending the skb to upper layers we must make sure that 
+		 * skb->data points to the aligned start of the packet. 
+		 */
+		int align;  
+		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		if (!new_skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
 		skb = myNextRxDesc->skb;
-		skb_put(skb, length);
-		myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
-		myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data);
+		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;	
+		skb_put(skb, length + align); 
+		skb_pull(skb, align); /* Remove alignment bytes */
+		myNextRxDesc->skb = new_skb;
+		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
 	}
 
 	skb->dev = dev;
@@ -1220,8 +1227,22 @@
 static int
 e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	/* Maybe default should return -EINVAL instead? */
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+
 	switch (cmd) {
+		case SIOCETHTOOL:
+			return e100_ethtool_ioctl(dev,ifr);
+		case SIOCGMIIPHY: /* Get PHY address */
+			data->phy_id = MDIO_PHYS_ADDR;
+			break;
+		case SIOCGMIIREG: /* Read MII register */
+			data->val_out = e100_get_mdio_reg(data->reg_num);
+			break;
+		case SIOCSMIIREG: /* Write MII register */
+			e100_set_mdio_reg(data->reg_num, data->val_in);
+			break;
+		/* The ioctls below should be considered obsolete but are */
+		/* still present for compatability with old scripts/apps  */	
 		case SET_ETH_SPEED_10:                  /* 10 Mbps */
 			e100_set_speed(10);
 			break;
@@ -1240,10 +1261,90 @@
 		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
 			e100_set_duplex(autoneg);
 			break;
-		default: /* Auto neg */
-			e100_set_speed(0);
-			e100_set_duplex(autoneg);
-			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+		case ETHTOOL_GSET:
+		{
+			memset((void *) &ecmd, 0, sizeof (ecmd));
+			ecmd.supported = 
+			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = MDIO_PHYS_ADDR;
+			ecmd.speed = current_speed;
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+			ecmd.advertising = ADVERTISED_TP;
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				ecmd.advertising |= ADVERTISED_Autoneg;
+			else {
+				ecmd.advertising |= 
+				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+				if (current_speed_selection == 10)
+					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+				else if (current_speed_selection == 100)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+				if (current_duplex == half)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+				else if (current_duplex == full)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+			}
+			ecmd.autoneg = AUTONEG_ENABLE;
+			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_SSET:
+		{
+			if (!capable(CAP_NET_ADMIN)) {
+				return -EPERM;
+			}
+			if (ecmd.autoneg == AUTONEG_ENABLE) {
+				e100_set_duplex(autoneg);
+				e100_set_speed(0);
+			} else {
+				e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full);
+				e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100);
+			}
+		}
+		break;
+		case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info;
+			memset((void *) &info, 0, sizeof (info));
+			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+			strncpy(info.version, "$Rev$", sizeof(info.version) - 1);
+			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+			info.regdump_len = 0;
+			info.eedump_len = 0;
+			info.testinfo_len = 0;
+			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_NWAY_RST:
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				e100_negotiate();
+		break;
+		default:
+			return -EOPNOTSUPP;
+		break;
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/gpio.c linux-2.4.21-rc3/arch/cris/drivers/gpio.c
--- linux-2.4.20/arch/cris/drivers/gpio.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/gpio.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
+/* $Id: gpio.c,v 1.21 2002/12/02 08:11:41 starvik Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,29 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.21  2002/12/02 08:11:41  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.20  2002/10/16 21:16:24  johana
+ * Added support for PA high level interrupt.
+ * That gives 2ms response time with iodtest for high levels and 2-12 ms
+ * response time on low levels if the check is not made in
+ * process.c:cpu_idle() as well.
+ *
+ * Revision 1.19  2002/10/14 18:27:33  johana
+ * Implemented alarm handling so select() now works.
+ * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
+ * cpu_idle().
+ * Otherwise I get 15-18 ms (same as doing the poll in userspace -
+ * but less overhead).
+ * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
+ * is in 2.4) as well?
+ * TODO? Perhaps call request_irq()/free_irq() only when needed?
+ * Increased version to 2.5
+ *
+ * Revision 1.18  2002/10/11 15:02:00  johana
+ * Mask inverted 8 bit value in setget_input().
+ *
  * Revision 1.17  2002/06/17 15:53:01  johana
  * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
  * that take a pointer as argument and thus can handle 32 bit ports (G)
@@ -95,11 +118,19 @@
 #include <asm/svinto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/irq.h>
 
 #define GPIO_MAJOR 120  /* experimental MAJOR number */
 
 #define D(x)
 
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+	
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -137,6 +168,8 @@
 
 static struct gpio_private *alarmlist = 0;
 
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+
 /* Port A and B use 8 bit access, but Port G is 32 bit */
 #define NUM_PORTS (GPIO_MINOR_B+1)
 
@@ -197,21 +230,81 @@
 
 
 static unsigned int 
-gpio_poll(struct file *filp,
-	  struct poll_table_struct *wait)
+gpio_poll(struct file *file,
+	  poll_table *wait)
 {
-	/* TODO poll on alarms! */
-#if 0
-	if (!ANYTHING_WANTED) {
-		D(printk("gpio_select sleeping task\n"));
-		select_wait(&gpio_wq, table);
+	unsigned int mask = 0;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned long data;
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor == GPIO_MINOR_A) {
+		unsigned long tmp;
+		data = *R_PORT_PA_DATA;
+		/* PA has support for high level interrupt -
+		 * lets activate for those low and with highalarm set
+		 */
+		tmp = ~data & priv->highalarm & 0xFF;
+		*R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
+	} else if (priv->minor == GPIO_MINOR_B)
+		data = *R_PORT_PB_DATA;
+	else if (priv->minor == GPIO_MINOR_G)
+		data = *R_PORT_G_DATA;
+	else
 		return 0;
+	
+	if ((data & priv->highalarm) ||
+	    (~data & priv->lowalarm)) {
+		mask = POLLIN|POLLRDNORM;
+	}
+	
+	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+void etrax_gpio_wake_up_check(void)
+{
+	struct gpio_private *priv = alarmlist;
+	unsigned long data = 0;
+	while (priv) {
+		if (USE_PORTS(priv)) {
+			data = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			data = *R_PORT_G_DATA;
+		}
+		if ((data & priv->highalarm) ||
+		    (~data & priv->lowalarm)) {
+			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			wake_up_interruptible(&priv->alarm_wq);
+		}
+		priv = priv->next;
+	}
+}
+
+static void 
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
+	}
+}
+
+static void 
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long tmp;
+	/* Find what PA interrupts are active */
+	tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF;
+	/* Clear them.. */
+	/* NOTE: Maybe we need to be more careful here if some other
+	 * driver uses PA interrupt as well?
+	 */
+	*R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR);
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
 	}
-	D(printk("gpio_select ready\n"));
-#endif
-	return 1;
 }
 
+
 static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
                           loff_t *off)
 {
@@ -322,7 +415,7 @@
 {
 	struct gpio_private *p = alarmlist;
 	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
-
+	
 	/* unlink from alarmlist and free the private structure */
 
 	if (p == todel) {
@@ -334,7 +427,17 @@
 	}
 
 	kfree(todel);
-
+	/* Check if there are still any alarms set */
+	p = alarmlist;
+	while (p) {
+		if (p->highalarm | p->lowalarm) {
+			gpio_some_alarms = 1;
+			return 0;
+		}
+		p = p->next;
+	}
+	gpio_some_alarms = 0;
+		
 	return 0;
 }
 
@@ -353,7 +456,7 @@
 		*priv->dir = *priv->dir_shadow &= 
 		~((unsigned char)arg & priv->changeable_dir);
 		restore_flags(flags);
-		return ~(*priv->dir_shadow);
+		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
 	} else if (priv->minor == GPIO_MINOR_G) {
 		/* We must fiddle with R_GEN_CONFIG to change dir */
 		if (((arg & dir_g_in_bits) != arg) && 
@@ -491,10 +594,12 @@
 	case IO_HIGHALARM:
 		// set alarm when bits with 1 in arg go high
 		priv->highalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_LOWALARM:
 		// set alarm when bits with 1 in arg go low
 		priv->lowalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_CLRALARM:
 		// clear alarm for bits with 1 in arg
@@ -760,8 +865,21 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
-
+	printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
+	/* We call etrax_gpio_wake_up_check() from timer interrupt and
+	 * from cpu_idle() in kernel/process.c
+	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+	 * in some tests.
+	 */  
+	if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
+		printk("err: timer0 irq for gpio\n");
+	}
+	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
+		printk("err: PA irq for gpio\n");
+	}
+	
 	return res;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/i2c.c linux-2.4.21-rc3/arch/cris/drivers/i2c.c
--- linux-2.4.20/arch/cris/drivers/i2c.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/i2c.c	2003-05-22 22:06:26.000000000 +0000
@@ -12,6 +12,12 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.9  2002/10/31 15:32:26  starvik
+*! Update Port B register and shadow even when running with hardware support
+*!   to avoid glitches when reading bits
+*! Never set direction to out in i2c_inbyte
+*! Removed incorrect clock togling at end of i2c_inbyte
+*!
 *! Revision 1.8  2002/08/13 06:31:53  starvik
 *! Made SDA and SCL line configurable
 *! Modified i2c_inbyte to work with PCF8563
@@ -47,7 +53,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
+/* $Id: i2c.c,v 1.9 2002/10/31 15:32:26 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -135,16 +141,24 @@
 
 /* enable or disable output-enable, to select output or input on the i2c bus */
 
-#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_))
-#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+#define i2c_dir_out() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); 
+#define i2c_dir_in() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
 
 /* control the i2c clock and data signals */
 
-#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x)))
+#define i2c_clk(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
 
-#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x)))
+#define i2c_data(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+	   ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
 
 /* read a bit from the i2c interface */
 
@@ -221,10 +235,11 @@
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
-		if (x & 0x80)
+		if (x & 0x80) {
 			i2c_data(I2C_DATA_HIGH);
-		else
+		} else {
 			i2c_data(I2C_DATA_LOW);
+		}
 		
 		i2c_delay(CLOCK_LOW_TIME/2);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -260,7 +275,6 @@
 
 	/* Enable I2C */
 	i2c_enable();
-	i2c_dir_out();
 	i2c_delay(CLOCK_LOW_TIME/2);
 
 	for (i = 1; i < 8; i++) {
@@ -281,12 +295,10 @@
 
 		/* Enable I2C */
 		i2c_enable();
-		i2c_dir_out();
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
-	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -416,7 +428,7 @@
 {
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ide.c linux-2.4.21-rc3/arch/cris/drivers/ide.c
--- linux-2.4.20/arch/cris/drivers/ide.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/ide.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.24 2002/04/22 11:47:21 johana Exp $
+/* $Id: ide.c,v 1.26 2002/09/17 12:16:59 bjornw Exp $
  *
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
@@ -8,6 +8,12 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.26  2002/09/17 12:16:59  bjornw
+ * Removed unnecessary cli/sti pair
+ *
+ * Revision 1.25  2002/08/19 08:07:19  matsfg
+ * Added IN_WORD.
+ *
  * Revision 1.24  2002/04/22 11:47:21  johana
  * Fix according to 2.4.19-pre7. time_after/time_before and
  * missing end of comment.
@@ -180,9 +186,14 @@
 			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
 		timeleft--;
 }
-
 unsigned char 
 IN_BYTE(ide_ioreg_t reg) {
+        /* data was in the lower 16 bits in the status reg */
+        return (unsigned char)(IN_WORD(reg));
+}
+
+unsigned short 
+IN_WORD(ide_ioreg_t reg) {
 	int status;
 	int timeleft;
 
@@ -226,7 +237,7 @@
 
 	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
 
-	return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
+        return (unsigned short)status;
 }
 
 /* PIO timing (in R_ATA_CONFIG)
@@ -303,9 +314,6 @@
 	pio = 4;
 	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
 	
-	save_flags(flags);
-	cli();
-
 	/* set pio mode! */
   	 
 	switch(pio) {
@@ -350,7 +358,6 @@
 					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
 			break;
 	}
-	restore_flags(flags);
 }
 
 void __init 
@@ -816,13 +823,13 @@
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/parport.c linux-2.4.21-rc3/arch/cris/drivers/parport.c
--- linux-2.4.20/arch/cris/drivers/parport.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/parport.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.9 2002/05/15 12:30:24 starvik Exp $
+/* $Id: parport.c,v 1.10 2002/10/03 05:54:24 starvik Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -56,11 +56,11 @@
 //#define CONFIG_PAR0_INT 1
 //#define CONFIG_PAR1_INT 1
 
-#define SETF(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)
-
-#define SETS(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 struct etrax100par_struct {
 	/* parallell port control */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/pcf8563.c linux-2.4.21-rc3/arch/cris/drivers/pcf8563.c
--- linux-2.4.20/arch/cris/drivers/pcf8563.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/pcf8563.c	2003-05-22 22:06:47.000000000 +0000
@@ -15,7 +15,7 @@
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ * $Id: pcf8563.c,v 1.4 2002/10/15 09:22:42 tobiasa Exp $
  */
 
 #include <linux/config.h>
@@ -39,7 +39,11 @@
 #define PCF8563_MAJOR 121		/* Local major number. */
 #define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
 #define PCF8563_NAME "PCF8563"
-#define DRIVER_VERSION "$Rev$"
+#define DRIVER_VERSION "$Revision: 1.4 $"
+
+/* I2C bus slave registers. */
+#define RTC_I2C_READ		0xa3
+#define RTC_I2C_WRITE		0xa2
 
 /* Two simple wrapper macros, saves a few keystrokes. */
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
@@ -59,11 +63,38 @@
 	release: pcf8563_release,
 };
 
+unsigned char
+pcf8563_readreg(int reg) 
+{
+	unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
+
+	/* The PCF8563 does not return 0 for unimplemented bits */
+	switch(reg)
+	{
+		case RTC_SECONDS:
+		case RTC_MINUTES:
+		     res &= 0x7f;
+		     break;
+		case RTC_HOURS:
+		case RTC_DAY_OF_MONTH:
+		     res &= 0x3f;
+		     break;
+		case RTC_MONTH:
+		     res = (res & 0x1f) - 1;  /* PCF8563 returns month in range 1-12 */
+		     break;
+	}
+	return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val) 
+{
+	i2c_writereg(RTC_I2C_WRITE,reg,val);
+}
+
 void
 get_rtc_time(struct rtc_time *tm)
 {
-	unsigned long flags;
-	
 	tm->tm_sec = rtc_read(RTC_SECONDS);
 	tm->tm_min = rtc_read(RTC_MINUTES);
 	tm->tm_hour = rtc_read(RTC_HOURS);
@@ -74,7 +105,7 @@
 	if (tm->tm_sec & 0x80)
 		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
 
-        tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
 	tm->tm_sec &= 0x7f;
 	tm->tm_min &= 0x7f;
 	tm->tm_hour &= 0x3f;
@@ -93,8 +124,6 @@
 pcf8563_init(void)
 {
 	unsigned char ret;
-        struct rtc_time tm;
-        
 	/*
 	 * First of all we need to reset the chip. This is done by
 	 * clearing control1, control2 and clk freq, clear the 
@@ -134,7 +163,7 @@
 		return -1;
 	}
 
-	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
         
 	/* Check for low voltage, and warn about it.. */
 	if (rtc_read(RTC_SECONDS) & 0x80)
@@ -163,7 +192,7 @@
 pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Some sanity checks. */
-	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+	if (_IOC_TYPE(cmd) != RTC_MAGIC)
 		return -ENOTTY;
 
 	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/serial.c linux-2.4.21-rc3/arch/cris/drivers/serial.c
--- linux-2.4.20/arch/cris/drivers/serial.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/serial.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
+/* $Id: serial.c,v 1.44 2002/11/21 04:28:06 hp Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,42 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.44  2002/11/21 04:28:06  hp
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.43  2002/11/15 12:02:25  pkj
+ * Make sure we have a tty in flush_to_flip_buffer() before we
+ * try to use it...
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
  * Revision 1.37  2002/08/13 13:02:37  bjornw
  * Removed some warnings because of unused code
  *
@@ -321,7 +357,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.37 $";
+static char *serial_version = "$Revision: 1.44 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -429,7 +465,7 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
                     const unsigned char *buf, int count);
-static inline int raw_write(struct tty_struct * tty, int from_user,
+extern inline int raw_write(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
 #ifdef CONFIG_ETRAX_RS485
 static int e100_write_rs485(struct tty_struct * tty, int from_user,
@@ -585,87 +621,214 @@
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 #endif
-  
 
-/* For now we assume that all bits are on the same port for each serial port */
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(R_PORT_PB_DATA):&dummy_ser[##line##]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Dummy shadow variables */
-#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_dir_ser0 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_dir_ser1 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_dir_ser2 = 0x00;
-#endif
+struct control_pins
+{
+	volatile unsigned char *dtr_port;
+	unsigned char          *dtr_shadow;
+	volatile unsigned char *ri_port;
+	unsigned char          *ri_shadow;
+	volatile unsigned char *dsr_port;
+	unsigned char          *dsr_shadow;
+	volatile unsigned char *cd_port;
+	unsigned char          *cd_shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] = 
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
+	},
 
-static unsigned char dummy_ser3 = 0x00;
-static unsigned char dummy_dir_ser3 = 0x00;
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
+	}
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Info needed for each ports extra control/status signals.
-   We only supports that all pins uses same register for each port */
 struct control_pins
 {
 	volatile unsigned char *port;
-	volatile unsigned char *shadow;
-	volatile unsigned char *dir_shadow;
+	unsigned char          *shadow;
 
-	unsigned char dtr_bit;
-	unsigned char ri_bit;
-	unsigned char dsr_bit;
-	unsigned char cd_bit;
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
 };
 
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
 static const struct control_pins e100_modem_pins[NR_PORTS] = 
 {
 	/* Ser 0 */
 	{
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
 #else
-		&dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
 	},
 
 	/* Ser 1 */
 	{
-#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
 #else
-		&dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
 	},
 
 	/* Ser 2 */
 	{
-#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-		R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
-		CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
 #else
-		&dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
 	},
 
 	/* Ser 3 */
 	{
-		&dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
 	}
 };
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
 
 #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
 unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
@@ -690,20 +853,16 @@
 
 /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
 /* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
 
 /* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
 
 /* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the memcpy_fromfs blocks while swapping in a page,
@@ -837,16 +996,17 @@
  * any general port.
  */
 
+
 static inline void 
 e100_dtr(struct e100_serial *info, int set)
 {
 #ifndef CONFIG_SVINTO_SIM
-	unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit);
+	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
 
 #ifdef SERIAL_DEBUG_IO  
 	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
 	printk("ser%i shadow before 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow,
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
 	       E100_DTR_GET(info));
 #endif
 	/* DTR is active low */
@@ -855,20 +1015,15 @@
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
+		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
 		restore_flags(flags);
 	}
 	
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].dtr_bit, !set);
-#endif
 #ifdef SERIAL_DEBUG_IO
 	printk("ser%i shadow after 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow, 
+	       info->line, *e100_modem_pins[info->line].dtr_shadow, 
 	       E100_DTR_GET(info));
 #endif
 #endif
@@ -890,6 +1045,7 @@
 #endif
 }
 
+
 /* If this behaves as a modem, RI and CD is an output */
 static inline void 
 e100_ri_out(struct e100_serial *info, int set)
@@ -897,14 +1053,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* RI is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit);
+		unsigned char mask = e100_modem_pins[info->line].ri_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].ri_shadow &= ~mask;
+		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -915,14 +1071,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* CD is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit);
+		unsigned char mask = e100_modem_pins[info->line].cd_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].cd_shadow &= ~mask;
+		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -1078,23 +1234,49 @@
  * rs_stop() and rs_start()
  *
  * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
  * ------------------------------------------------------------
  */
 
-/* FIXME - when are these used and what is the purpose ? 
- * In rs_stop we probably just can block the transmit DMA ready irq
- * and in rs_start we re-enable it (and then the old one will come).
- */
-
 static void 
 rs_stop(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+		
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		restore_flags(flags);
+	}
 }
 
 static void 
 rs_start(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		
+		restore_flags(flags);
+	}
 }
 
 /*
@@ -1341,7 +1523,7 @@
 	return 1;
 }
 
-static _INLINE_ unsigned int
+extern _INLINE_ unsigned int
 handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
 {
 	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
@@ -1567,7 +1749,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
 		if (ireg & info->irq) {  
@@ -1613,7 +1795,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for both dma_eop and dma_descr for the input dma channel */
 		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
@@ -1671,10 +1853,10 @@
 	return 1;
 }
 
-static _INLINE_ void
+extern _INLINE_ void
 flush_to_flip_buffer(struct e100_serial *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty;
 	struct etrax_recv_buffer *buffer;
 	unsigned int length;
 	unsigned long flags;
@@ -1685,6 +1867,11 @@
 	save_flags(flags);
 	cli();
 
+	if (!(tty = info->tty)) {
+		restore_flags(flags);
+		return;
+	}
+
 	length = tty->flip.count;
 
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
@@ -1773,7 +1960,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (info->uses_dma) 
+		if (info->enabled && info->uses_dma) 
 			check_flush_timeout(info);
 	}
 } /* timeout_interrupt */
@@ -1880,7 +2067,7 @@
 
 */
 
-static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
+extern void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
 {
 	unsigned char rstat = info->port[REG_STATUS];
 
@@ -2247,6 +2434,7 @@
 change_speed(struct e100_serial *info)
 {
 	unsigned int cflag;
+	unsigned long xoff;
 
 	/* first some safety checks */
 	
@@ -2316,7 +2504,13 @@
 	
 	info->port[REG_TR_CTRL] = info->tx_ctrl;
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	*((unsigned long *)&info->port[REG_XOFF]) = 0;
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+	if (info->tty->termios->c_iflag & IXON ) {
+		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+	}
+	
+	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
 #endif /* !CONFIG_SVINTO_SIM */
 
 	update_char_time(info);
@@ -2349,7 +2543,7 @@
 	restore_flags(flags);
 }
 
-static inline int 
+extern inline int 
 raw_write(struct tty_struct * tty, int from_user,
 	  const unsigned char *buf, int count)
 {
@@ -2497,7 +2691,7 @@
 
 		/* Sleep until all sent */
 		tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_FAST_TIMER
 		/* Now sleep a little more so that shift register is empty */
 		schedule_usleep(info->char_time_usec * 2);
 #endif
@@ -2805,14 +2999,15 @@
 	       E100_DSR_GET(info),
 	       E100_CTS_GET(info));
 #endif
+
 	result =  
 		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
 		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
 		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-	
+
 #ifdef SERIAL_DEBUG_IO 
 	printk("e100ser: modem state: %i 0x%08X\n", result, result);
 	{
@@ -3488,7 +3683,7 @@
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct e100_serial *info)
+extern inline int line_info(char *buf, struct e100_serial *info)
 {
 	char	stat_buf[30];
 	int	ret;
@@ -3503,17 +3698,17 @@
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
-	if (E100_RTS_GET(info))
+	if (!E100_RTS_GET(info))
 		strcat(stat_buf, "|RTS");
-	if (E100_CTS_GET(info))
+	if (!E100_CTS_GET(info))
 		strcat(stat_buf, "|CTS");
-	if (E100_DTR_GET(info))
+	if (!E100_DTR_GET(info))
 		strcat(stat_buf, "|DTR");
-	if (E100_DSR_GET(info))
+	if (!E100_DSR_GET(info))
 		strcat(stat_buf, "|DSR");
-	if (E100_CD_GET(info))
+	if (!E100_CD_GET(info))
 		strcat(stat_buf, "|CD");
-	if (E100_RI_GET(info))
+	if (!E100_RI_GET(info))
 		strcat(stat_buf, "|RI");
 
 	ret += sprintf(buf+ret, " baud:%d", info->baud);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/sync_serial.c linux-2.4.21-rc3/arch/cris/drivers/sync_serial.c
--- linux-2.4.20/arch/cris/drivers/sync_serial.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/drivers/sync_serial.c	2003-05-22 22:06:26.000000000 +0000
@@ -64,13 +64,13 @@
 #define DEFAULT_FRAME_RATE 0
 #define DEFAULT_WORD_RATE 7
 
-#define DEBUG(x) 
+#define DEBUG(x)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 typedef struct sync_port
 {
@@ -107,8 +107,7 @@
 	char in_buffer[IN_BUFFER_SIZE];
 	volatile char* readp;  /* Next byte to be read by application */
 	volatile char* writep; /* Next byte to be written by etrax */
-	int odd_output; /* 1 if writing odd nible in 12 bit mode */
-	int odd_input;  /* 1 if reading odd nible in 12 bit mode */
+	int started; /* 1 if port has been started */
 } sync_port;
 
 
@@ -221,7 +220,6 @@
 	  IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
           IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
 	start_dma_in(&ports[0]);
 #else
@@ -229,7 +227,6 @@
 	initialize_port(0);
 	if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
 #endif
 
@@ -252,7 +249,6 @@
 	  IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
 	start_dma_in(&ports[1]);
 #else
@@ -263,7 +259,6 @@
 		if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
 #endif
 #endif
 
@@ -292,12 +287,12 @@
 	struct sync_port* port = &ports[portnbr];
 
 	DEBUG(printk("Init sync serial port %d\n", portnbr));
-    
+
+	port->started = 0;    
 	port->port_nbr = portnbr;	
 	port->busy = 0;		
 	port->readp = port->in_buffer;
-	port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
-	port->odd_input = 0;
+	port->writep = port->in_buffer;
 
 	init_waitqueue_head(&port->out_wait_q);
 	init_waitqueue_head(&port->in_wait_q);
@@ -422,6 +417,10 @@
 		case SSP_MODE:
 			if (arg > 5)
 				return -EINVAL;
+			if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)
+				*R_IRQ_MASK1_CLR = 1 << port->data_avail_bit;
+			else
+				*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
 			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
 			break;
 		case SSP_FRAME_SYNC:
@@ -466,8 +465,8 @@
 			if (arg & CLOCK_NOT_GATED)
 				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal);
 			else if (arg & CLOCK_GATED)
-				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);
-    
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);    
+
 			break;
 		case SSP_IPOLARITY:
 			if (arg & CLOCK_NORMAL)
@@ -553,11 +552,10 @@
 	copy_from_user(port->out_buffer, buf, count);
 	port->outp = port->out_buffer;
 	port->out_count = count;
-	port->odd_output = 1;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
-	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	send_word(port); /* Start sender by sending first word */
+	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
@@ -586,9 +584,15 @@
 
 	count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count;
 
-	/* Make sure transmitter is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+	/* Make sure transmitter/receiver is running */
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	if (!port->use_dma)
@@ -629,9 +633,14 @@
 
 	DEBUG(printk("Read dev %d count %d\n", dev, count));
 
-	/* Make sure receiver is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	/* Calculate number of available bytes */
@@ -680,13 +689,12 @@
 			*port->data_out = *port->outp++;
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
-			port->out_count--;
-			if (port->odd_output)
-				*port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1));
-			else
-				*port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1));
-			port->odd_output = !port->odd_output;
-			port->outp++;
+			{
+				int data = (*port->outp++) << 8;
+				data |= *port->outp++;
+				port->out_count-=2;  
+				*port->data_out = data;
+			}
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
 			port->out_count-=2;
@@ -710,7 +718,7 @@
 {
 	port->out_descr.hw_len = 0;
 	port->out_descr.next = 0;
-	port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
+	port->out_descr.ctrl = d_eol | d_eop | d_wait;
 	port->out_descr.sw_len = count;
 	port->out_descr.buf = virt_to_phys(port->out_buffer);
 	port->out_descr.status = 0;
@@ -765,6 +773,9 @@
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
 		sync_port *port = &ports[i];
+		if (!port->enabled)
+			continue;
+
 		if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */
 		{
 			/* Clear IRQ */
@@ -783,19 +794,15 @@
 
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
-		int update = 0;
 		sync_port *port = &ports[i];
 
 		if (!port->enabled)
-		{
 			continue;
-		}    
 
 		if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */
 		{
 			/* DMA has reached end of descriptor */
 			*port->input_dma_clr_irq = 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
 			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
 
 			/* Find out which descriptor that is ready */
@@ -847,18 +854,9 @@
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
 				{
 					int data = *(unsigned short *)port->data_in;
-					if (port->odd_input)
-					{
-						*port->writep |= (data & 0x0f00) >> 8;
-						*(port->writep + 1) = data & 0xff;
-					}
-					else
-					{
-						*port->writep = (data & 0x0ff0) >> 4;
-						*(port->writep + 1) = (data & 0x0f) << 4;
-					}
-					port->odd_input = !port->odd_input;
-					port->writep+=1;
+					*port->writep = (data & 0x0ff0) >> 4;
+					*(port->writep + 1) = data & 0x0f;
+					port->writep+=2;
 				}
 				break;
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
@@ -875,14 +873,14 @@
 					break;
 			}
 
-			if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
 				port->writep = port->in_buffer;
 			wake_up_interruptible(&port->in_wait_q); /* Wake up application */
 		}
 
 		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */
 		{
-			if (port->out_count) /* More data to send */
+			if (port->out_count > 0) /* More data to send */
 				send_word(port);
 			else /* transmission finished */
 			{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/entry.S linux-2.4.21-rc3/arch/cris/kernel/entry.S
--- linux-2.4.20/arch/cris/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/entry.S	2003-05-22 22:06:42.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.39 2002/04/24 00:46:45 bjornw Exp $
+/* $Id: entry.S,v 1.40 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,9 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.40  2002/12/02 08:11:41  starvik
+ *  Merge of Linux 2.4.20
+ *
  *  Revision 1.39  2002/04/24 00:46:45  bjornw
  *  Added sys_tkill
  *
@@ -736,12 +739,12 @@
  * the grosser the code, at least with the gcc version in cris-dist-1.13.
  */
 
-/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
+/* int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
 /*                   r10                r11         r12  */
 
 	.text
-	.global kernel_thread
-kernel_thread:
+	.global arch_kernel_thread
+arch_kernel_thread:
 
 	/* Save ARG for later.  */
 	move.d $r11, $r13
@@ -1016,7 +1019,33 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
-	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
+ 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_destroy */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_getevents */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_submit */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_cancel */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
 	
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/fasttimer.c linux-2.4.21-rc3/arch/cris/kernel/fasttimer.c
--- linux-2.4.20/arch/cris/kernel/fasttimer.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/fasttimer.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,10 +1,13 @@
-/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+/* $Id: fasttimer.c,v 1.5 2002/10/15 06:21:39 starvik Exp $
  * linux/arch/cris/kernel/fasttimer.c
  *
  * Fast timers for ETRAX100/ETRAX100LX
  * This may be useful in other OS than Linux so use 2 space indentation...
  *
  * $Log: fasttimer.c,v $
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
  * Revision 1.4  2002/05/28 17:47:59  johana
  * Added del_fast_timer()
  *
@@ -551,6 +554,8 @@
   struct fast_timer t;
 #ifdef DECLARE_WAITQUEUE
   wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
   DECLARE_WAITQUEUE(wait, current);
 #else
   struct wait_queue *sleep_wait = NULL;
@@ -566,6 +571,9 @@
   set_current_state(TASK_RUNNING);
   remove_wait_queue(&sleep_wait, &wait);
   D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
 }
 
 #ifdef CONFIG_PROC_FS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/ksyms.c linux-2.4.21-rc3/arch/cris/kernel/ksyms.c
--- linux-2.4.20/arch/cris/kernel/ksyms.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/ksyms.c	2003-05-22 22:06:50.000000000 +0000
@@ -24,6 +24,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern unsigned long get_cmos_time(void);
 extern void __Udiv(void);
+extern void __Umod(void);
 extern void __ashrdi3(void);
 extern void iounmap(void *addr);
 
@@ -47,9 +48,11 @@
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
 
 /* Math functions */
 EXPORT_SYMBOL(__Udiv);
+EXPORT_SYMBOL(__Umod);
 EXPORT_SYMBOL(__ashrdi3);
 
 /* Memory functions */
@@ -70,14 +73,13 @@
 EXPORT_SYMBOL(port_g_data_shadow);
 
 /* Userspace access functions */
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__generic_copy_from_user);
-EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
 EXPORT_SYMBOL(__copy_user_zeroing);
 EXPORT_SYMBOL(__copy_user);
 
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
+
 #undef memcpy
 #undef memset
 extern void * memset(void *, int, __kernel_size_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/process.c linux-2.4.21-rc3/arch/cris/kernel/process.c
--- linux-2.4.20/arch/cris/kernel/process.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/process.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.22 2001/11/13 09:40:43 orjanf Exp $
+/* $Id: process.c,v 1.23 2002/10/14 18:29:27 johana Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,10 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.23  2002/10/14 18:29:27  johana
+ *  Call etrax_gpio_wake_up_check() from cpu_idle() to reduce gpio latency
+ *  from ~15 ms to ~6 ms.
+ *
  *  Revision 1.22  2001/11/13 09:40:43  orjanf
  *  Added dump_fpu (needed for core dumps).
  *
@@ -121,11 +125,18 @@
 {
 	hlt_counter--;
 }
- 
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
 int cpu_idle(void *unused)
 {
 	while(1) {
 		current->counter = -100;
+#ifdef CONFIG_ETRAX_GPIO
+		/* This can reduce latency from 15 ms to 6 ms */
+		etrax_gpio_wake_up_check(); /* drivers/gpio.c */
+#endif
 		schedule();
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/setup.c linux-2.4.21-rc3/arch/cris/kernel/setup.c
--- linux-2.4.20/arch/cris/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/setup.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
+/* $Id: setup.c,v 1.27 2002/10/11 12:57:15 pkj Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -232,33 +232,34 @@
 		info = &cpu_info[revision];
 
 	return seq_printf(m,
-		       "cpu\t\t: CRIS\n"
-		       "cpu revision\t: %lu\n"
-		       "cpu model\t: %s\n"
-		       "cache size\t: %d kB\n"
-		       "fpu\t\t: %s\n"
-		       "mmu\t\t: %s\n"
-		       "mmu DMA bug\t: %s\n"
-		       "ethernet\t: %s Mbps\n"
-		       "token ring\t: %s\n"
-		       "scsi\t\t: %s\n"
-		       "ata\t\t: %s\n"
-		       "usb\t\t: %s\n"
-		       "bogomips\t: %lu.%02lu\n",
-
-		       revision,
-		       info->model,
-		       info->cache,
-		       info->flags & HAS_FPU ? "yes" : "no",
-		       info->flags & HAS_MMU ? "yes" : "no",
-		       info->flags & HAS_MMU_BUG ? "yes" : "no",
-		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
-		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
-		       info->flags & HAS_SCSI ? "yes" : "no",
-		       info->flags & HAS_ATA ? "yes" : "no",
-		       info->flags & HAS_USB ? "yes" : "no",
-		       (loops_per_jiffy * HZ + 500) / 500000,
-		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+			  "processor\t: 0\n"
+			  "cpu\t\t: CRIS\n"
+			  "cpu revision\t: %lu\n"
+			  "cpu model\t: %s\n"
+			  "cache size\t: %d kB\n"
+			  "fpu\t\t: %s\n"
+			  "mmu\t\t: %s\n"
+			  "mmu DMA bug\t: %s\n"
+			  "ethernet\t: %s Mbps\n"
+			  "token ring\t: %s\n"
+			  "scsi\t\t: %s\n"
+			  "ata\t\t: %s\n"
+			  "usb\t\t: %s\n"
+			  "bogomips\t: %lu.%02lu\n",
+
+			  revision,
+			  info->model,
+			  info->cache,
+			  info->flags & HAS_FPU ? "yes" : "no",
+			  info->flags & HAS_MMU ? "yes" : "no",
+			  info->flags & HAS_MMU_BUG ? "yes" : "no",
+			  info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+			  info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+			  info->flags & HAS_SCSI ? "yes" : "no",
+			  info->flags & HAS_ATA ? "yes" : "no",
+			  info->flags & HAS_USB ? "yes" : "no",
+			  (loops_per_jiffy * HZ + 500) / 500000,
+			  ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/signal.c linux-2.4.21-rc3/arch/cris/kernel/signal.c
--- linux-2.4.20/arch/cris/kernel/signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/signal.c	2003-05-22 22:06:25.000000000 +0000
@@ -517,7 +517,7 @@
  * OK, we're invoking a handler
  */	
 
-static inline void
+extern inline void
 handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/time.c linux-2.4.21-rc3/arch/cris/kernel/time.c
--- linux-2.4.20/arch/cris/kernel/time.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/time.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.14 2002/03/05 13:31:03 johana Exp $
+/* $Id: time.c,v 1.17 2002/11/15 14:49:24 oskarp Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001, 2002 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -25,6 +25,9 @@
  *      resolution within a jiffie as well.
  * 2002-03-05    Johan Adolfsson
  *      Use prescaler in do_slow_gettimeoffset() to get 1 us resolution (40ns)
+ * 2002-09-06    Johan Adolfsson
+ *      Handle lost ticks by checking wall_jiffies, more efficient code 
+ *      by using local vars and not the pointer argument.
  *
  */
 
@@ -62,6 +65,8 @@
 
 #define TICK_SIZE tick
 
+extern unsigned long wall_jiffies;
+
 /* The timers count from their initial value down to 1 
  * The R_TIMER0_DATA counts down when R_TIM_PRESC_STATUS reaches halv
  * of the divider value.
@@ -171,10 +176,8 @@
 
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are three kinds of problems that must be avoided here:
+	 * there are one problem that must be avoided here:
 	 *  1. the timer counter underflows
-	 *  2. we are after the timer interrupt, but the bottom half handler
-	 *     hasn't executed yet.
 	 */
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
@@ -198,7 +201,8 @@
 	return usec_count;
 }
 
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+#define do_gettimeoffset() do_slow_gettimeoffset()
 
 /*
  * This version of gettimeofday has near microsecond resolution.
@@ -206,20 +210,33 @@
 void do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags;
-
+	unsigned long usec, sec;
 	save_flags(flags);
 	cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
 	restore_flags(flags);
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
+	unsigned long flags;
+	signed long new_usec, new_sec;
+	save_flags(flags);  
 	cli();
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
@@ -227,20 +244,23 @@
 	 * Discover what correction gettimeofday
 	 * would have done, and then undo it!
 	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	if (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
+	new_usec = tv->tv_usec;
+	new_usec -= do_gettimeoffset();
+	new_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	new_sec = tv->tv_sec;
+	while (new_usec < 0) {
+		new_usec += 1000000;
+		new_sec--;
 	}
+	xtime.tv_sec = new_sec;
+	xtime.tv_usec = new_usec;
 
-	xtime = *tv;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_state = TIME_ERROR;	/* p. 24, (a) */
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	restore_flags(flags);
 }
 
 
@@ -479,10 +499,16 @@
 void __init
 time_init(void)
 {	
-	/* probe for the RTC and read it if it exists */
+	/* Probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
 
 	if(RTC_INIT() < 0) {
-		/* no RTC, start at 1980 */
+		/* no RTC, start at the Epoch (00:00:00 UTC, January 1, 1970) */
 		xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 		have_rtc = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/traps.c linux-2.4.21-rc3/arch/cris/kernel/traps.c
--- linux-2.4.20/arch/cris/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/kernel/traps.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.17 2001/12/07 17:02:34 bjornw Exp $
+/* $Id: traps.c,v 1.18 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/traps.c
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/dram_init.S linux-2.4.21-rc3/arch/cris/lib/dram_init.S
--- linux-2.4.20/arch/cris/lib/dram_init.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/lib/dram_init.S	2003-05-22 22:06:40.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
+/* $Id: dram_init.S,v 1.13 2002/10/30 07:42:28 starvik Exp $
  * 
  * DRAM/SDRAM initialization - alter with care
  * This file is intended to be included from other assembler files
@@ -11,6 +11,9 @@
  * Authors:  Mikael Starvik (starvik@axis.com)	
  * 
  * $Log: dram_init.S,v $
+ * Revision 1.13  2002/10/30 07:42:28  starvik
+ * Always read SDRAM command sequence from flash
+ *
  * Revision 1.12  2002/08/09 11:37:37  orjanf
  * Added double initialization work-around for Samsung SDRAMs.
  *
@@ -143,7 +146,9 @@
 	
 	; Issue initialization command sequence
 	move.d   _sdram_commands_start, $r2
+	and.d    0x00ffffff, $r2 ; Make sure commands are read from flash
 	move.d   _sdram_commands_end,  $r3
+	and.d    0x00ffffff, $r2
 1:	clear.d  $r4
 	move.b   [$r2+], $r4
 	lslq     9, $r4	; Command starts at bit 9
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/hw_settings.S linux-2.4.21-rc3/arch/cris/lib/hw_settings.S
--- linux-2.4.20/arch/cris/lib/hw_settings.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/lib/hw_settings.S	2003-05-22 22:06:42.000000000 +0000
@@ -1,11 +1,11 @@
 /*
- * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
+ * $Id: hw_settings.S,v 1.5 2002/08/15 09:16:06 bjornw Exp $
  * 
  * This table is used by some tools to extract hardware parameters.
  * The table should be included in the kernel and the decompressor.
  * Don't forget to update the tools if you change this table.
  *
- * Copyright (C) 2001 Axis Communications AB
+ * Copyright (C) 2001, 2002 Axis Communications AB
  *
  * Authors:  Mikael Starvik (starvik@axis.com)	
  */
@@ -16,8 +16,8 @@
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
 	
-	.ascii "HW_PARAM_MAGIC"					; Magic number
-	.dword CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"	; Magic number
+	.dword 0xc0004000	; Where to load the kernel image (physical!)
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/usercopy.c linux-2.4.21-rc3/arch/cris/lib/usercopy.c
--- linux-2.4.20/arch/cris/lib/usercopy.c	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/lib/usercopy.c	2003-05-22 22:06:27.000000000 +0000
@@ -88,11 +88,11 @@
        If you want to check that the allocation was right; then
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12".  */
-    __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+    __asm__ volatile ("\
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -189,7 +189,8 @@
 }
 
 /* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  */
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
 
 unsigned long
 __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn)
@@ -207,30 +208,34 @@
   register int n __asm__ ("r12") = pn;
   register int retn __asm__ ("r10") = 0;
 
-  /* When src is aligned but not dst, this makes a few extra needless
-     cycles.  I believe it would take as many to check that the
-     re-alignment was unnecessary.  */
-  if (((unsigned long) dst & 3) != 0
-      /* Don't align if we wouldn't copy more than a few bytes; so we
-	 don't have to check further for overflows.  */
-      && n >= 3)
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
   {
-    if ((unsigned long) dst & 1)
+    if (((unsigned long) src & 1) && n != 0)
     {
       __asm_copy_from_user_1 (dst, src, retn);
       n--;
     }
 
-    if ((unsigned long) dst & 2)
+    if (((unsigned long) src & 2) && n >= 2)
     {
       __asm_copy_from_user_2 (dst, src, retn);
       n -= 2;
     }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
   }
 
   /* Decide which copying method to use. */
   if (n >= 44*2)		/* Break even between movem and
-				   move16 is at 38.7*2, but modulo 44. */
+				   move16 is at 38.7*2, but modulo 44.
+				   FIXME: We use move4 now.  */
   {
     /* For large copies we use 'movem' */
 
@@ -249,10 +254,10 @@
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12" */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -273,73 +278,30 @@
 	movem	$r10,[$r13+]
 
 	addq   44,$r12  ;; compensate for last loop underflowing n
-8:
+
 	;; Restore registers from stack
 	movem [$sp+],$r10
-
+4:
 	.section .fixup,\"ax\"
 
 ;; Do not jump back into the loop if we fail.  For some uses, we get a
-;; page fault but for performance reasons we care to not get further
-;; faults.  For example, fs/super.c at one time did
+;; page fault somewhere on the line.  Without checking for page limits,
+;; we don't know where, but we need to copy accurately and keep an
+;; accurate count; not just clear the whole line.  To do that, we fall
+;; down in the code below, proceeding with smaller amounts.  It should
+;; be kept in mind that we have to cater to code like what at one time
+;; was in fs/super.c:
 ;;  i = size - copy_from_user((void *)page, data, size);
 ;; which would cause repeated faults while clearing the remainder of
 ;; the SIZE bytes at PAGE after the first fault.
+;; A caveat here is that we must not fall through from a failing page
+;; to a valid page.
 
 3:
-	move.d [$sp],$r10
-
-;; Number of remaining bytes, cleared but not copied, is r12 + 44.
-
-	add.d $r12,$r10
-	addq 44,$r10
-
-	move.d $r10,[$sp]
-	clear.d $r0
-	clear.d $r1
-	clear.d $r2
-	clear.d $r3
-	clear.d $r4
-	clear.d $r5
-	clear.d $r6
-	clear.d $r7
-	clear.d $r8
-	clear.d $r9
-	clear.d $r10
-
-;; Perform clear similar to the copy-loop.
-
-4:
-	subq 44,$r12
-	bge 4b
-	movem $r10,[$r13+]
-
-;; Clear by four for the remaining multiples.
-
-	addq 40,$r12
-	bmi 6f
-	nop
-5:
-	subq 4,$r12
-	bpl 5b
-	clear.d [$r13+]
-6:
-	addq 4,$r12
-	beq 7f
-	nop
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	subq 1,$r12
-	beq 7f
-	clear.b [$r13+]
-
-	clear.d $r12
-	clear.b [$r13+]
-7:
-	jump 8b
+	movem  [$sp+],$r10
+	addq	44,$r12 ;; Get back count before faulting point.
+	subq	44,$r11 ;; Get back pointer to faulting movem-line.
+	jump	4b	;; Fall through, pretending the fault didn't happen.
 
 	.previous
 	.section __ex_table,\"a\"
@@ -354,25 +316,30 @@
   /* Either we directly start copying here, using dword copying in a loop,
      or we copy as much as possible with 'movem' and then the last block
      (<44 bytes) is copied here.  This will work since 'movem' will have
-     updated src, dst and n. */
+     updated src, dst and n.  (Except with failing src.)
 
-  while (n >= 16)
-  {
-    __asm_copy_from_user_16 (dst, src, retn);
-    n -= 16;
-  }
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
 
-  /* Having a separate by-four loops cuts down on cache footprint.
-     FIXME:  Test with and without; increasing switch to be 0..15.  */
   while (n >= 4)
   {
     __asm_copy_from_user_4 (dst, src, retn);
     n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
   }
 
+  /* If we get here, there were no memory read faults.  */
   switch (n)
   {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
     case 0:
+      /* This case deliberately left in (if you have doubts check the
+	 generated assembly code).  */
       break;
     case 1:
       __asm_copy_from_user_1 (dst, src, retn);
@@ -385,7 +352,22 @@
       break;
   }
 
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
   return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
 }
 
 /* Zero userspace.  */
@@ -444,10 +426,10 @@
       check the equalities in the first comment.  It should say
       something like "r13=r13, r11=r11, r12=r12". */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r12 %2=r10
-	;;
+	.ifnc %0%1%2,$r13$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll clobber in the movem process
 	;; on the stack.  Don't mention them to gcc, it will only be
 	;; upset.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/mm/ioremap.c linux-2.4.21-rc3/arch/cris/mm/ioremap.c
--- linux-2.4.20/arch/cris/mm/ioremap.c	2001-05-01 23:04:56.000000000 +0000
+++ linux-2.4.21-rc3/arch/cris/mm/ioremap.c	2003-05-22 22:06:26.000000000 +0000
@@ -13,7 +13,7 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
 {
 	unsigned long end;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/Makefile linux-2.4.21-rc3/arch/i386/Makefile
--- linux-2.4.20/arch/i386/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -23,8 +23,10 @@
 
 CFLAGS += -pipe
 
+check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
 # prevent gcc from keeping the stack 16 byte aligned
-CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
+CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
 
 ifdef CONFIG_M386
 CFLAGS += -march=i386
@@ -59,15 +61,16 @@
 endif
 
 ifdef CONFIG_MK6
-CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; else echo "-march=i586"; fi)
+CFLAGS += $(call check_gcc,-march=k6,-march=i586)
 endif
 
 ifdef CONFIG_MK7
-CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=athlon"; else echo "-march=i686 -malign-functions=4"; fi) 
+CFLAGS += $(call check_gcc,-march=athlon,-march=i686 -malign-functions=4)
 endif
 
 ifdef CONFIG_MCRUSOE
-CFLAGS += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0
+CFLAGS += -march=i686
+CFLAGS += $(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
 endif
 
 ifdef CONFIG_MWINCHIPC6
@@ -83,7 +86,12 @@
 endif
 
 ifdef CONFIG_MCYRIXIII
-CFLAGS += -march=i486 -malign-functions=0 -malign-jumps=0 -malign-loops=0
+CFLAGS += $(call check_gcc,-march=c3,-march=i486)
+CFLAGS += $(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
+endif
+
+ifdef CONFIG_MVIAC3_2
+CFLAGS += $(call check_gcc,-march=c3-2,-march=i686)
 endif
 
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/config.in linux-2.4.21-rc3/arch/i386/config.in
--- linux-2.4.20/arch/i386/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/config.in	2003-05-22 22:06:40.000000000 +0000
@@ -36,12 +36,14 @@
 	 Pentium-4				CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III			CONFIG_MK6 \
 	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Opteron/Athlon64/Hammer/K8		CONFIG_MK8 \
 	 Elan					CONFIG_MELAN \
 	 Crusoe					CONFIG_MCRUSOE \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
 	 Winchip-2A/Winchip-3			CONFIG_MWINCHIP3D \
-	 CyrixIII/VIA-C3/VIA-C5			CONFIG_MCYRIXIII" Pentium-Pro
+	 CyrixIII/VIA-C3			CONFIG_MCYRIXIII \
+	 VIA-C3-2				CONFIG_MVIAC3_2" Pentium-Pro
 #
 # Define implied options from the CPU selection here
 #
@@ -99,7 +101,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
-   define_bool CONFIG_X86_PGE y
+   bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
@@ -126,6 +128,11 @@
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
+if [ "$CONFIG_MK8" = "y" ]; then
+   # for now. may later want to add SSE support and optimized
+   # functions
+   define_bool CONFIG_MK7 y
+fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_HAS_TSC y
@@ -147,6 +154,14 @@
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
+fi
+if [ "$CONFIG_MVIAC3_2" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -216,12 +231,26 @@
       define_bool CONFIG_X86_IO_APIC y
    fi
 else
-   bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
+   bool 'Multi-node NUMA system support' CONFIG_X86_NUMA
+   if [ "$CONFIG_X86_NUMA" = "y" ]; then
+      #Platform Choices
+      bool ' Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
+      if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+         define_bool CONFIG_MULTIQUAD y
+      fi
+      bool ' IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT
+      if [ "$CONFIG_X86_SUMMIT" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+      fi
+   fi
 fi
 
-bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
-if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
-   define_bool CONFIG_X86_TSC y
+if [ "$CONFIG_X86_NUMA" != "y" ]; then
+   bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
+   if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
+      define_bool CONFIG_X86_TSC y
+   fi
 fi
 
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/apic.c linux-2.4.21-rc3/arch/i386/kernel/apic.c
--- linux-2.4.20/arch/i386/kernel/apic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/apic.c	2003-05-22 22:06:53.000000000 +0000
@@ -261,6 +261,16 @@
 	apic_write_around(APIC_LVT1, value);
 }
 
+static unsigned long calculate_ldr(unsigned long old)
+{
+	unsigned long id;
+	if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		id = physical_to_logical_apicid(hard_smp_processor_id());
+	else
+		id = 1UL << smp_processor_id();
+	return (old & ~APIC_LDR_MASK)|SET_APIC_LOGICAL_ID(id);
+}
+
 void __init setup_local_APIC (void)
 {
 	unsigned long value, ver, maxlvt;
@@ -298,15 +308,16 @@
 		 * for us. Otherwise put the APIC into clustered or flat
 		 * delivery mode. Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, APIC_DFR_FLAT);
+		if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+			apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+		else
+			apic_write_around(APIC_DFR, APIC_DFR_FLAT);
 
 		/*
 		 * Set up the logical destination ID.
 		 */
 		value = apic_read(APIC_LDR);
-		value &= ~APIC_LDR_MASK;
-		value |= (1<<(smp_processor_id()+24));
-		apic_write_around(APIC_LDR, value);
+		apic_write_around(APIC_LDR, calculate_ldr(value));
 	}
 
 	/*
@@ -600,6 +611,8 @@
 	case X86_VENDOR_AMD:
 		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
 			break;
+		if (boot_cpu_data.x86 == 15 && cpu_has_apic)
+			break;
 		goto no_apic;
 	case X86_VENDOR_INTEL:
 		if (boot_cpu_data.x86 == 6 ||
@@ -636,7 +649,6 @@
 	}
 	set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
 	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-	boot_cpu_physical_apicid = 0;
 	if (nmi_watchdog != NMI_NONE)
 		nmi_watchdog = NMI_LOCAL_APIC;
 
@@ -1156,8 +1168,7 @@
 
 	connect_bsp_APIC();
 
-	phys_cpu_present_map = 1;
-	apic_write_around(APIC_ID, boot_cpu_physical_apicid);
+	phys_cpu_present_map = 1 << boot_cpu_physical_apicid;
 
 	apic_pm_init2();
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/apm.c linux-2.4.21-rc3/arch/i386/kernel/apm.c
--- linux-2.4.20/arch/i386/kernel/apm.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/apm.c	2003-05-22 22:06:25.000000000 +0000
@@ -247,6 +247,7 @@
  *	    					powering off
  *	    [no-]debug			log some debugging messages
  *	    [no-]power[-_]off		power off on shutdown
+ *	    [no-]smp			Use apm even on an SMP box
  *	    bounce[-_]interval=<n>	number of ticks to ignore suspend
  *	    				bounces
  *          idle[-_]threshold=<n>       System idle percentage above which to
@@ -393,6 +394,7 @@
 static int			got_clock_diff;
 #endif
 static int			debug;
+static int			smp = 0;
 static int			apm_disabled = -1;
 #ifdef CONFIG_SMP
 static int			power_off;
@@ -494,6 +496,40 @@
 }
 
 /*
+ * Lock APM functionality to physical CPU 0
+ */
+ 
+#ifdef CONFIG_SMP
+
+static unsigned long apm_save_cpus(void)
+{
+	unsigned long x = current->cpus_allowed;
+	/* Some bioses don't like being called from CPU != 0 */
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		set_cpus_allowed(current, 1 << cpu_logical_map(0));
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
+	}
+	return x;
+}
+
+static inline void apm_restore_cpus(unsigned long mask)
+{
+	set_cpus_allowed(current, mask);
+}
+
+#else
+
+/*
+ *	No CPU lockdown needed on a uniprocessor
+ */
+ 
+#define apm_save_cpus()	0
+#define apm_restore_cpus(x)	(void)(x)
+
+#endif
+
+/*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
  * apm_info.allow_ints, we are being really paranoid here!  Not only
  * are interrupts disabled, but all the segment registers (except SS)
@@ -566,7 +602,8 @@
 {
 	APM_DECL_SEGS
 	unsigned long	flags;
-
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -588,6 +625,9 @@
 		: "memory", "cc");
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+	
+	apm_restore_cpus(cpus);
+	
 	return *eax & 0xff;
 }
 
@@ -611,6 +651,8 @@
 	APM_DECL_SEGS
 	unsigned long	flags;
 
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -636,6 +678,9 @@
 	}
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+
+	apm_restore_cpus(cpus);
+	
 	return error;
 }
 
@@ -751,10 +796,12 @@
 	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
 		static unsigned long t;
 
-		if (time_after(jiffies, t + 10 * HZ)) {
+		/* This always fails on some SMP boards running UP kernels.
+		 * Only report the failure the first 5 times.
+		 */
+		if (++t < 5) {
 			printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
 					(eax >> 8) & 0xff);
-			t = jiffies;
 		}
 		return -1;
 	}
@@ -888,17 +935,12 @@
 	/*
 	 * This may be called on an SMP machine.
 	 */
-#ifdef CONFIG_SMP
-	/* Some bioses don't like being called from CPU != 0 */
-	if (cpu_number_map(smp_processor_id()) != 0) {
-		current->cpus_allowed = 1;
-		schedule();
-		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
-			BUG();
-	}
-#endif
 	if (apm_info.realmode_power_off)
+	{
+		(void)apm_save_cpus();
 		machine_real_restart(po_bios_call, sizeof(po_bios_call));
+		/* Never returns */
+	}
 	else
 		(void) set_system_power_state(APM_STATE_OFF);
 }
@@ -1074,6 +1116,19 @@
 	}
 	if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
 		return 1;
+	if (error == APM_NOT_ENGAGED) {
+		static int tried;
+		int eng_error;
+		if (tried++ == 0) {
+			eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+			if (eng_error) {
+				apm_error("set display", error);
+				apm_error("engage interface", eng_error);
+				return 0;
+			} else
+				return apm_console_blank(blank);
+		}
+	}
 	apm_error("set display", error);
 	return 0;
 }
@@ -1397,7 +1452,7 @@
 	as = fp->private_data;
 	if (check_apm_user(as, "read"))
 		return -EIO;
-	if (count < sizeof(apm_event_t))
+	if ((int)count < sizeof(apm_event_t))
 		return -EINVAL;
 	if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
 		return -EAGAIN;
@@ -1571,7 +1626,7 @@
 
 	p = buf;
 
-	if ((smp_num_cpus == 1) &&
+	if ((smp_num_cpus == 1 || smp) &&
 	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
@@ -1716,7 +1771,7 @@
 		}
 	}
 
-	if (debug) {
+	if (debug && (smp_num_cpus == 1 || smp )) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1760,7 +1815,7 @@
 		pm_power_off = apm_power_off;
 	register_sysrq_key('o', &sysrq_poweroff_op);
 
-	if (smp_num_cpus == 1) {
+	if (smp_num_cpus == 1 || smp) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 		console_blank_hook = apm_console_blank;
 #endif
@@ -1799,6 +1854,11 @@
 			str += 3;
 		if (strncmp(str, "debug", 5) == 0)
 			debug = !invert;
+		if (strncmp(str, "smp", 3) == 0)
+		{
+			smp = !invert;
+			idle_threshold = 100;
+		}
 		if ((strncmp(str, "power-off", 9) == 0) ||
 		    (strncmp(str, "power_off", 9) == 0))
 			power_off = !invert;
@@ -1903,7 +1963,7 @@
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
 		return -ENODEV;
 	}
-	if ((smp_num_cpus > 1) && !power_off) {
+	if ((smp_num_cpus > 1) && !power_off && !smp) {
 		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
 		return -ENODEV;
 	}
@@ -1957,7 +2017,7 @@
 
 	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
-	if (smp_num_cpus > 1) {
+	if (smp_num_cpus > 1 && !smp) {
 		printk(KERN_NOTICE
 		   "apm: disabled - APM is not SMP safe (power off active).\n");
 		return 0;
@@ -2025,5 +2085,8 @@
 MODULE_PARM(idle_period, "i");
 MODULE_PARM_DESC(idle_period,
 	"Period (in sec/100) over which to caculate the idle percentage");
+MODULE_PARM(smp, "i");
+MODULE_PARM_DESC(smp,
+	"Set this to enable APM use on an SMP platform. Use with caution on older systems");
 
 EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/bluesmoke.c linux-2.4.21-rc3/arch/i386/kernel/bluesmoke.c
--- linux-2.4.20/arch/i386/kernel/bluesmoke.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/bluesmoke.c	2003-05-22 22:06:40.000000000 +0000
@@ -221,7 +221,7 @@
 			/*
 			 *	AMD K7 machine check is Intel like
 			 */
-			if(c->x86 == 6)
+			if(c->x86 == 6 || c->x86 == 15)
 				intel_mcheck_init(c);
 			break;
 		case X86_VENDOR_INTEL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/dmi_scan.c linux-2.4.21-rc3/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20/arch/i386/kernel/dmi_scan.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/dmi_scan.c	2003-05-22 22:06:41.000000000 +0000
@@ -11,6 +11,8 @@
 #include <asm/system.h>
 #include <linux/bootmem.h>
 
+#include "pci-i386.h"
+
 unsigned long dmi_broken;
 int is_sony_vaio_laptop;
 
@@ -99,14 +101,6 @@
 	u8 buf[15];
 	u32 fp=0xF0000;
 
-#ifdef CONFIG_SIMNOW
-	/*
- 	 *	Skip on x86/64 with simnow. Will eventually go away
- 	 *	If you see this ifdef in 2.6pre mail me !
- 	 */
-	return -1;
-#endif
- 	
 	while( fp < 0xFFFFF)
 	{
 		isa_memcpy_fromio(buf, fp, 15);
@@ -421,6 +415,8 @@
  */
  
 extern int skip_ioapic_setup;
+extern int broken_440gx_bios;
+extern unsigned int pci_probe;
 static __init int broken_pirq(struct dmi_blacklist *d)
 {
 	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
@@ -431,27 +427,11 @@
 #ifdef CONFIG_X86_IO_APIC
 	skip_ioapic_setup = 0;
 #endif
-	return 0;
-}
-
-/*
- * ASUS K7V-RM has broken ACPI table defining sleep modes
- */
-
-static __init int broken_acpi_Sx(struct dmi_blacklist *d)
-{
-	printk(KERN_WARNING "Detected ASUS mainboard with broken ACPI sleep table\n");
-	dmi_broken |= BROKEN_ACPI_Sx;
-	return 0;
-}
-
-/*
- * Toshiba keyboard likes to repeat keys when they are not repeated.
- */
-
-static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
-{
-	printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, contact pavel@ucw.cz\n");
+#ifdef CONFIG_PCI
+	broken_440gx_bios = 1;
+	pci_probe |= PCI_BIOS_IRQ_SCAN;
+#endif
+	
 	return 0;
 }
 
@@ -595,6 +575,11 @@
 			MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"),
 			NO_MATCH, NO_MATCH,
 			} },
+	{ apm_is_horked, "Intel D810EMO", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "MO81010A.86A.0008.P04.0004170800"),
+			NO_MATCH, NO_MATCH,
+			} },
 	{ apm_is_horked, "Dell XPS-Z", { /* APM crashes */
 			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
 			MATCH(DMI_BIOS_VERSION, "A11"),
@@ -694,6 +679,18 @@
 			MATCH(DMI_BIOS_VERSION, "R0204P1"),
 			MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
 			} },
+			
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
+	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "RK116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
 
 	/* Machines which have problems handling enabled local APICs */
 
@@ -760,16 +757,6 @@
 			NO_MATCH, NO_MATCH, NO_MATCH
 			} },
 			
-	{ broken_acpi_Sx, "ASUS K7V-RM", {		/* Bad ACPI Sx table */
-			MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
-			MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
-			NO_MATCH, NO_MATCH
-			} },
-			
-	{ broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
-			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
-			NO_MATCH, NO_MATCH, NO_MATCH
-			} },
 	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
 			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
 			NO_MATCH, NO_MATCH, NO_MATCH
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.21-rc3/arch/i386/kernel/entry.S
--- linux-2.4.20/arch/i386/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/entry.S	2003-05-22 22:06:39.000000000 +0000
@@ -643,7 +643,7 @@
 	.long SYMBOL_NAME(sys_lremovexattr)
 	.long SYMBOL_NAME(sys_fremovexattr)
  	.long SYMBOL_NAME(sys_tkill)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_sendfile64)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
@@ -657,6 +657,12 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_lookup_dcookie */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_create */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_ctl 255 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_wait */
+ 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_remap_file_pages */
+ 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_tid_address */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/head.S linux-2.4.21-rc3/arch/i386/kernel/head.S
--- linux-2.4.20/arch/i386/kernel/head.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/head.S	2003-05-22 22:06:26.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/i386/head.S -- the 32-bit startup code.
+ *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/i386_ksyms.c linux-2.4.21-rc3/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.20/arch/i386/kernel/i386_ksyms.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/i386_ksyms.c	2003-05-22 22:06:43.000000000 +0000
@@ -86,6 +86,7 @@
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
+EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__delay);
 EXPORT_SYMBOL(__const_udelay);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/io_apic.c linux-2.4.21-rc3/arch/i386/kernel/io_apic.c
--- linux-2.4.20/arch/i386/kernel/io_apic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/io_apic.c	2003-05-22 22:06:40.000000000 +0000
@@ -292,7 +292,7 @@
 
 	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
 		bus, slot, pin);
-	if (mp_bus_id_to_pci_bus[bus] == -1) {
+	if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) {
 		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
 		return -1;
 	}
@@ -739,8 +739,9 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
-	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
-	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+	printk(KERN_WARNING 
+		"An unexpected IO-APIC was found. If this kernel release is less than\n"
+		"three months old please report this to linux-smp@vger.kernel.org\n");
 }
 
 void __init print_IO_APIC(void)
@@ -775,7 +776,9 @@
 	printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
 	printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)&reg_00);
 	printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.ID);
-	if (reg_00.__reserved_1 || reg_00.__reserved_2)
+	printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.delivery_type);
+	printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.LTS);
+	if (reg_00.__reserved_0 || reg_00.__reserved_1 || reg_00.__reserved_2)
 		UNEXPECTED_IO_APIC();
 
 	printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
@@ -793,6 +796,8 @@
 	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
 	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x02) && /* VIA */
+		(reg_01.version != 0x03) && /* later VIA */
 		(reg_01.version != 0x10) && /* oldest IO-APICs */
 		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
 		(reg_01.version != 0x13) && /* Xeon IO-APICs */
@@ -1067,7 +1072,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+		if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1079,14 +1084,16 @@
 		 * Sanity check, is the ID really free? Every APIC in a
 		 * system must have a unique ID or we get lots of nice
 		 * 'stuck on smp_invalidate_needed IPI wait' messages.
+		 * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
 		 */
-		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+		if ((clustered_apic_mode != CLUSTERED_APIC_XAPIC) &&
+		    (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			for (i = 0; i < 0xf; i++)
 				if (!(phys_id_present_map & (1 << i)))
 					break;
-			if (i >= 0xf)
+			if (i >= apic_broadcast_id)
 				panic("Max APIC ID exceeded!\n");
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
 				i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/ioport.c linux-2.4.21-rc3/arch/i386/kernel/ioport.c
--- linux-2.4.20/arch/i386/kernel/ioport.c	1999-07-19 22:22:48.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/ioport.c	2003-05-22 22:06:43.000000000 +0000
@@ -72,17 +72,18 @@
 		 */
 		memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
 		t->ioperm = 1;
-		/*
-		 * this activates it in the TSS
-		 */
-		tss->bitmap = IO_BITMAP_OFFSET;
 	}
 
 	/*
 	 * do it in the per-thread copy and in the TSS ...
 	 */
 	set_bitmap(t->io_bitmap, from, num, !turn_on);
-	set_bitmap(tss->io_bitmap, from, num, !turn_on);
+	if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */
+		set_bitmap(tss->io_bitmap, from, num, !turn_on);
+	} else {
+		memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_SIZE);
+		tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */
+	}
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/microcode.c linux-2.4.21-rc3/arch/i386/kernel/microcode.c
--- linux-2.4.20/arch/i386/kernel/microcode.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/microcode.c	2003-05-22 22:06:38.000000000 +0000
@@ -55,7 +55,7 @@
  *		Tigran Aivazian <tigran@veritas.com>,
  *		Serialize updates as required on HT processors due to speculative
  *		nature of implementation.
- *	1.11	22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ *	1.11	22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
  *		Fix the panic when writing zero-length microcode chunk.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/mpparse.c linux-2.4.21-rc3/arch/i386/kernel/mpparse.c
--- linux-2.4.20/arch/i386/kernel/mpparse.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/mpparse.c	2003-05-22 22:06:40.000000000 +0000
@@ -36,18 +36,20 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+int *mp_bus_id_to_type;
+int *mp_bus_id_to_node;
+int *mp_bus_id_to_local;
+int *mp_bus_id_to_pci_bus;
+int max_mp_busses;
+int max_irq_sources;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mpc_config_intsrc *mp_irqs;
 
 /* MP IRQ source entries */
 int mp_irq_entries;
@@ -65,8 +67,14 @@
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
 unsigned char esr_disable = 0;
+unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE;
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+#endif
+unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
 /*
  * Intel MP BIOS table parsing routines:
@@ -118,6 +126,8 @@
 		case 0x0F:
 			if (model == 0x00)
 				return("Pentium 4(tm)");
+			if (model == 0x01)
+				return("Pentium 4(tm)");
 			if (model == 0x02)
 				return("Pentium 4(tm) XEON(tm)");
 			if (model == 0x0F)
@@ -226,16 +236,14 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
-			--num_processors;
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
 
-	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
-		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
-	} else {
-		phys_cpu_present_map |= 1 << m->mpc_apicid;
-	}
+	logical_cpu_present_map |= 1 << (num_processors-1);
+ 	phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
+ 
 	/*
 	 * Validate version
 	 */
@@ -244,6 +252,7 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
+	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -308,7 +317,7 @@
 			m->mpc_irqtype, m->mpc_irqflag & 3,
 			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
 			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+	if (++mp_irq_entries == max_irq_sources)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
@@ -398,9 +407,12 @@
 
 static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
-	char str[16];
+	char oem[16], prod[14];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
+	int num_bus = 0;
+	int num_irq = 0;
+	unsigned char *bus_data;
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -423,14 +435,16 @@
 		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
 		return 0;
 	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
-
-	memcpy(str,mpc->mpc_productid,12);
-	str[12]=0;
-	printk("Product ID: %s ",str);
+	memcpy(oem,mpc->mpc_oem,8);
+	oem[8]=0;
+	printk("OEM ID: %s ",oem);
+
+	memcpy(prod,mpc->mpc_productid,12);
+	prod[12]=0;
+	printk("Product ID: %s ",prod);
 
+	detect_clustered_apic(oem, prod);
+	
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
 	/* save the local APIC address, it might be non-default,
@@ -446,9 +460,70 @@
 		mpc_record = 0;
 	}
 
+	/* Pre-scan to determine the number of bus and 
+	 * interrupts records we have
+	 */
+	while (count < mpc->mpc_length) {
+		switch (*mpt) {
+			case MP_PROCESSOR:
+				mpt += sizeof(struct mpc_config_processor);
+				count += sizeof(struct mpc_config_processor);
+				break;
+			case MP_BUS:
+				++num_bus;
+				mpt += sizeof(struct mpc_config_bus);
+				count += sizeof(struct mpc_config_bus);
+				break;
+			case MP_INTSRC:
+				++num_irq;
+				mpt += sizeof(struct mpc_config_intsrc);
+				count += sizeof(struct mpc_config_intsrc);
+				break;
+			case MP_IOAPIC:
+				mpt += sizeof(struct mpc_config_ioapic);
+				count += sizeof(struct mpc_config_ioapic);
+				break;
+			case MP_LINTSRC:
+				mpt += sizeof(struct mpc_config_lintsrc);
+				count += sizeof(struct mpc_config_lintsrc);
+				break;
+			default:
+				count = mpc->mpc_length;
+				break;
+		}
+	}
+	/* 
+	 * Paranoia: Allocate one extra of both the number of busses and number
+	 * of irqs, and make sure that we have at least 4 interrupts per PCI
+	 * slot.  But some machines do not report very many busses, so we need
+	 * to fall back on the older defaults.
+	 */
+	++num_bus;
+	max_mp_busses = max(num_bus, MAX_MP_BUSSES);
+	if (num_irq < (4 * max_mp_busses))
+		num_irq = 4 * num_bus;	/* 4 intr/PCI slot */
+	++num_irq;
+	max_irq_sources = max(num_irq, MAX_IRQ_SOURCES);
+	
+	count = (max_mp_busses * sizeof(int)) * 4;
+	count += (max_irq_sources * sizeof(struct mpc_config_intsrc));
+	bus_data = alloc_bootmem(count);
+	if (!bus_data) {
+		printk(KERN_ERR "SMP mptable: out of memory!\n");
+		return 0;
+	}
+	mp_bus_id_to_type = (int *)&bus_data[0];
+	mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))];
+	mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2];
+	mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3];
+	mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4];
+	memset(mp_bus_id_to_pci_bus, -1, max_mp_busses);
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
+	count = sizeof(*mpc);
+	mpt = ((unsigned char *)mpc)+count;
 	while (count < mpc->mpc_length) {
 		switch(*mpt) {
 			case MP_PROCESSOR:
@@ -510,9 +585,19 @@
 	}
 
 	if (clustered_apic_mode){
-		esr_disable = 1;
+		phys_cpu_present_map = logical_cpu_present_map;
 	}
 
+
+	printk("Enabling APIC mode: ");
+	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
+		printk("Clustered Logical.	");
+	else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		printk("Physical.	");
+	else
+		printk("Flat.	");
+	printk("Using %d I/O APICs\n",nr_ioapics);
+
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
@@ -808,18 +893,16 @@
 	 * there is a real-mode segmented pointer pointing to the
 	 * 4K EBDA area at 0x40E, calculate and scan it here.
 	 *
-	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * NOTE! There were Linux loaders that will corrupt the EBDA
 	 * area, and as such this kind of SMP config may be less
 	 * trustworthy, simply because the SMP table may have been
-	 * stomped on during early boot. These loaders are buggy and
-	 * should be fixed.
+	 * stomped on during early boot.  Thankfully the bootloaders
+	 * now honour the EBDA.
 	 */
 
 	address = *(unsigned short *)phys_to_virt(0x40E);
 	address <<= 4;
 	smp_scan_config(address, 0x1000);
-	if (smp_found_config)
-		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
 
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/mtrr.c linux-2.4.21-rc3/arch/i386/kernel/mtrr.c
--- linux-2.4.20/arch/i386/kernel/mtrr.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/mtrr.c	2003-05-22 22:06:25.000000000 +0000
@@ -492,6 +492,14 @@
 		return 0;
 		}
 	}
+	/* Intel 450NX errata # 23. Non ascending cachline evictions to
+	   write combining memory may resulting in data corruption */
+	dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, NULL);
+	if(dev)
+	{
+		printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
+		return 0;
+	}		
 
     switch ( mtrr_if )
     {
@@ -2143,7 +2151,7 @@
 		   query the width (in bits) of the physical
 		   addressable memory on the Hammer family.
 		 */
-		if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
+		if (boot_cpu_data.x86 == 15 && (cpuid_eax(0x80000000) >= 0x80000008)) {
 			u32	phys_addr;
 			phys_addr = cpuid_eax(0x80000008) & 0xff ;
 			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/nmi.c linux-2.4.21-rc3/arch/i386/kernel/nmi.c
--- linux-2.4.20/arch/i386/kernel/nmi.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/nmi.c	2003-05-22 22:06:47.000000000 +0000
@@ -72,18 +72,21 @@
 
 int __init check_nmi_watchdog (void)
 {
-	irq_cpustat_t tmp[NR_CPUS];
+	unsigned int prev_nmi_count[NR_CPUS];
 	int j, cpu;
 
 	printk(KERN_INFO "testing NMI watchdog ... ");
 
-	memcpy(tmp, irq_stat, sizeof(tmp));
+	for (j = 0; j < smp_num_cpus; j++) {
+		cpu = cpu_logical_map(j);
+		prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
+	}
 	sti();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
 	for (j = 0; j < smp_num_cpus; j++) {
 		cpu = cpu_logical_map(j);
-		if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
+		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck!\n", cpu);
 			return -1;
 		}
@@ -119,7 +122,7 @@
 		nmi_watchdog = nmi;
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
-			(boot_cpu_data.x86 == 6))
+	       	    ((boot_cpu_data.x86 == 6) || (boot_cpu_data.x86 == 15)))
 		nmi_watchdog = nmi;
 	/*
 	 * We can enable the IO-APIC watchdog
@@ -278,7 +281,7 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6)
+		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
 			return;
 		setup_k7_watchdog();
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/pci-irq.c linux-2.4.21-rc3/arch/i386/kernel/pci-irq.c
--- linux-2.4.20/arch/i386/kernel/pci-irq.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/pci-irq.c	2003-05-22 22:06:53.000000000 +0000
@@ -23,6 +23,7 @@
 #define PIRQ_VERSION 0x0100
 
 int broken_hp_bios_irq9;
+int broken_440gx_bios;
 
 static struct irq_routing_table *pirq_table;
 
@@ -681,7 +682,10 @@
 void __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
-	pirq_table = pirq_find_routing_table();
+	if (broken_440gx_bios)
+ 		pirq_table = NULL;	
+ 	else
+		pirq_table = pirq_find_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
 		pirq_table = pcibios_get_irq_routing_table();
@@ -779,9 +783,16 @@
 void pcibios_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
+	extern int interrupt_line_quirk;
+	
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
 		char *msg;
+
+		/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
+		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
+			return;
+
 		if (io_apic_assign_pci_irqs)
 			msg = " Probably buggy MP table.";
 		else if (pci_probe & PCI_BIOS_IRQ_SCAN)
@@ -791,4 +802,9 @@
 		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
 		       'A' + pin - 1, dev->slot_name, msg);
 	}
+	/* VIA bridges use interrupt line for apic/pci steering across
+	   the V-Link */
+	else if (interrupt_line_quirk)
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/process.c linux-2.4.21-rc3/arch/i386/kernel/process.c
--- linux-2.4.20/arch/i386/kernel/process.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/process.c	2003-05-22 22:06:24.000000000 +0000
@@ -485,7 +485,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval, d0;
 
@@ -508,6 +508,7 @@
 		 "r" (arg), "r" (fn),
 		 "b" (flags | CLONE_VM)
 		: "memory");
+
 	return retval;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/setup.c linux-2.4.21-rc3/arch/i386/kernel/setup.c
--- linux-2.4.20/arch/i386/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/setup.c	2003-05-22 22:06:43.000000000 +0000
@@ -71,6 +71,9 @@
  *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
  *  Dave Jones <davej@suse.de>, September, October 2001.
  *
+ *  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *  Alex Achenbach <xela@slit.de>, December 2002.
+ *
  */
 
 /*
@@ -501,7 +504,7 @@
 	int chgidx, still_changing;
 	int overlap_entries;
 	int new_bios_entry;
-	int old_nr, new_nr;
+	int old_nr, new_nr, chg_nr;
 	int i;
 
 	/*
@@ -555,20 +558,24 @@
 	for (i=0; i < 2*old_nr; i++)
 		change_point[i] = &change_point_list[i];
 
-	/* record all known change-points (starting and ending addresses) */
+	/* record all known change-points (starting and ending addresses),
+	   omitting those that are for empty memory regions */
 	chgidx = 0;
 	for (i=0; i < old_nr; i++)	{
-		change_point[chgidx]->addr = biosmap[i].addr;
-		change_point[chgidx++]->pbios = &biosmap[i];
-		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
-		change_point[chgidx++]->pbios = &biosmap[i];
+		if (biosmap[i].size != 0) {
+			change_point[chgidx]->addr = biosmap[i].addr;
+			change_point[chgidx++]->pbios = &biosmap[i];
+			change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+			change_point[chgidx++]->pbios = &biosmap[i];
+		}
 	}
+	chg_nr = chgidx;    	/* true number of change-points */
 
 	/* sort change-point list by memory addresses (low -> high) */
 	still_changing = 1;
 	while (still_changing)	{
 		still_changing = 0;
-		for (i=1; i < 2*old_nr; i++)  {
+		for (i=1; i < chg_nr; i++)  {
 			/* if <current_addr> > <last_addr>, swap */
 			/* or, if current=<start_addr> & last=<end_addr>, swap */
 			if ((change_point[i]->addr < change_point[i-1]->addr) ||
@@ -591,7 +598,7 @@
 	last_type = 0;		 /* start with undefined memory type */
 	last_addr = 0;		 /* start with 0 as last starting address */
 	/* loop through change-points, determining affect on the new bios map */
-	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	for (chgidx=0; chgidx < chg_nr; chgidx++)
 	{
 		/* keep track of all overlapping bios entries */
 		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
@@ -1259,19 +1266,19 @@
 			l2size = 256;
 	}
 
-	/* Intel PIII Tualatin. This comes in two flavours.
-	 * One has 256kb of cache, the other 512. We have no way
-	 * to determine which, so we use a boottime override
-	 * for the 512kb model, and assume 256 otherwise.
-	 */
-	if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
-		(c->x86_model == 11) && (l2size == 0))
-		l2size = 256;
-
-	/* VIA C3 CPUs (670-68F) need further shifting. */
-	if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) &&
-		((c->x86_model == 7) || (c->x86_model == 8))) {
-		l2size = l2size >> 8;
+	if (c->x86_vendor == X86_VENDOR_CENTAUR) {
+		/* VIA C3 CPUs (670-68F) need further shifting. */
+		if ((c->x86 == 6) &&
+		    ((c->x86_model == 7) || (c->x86_model == 8))) {
+			l2size >>= 8;
+		}
+
+		/* VIA also screwed up Nehemiah stepping 1, and made
+		   it return '65KB' instead of '64KB'
+		   - Note, it seems this may only be in engineering samples. */
+		if ((c->x86==6) && (c->x86_model==9) &&
+		    (c->x86_mask==1) && (l2size==65))
+			l2size -= 1;
 	}
 
 	/* Allow user to override all this if necessary. */
@@ -1421,7 +1428,7 @@
 			 * If the BIOS didn't enable it already, enable it
 			 * here.
 			 */
-			if (c->x86_model == 6 || c->x86_model == 7) {
+			if (c->x86_model >= 6 && c->x86_model <= 10) {
 				if (!test_bit(X86_FEATURE_XMM,
 					      &c->x86_capability)) {
 					printk(KERN_INFO
@@ -1433,8 +1440,20 @@
                                                 &c->x86_capability);
 				}
 			}
-			break;
 
+			/* It's been determined by AMD that Athlons since model 8 stepping 1
+			 * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
+			 * As per AMD technical note 27212 0.2
+			 */
+			if ((c->x86_model == 8 && c->x86_mask>=1) || (c->x86_model > 8)) {
+				rdmsr(MSR_K7_CLK_CTL, l, h);
+				if ((l & 0xfff00000) != 0x20000000) {
+					printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
+						((l & 0x000fffff)|0x20000000));
+					wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
+				}
+			}
+			break;
 	}
 
 	display_cacheinfo(c);
@@ -1478,11 +1497,9 @@
 }
 
 /*
- * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
- * order to identify the Cyrix CPU model after we're out of setup.c
- *
- * Actually since bugs.h doesn't even reference this perhaps someone should
- * fix the documentation ???
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in
+ * order to identify the Cyrix CPU model after we're out of the
+ * initial setup.
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
 
@@ -2076,6 +2093,10 @@
 					set_bit(X86_FEATURE_CX8, &c->x86_capability);
 					set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
 
+					/* fall through */
+
+				case 9: /* Nehemiah */
+				default:
 					get_model_name(c);
 					display_cacheinfo(c);
 					break;
@@ -2183,6 +2204,7 @@
 #define LVL_1_DATA      2
 #define LVL_2           3
 #define LVL_3           4
+#define LVL_TRACE       5
 
 struct _cache_table
 {
@@ -2202,6 +2224,9 @@
 	{ 0x23, LVL_3,      1024 },
 	{ 0x25, LVL_3,      2048 },
 	{ 0x29, LVL_3,      4096 },
+	{ 0x39, LVL_2,      128 },
+	{ 0x3b, LVL_2,      128 },
+	{ 0x3C, LVL_2,      256 },
 	{ 0x41, LVL_2,      128 },
 	{ 0x42, LVL_2,      256 },
 	{ 0x43, LVL_2,      512 },
@@ -2210,11 +2235,15 @@
 	{ 0x66, LVL_1_DATA, 8 },
 	{ 0x67, LVL_1_DATA, 16 },
 	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x70, LVL_TRACE,  12 },
+	{ 0x71, LVL_TRACE,  16 },
+	{ 0x72, LVL_TRACE,  32 },
 	{ 0x79, LVL_2,      128 },
 	{ 0x7A, LVL_2,      256 },
 	{ 0x7B, LVL_2,      512 },
 	{ 0x7C, LVL_2,      1024 },
 	{ 0x82, LVL_2,      256 },
+	{ 0x83, LVL_2,      512 },
 	{ 0x84, LVL_2,      1024 },
 	{ 0x85, LVL_2,      2048 },
 	{ 0x00, 0, 0}
@@ -2222,7 +2251,7 @@
 
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
-	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
 	char *p = NULL;
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	static int f00f_workaround_enabled = 0;
@@ -2282,8 +2311,10 @@
 						case LVL_3:
 							l3 += cache_table[k].size;
 							break;
+						case LVL_TRACE:
+							trace += cache_table[k].size;
+							break;
 						}
-
 						break;
 					}
 
@@ -2291,9 +2322,25 @@
 				}
 			}
 		}
-		if ( l1i || l1d )
-			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			       l1i, l1d);
+
+		/* Intel PIII Tualatin. This comes in two flavours.
+		 * One has 256kb of cache, the other 512. We have no way
+		 * to determine which, so we use a boottime override
+		 * for the 512kb model, and assume 256 otherwise.
+		 */
+		if ((c->x86 == 6) && (c->x86_model == 11) && (l2 == 0))
+			l2 = 256;
+		/* Allow user to override all this if necessary. */
+		if (cachesize_override != -1)
+			l2 = cachesize_override;
+
+		if ( trace )
+			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+		else if ( l1i )
+			printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+		if ( l1d )
+			printk(", L1 D cache: %dK\n", l1d);
+
 		if ( l2 )
 			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
 		if ( l3 )
@@ -2412,6 +2459,8 @@
 	else if (!strcmp(v, "GenuineTMx86") ||
 		 !strcmp(v, "TransmetaCPU"))
 		c->x86_vendor = X86_VENDOR_TRANSMETA;
+	else if (!strcmp(v, "SiS SiS SiS "))
+		c->x86_vendor = X86_VENDOR_SIS;
 	else
 		c->x86_vendor = X86_VENDOR_UNKNOWN;
 }
@@ -2463,6 +2512,9 @@
 	{ X86_VENDOR_RISE,	5,
 	  { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL,
 	    NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }},
+	{ X86_VENDOR_SIS,	5,
+	  { NULL, NULL, NULL, NULL, "SiS55x", NULL, NULL,
+	    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
 };
 
 /* Look up CPU names by table lookup. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smp.c linux-2.4.21-rc3/arch/i386/kernel/smp.c
--- linux-2.4.20/arch/i386/kernel/smp.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/smp.c	2003-05-22 22:06:26.000000000 +0000
@@ -214,7 +214,10 @@
 			/*
 			 * prepare target chip field
 			 */
-			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+			if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+				cfg = __prepare_ICR2(cpu_to_physical_apicid(query_cpu));
+			else
+				cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
 			apic_write_around(APIC_ICR2, cfg);
 		
 			/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smpboot.c linux-2.4.21-rc3/arch/i386/kernel/smpboot.c
--- linux-2.4.20/arch/i386/kernel/smpboot.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/smpboot.c	2003-05-22 22:06:44.000000000 +0000
@@ -410,7 +410,7 @@
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	/*
 	 * Because we use NMIs rather than the INIT-STARTUP sequence to
-	 * bootstrap the CPUs, the APIC may be in a wierd state. Kick it.
+	 * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
 	 */
 	if (clustered_apic_mode)
 		clear_local_APIC();
@@ -525,12 +525,12 @@
 	int apicid, cpu;
 
 	for (apicid = 0; apicid < MAX_APICID; apicid++) {
-		physical_apicid_2_cpu[apicid] = -1;
-		logical_apicid_2_cpu[apicid] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
 	}
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		cpu_2_physical_apicid[cpu] = -1;
-		cpu_2_logical_apicid[cpu] = -1;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -540,7 +540,7 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		logical_apicid_2_cpu[apicid] = cpu;	
 		cpu_2_logical_apicid[cpu] = apicid;
 	} else {
@@ -555,12 +555,12 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
-		logical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_logical_apicid[cpu] = -1;
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	} else {
-		physical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_physical_apicid[cpu] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -785,7 +785,7 @@
 	unsigned long boot_error = 0;
 	int timeout, cpu;
 	unsigned long start_eip;
-	unsigned short nmi_high, nmi_low;
+	unsigned short nmi_high = 0, nmi_low = 0;
 
 	cpu = ++cpucount;
 	/*
@@ -1019,7 +1019,10 @@
 	 * We have the boot CPU online for sure.
 	 */
 	set_bit(0, &cpu_online_map);
-	boot_cpu_logical_apicid = logical_smp_processor_id();
+	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		boot_cpu_logical_apicid = physical_to_logical_apicid(boot_cpu_physical_apicid);
+	else
+		boot_cpu_logical_apicid = logical_smp_processor_id();
 	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
 
 	global_irq_holder = 0;
@@ -1111,7 +1114,7 @@
 		if (apicid == boot_cpu_apicid)
 			continue;
 
-		if (!(phys_cpu_present_map & (1 << bit)))
+		if (!(phys_cpu_present_map & (1ul << bit)))
 			continue;
 		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
 			continue;
@@ -1122,9 +1125,9 @@
 		 * Make sure we unmap all failed CPUs
 		 */
 		if ((boot_apicid_to_cpu(apicid) == -1) &&
-				(phys_cpu_present_map & (1 << bit)))
-			printk("CPU #%d not responding - cannot use it.\n",
-								apicid);
+				(phys_cpu_present_map & (1ul << bit)))
+			printk("CPU #%d/0x%02x not responding - cannot use it.\n",
+								bit, apicid);
 	}
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/time.c linux-2.4.21-rc3/arch/i386/kernel/time.c
--- linux-2.4.20/arch/i386/kernel/time.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/kernel/time.c	2003-05-22 22:06:46.000000000 +0000
@@ -256,12 +256,185 @@
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
+
+/* IBM Summit (EXA) Cyclone Timer code*/
+#ifdef CONFIG_X86_SUMMIT
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0
+#define CYCLONE_PMCC_OFFSET 0x51A0
+#define CYCLONE_MPMC_OFFSET 0x51D0
+#define CYCLONE_MPCS_OFFSET 0x51A8
+#define CYCLONE_TIMER_FREQ 100000000
+
+int use_cyclone = 0;
+int __init cyclone_setup(char *str) 
+{
+	use_cyclone = 1;
+	return 1;
+}
+
+static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+static u32 last_cyclone_timer;
+
+static inline void mark_timeoffset_cyclone(void)
+{
+	int count;
+	unsigned long delta = last_cyclone_timer;
+	spin_lock(&i8253_lock);
+	/* quickly read the cyclone timer */
+	if(cyclone_timer)
+		last_cyclone_timer = cyclone_timer[0];
+
+	/* calculate delay_at_last_interrupt */
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	/*lost tick compensation*/
+	delta = last_cyclone_timer - delta;
+	if(delta > loops_per_jiffy+2000){
+		delta = (delta/loops_per_jiffy)-1;
+		jiffies += delta;
+	}
+               
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+static unsigned long do_gettimeoffset_cyclone(void)
+{
+	u32 offset;
+
+	if(!cyclone_timer)
+		return delay_at_last_interrupt;
+
+	/* Read the cyclone timer */
+	offset = cyclone_timer[0];
+
+	/* .. relative to previous jiffy */
+	offset = offset - last_cyclone_timer;
+
+	/* convert cyclone ticks to microseconds */	
+	/* XXX slow, can we speed this up? */
+	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + offset;
+}
+
+static void __init init_cyclone_clock(void)
+{
+	u32* reg;	
+	u32 base;		/* saved cyclone base address */
+	u32 pageaddr;	/* page that contains cyclone_timer register */
+	u32 offset;		/* offset from pageaddr to cyclone_timer register */
+	int i;
+	
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address */
+	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
+	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	base = *reg;	
+	if(!base){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		use_cyclone = 0;
+		return;
+	}
+	
+	/* setup PMCC */
+	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* setup MPCS */
+	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* map in cyclone_timer */
+	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!cyclone_timer){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+
+	/*quick test to make sure its ticking*/
+	for(i=0; i<3; i++){
+		u32 old = cyclone_timer[0];
+		int stall = 100;
+		while(stall--) barrier();
+		if(cyclone_timer[0] == old){
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			cyclone_timer = 0;
+			use_cyclone = 0;
+			return;
+		}
+	}
+	/* Everything looks good, so set do_gettimeoffset */
+	do_gettimeoffset = do_gettimeoffset_cyclone;	
+}
+void __cyclone_delay(unsigned long loops)
+{
+	unsigned long bclock, now;
+	if(!cyclone_timer)
+		return;
+	bclock = cyclone_timer[0];
+	do {
+		rep_nop();
+		now = cyclone_timer[0];
+	} while ((now-bclock) < loops);
+}
+#endif /* CONFIG_X86_SUMMIT */
+
 #else
 
 #define do_gettimeoffset()	do_fast_gettimeoffset()
 
 #endif
 
+/* No-cyclone stubs */
+#ifndef CONFIG_X86_SUMMIT
+int __init cyclone_setup(char *str) 
+{
+	printk(KERN_ERR "cyclone: Kernel not compiled with CONFIG_X86_SUMMIT, cannot use the cyclone-timer.\n");
+	return 1;
+}
+
+const int use_cyclone = 0;
+static void mark_timeoffset_cyclone(void) {}
+static unsigned long do_gettimeoffset_cyclone(void) {return 0;}
+static void init_cyclone_clock(void) {}
+void __cyclone_delay(unsigned long loops) {}
+#endif /* CONFIG_X86_SUMMIT */
+
 /*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
@@ -481,8 +654,9 @@
 	 */
 	write_lock(&xtime_lock);
 
-	if (use_tsc)
-	{
+	if(use_cyclone)
+		mark_timeoffset_cyclone();
+	else if (use_tsc) {
 		/*
 		 * It is important that these two operations happen almost at
 		 * the same time. We do the RDTSC stuff first, since it's
@@ -504,12 +678,34 @@
 
 		count = inb_p(0x40);    /* read the latched count */
 		count |= inb(0x40) << 8;
+
+		/* Any unpaired read will cause the above to swap MSB/LSB
+		   forever.  Try to detect this and reset the counter. 
+		   
+		   This happens very occasionally with buggy SMM bios
+		   code at least */
+		   
+		if (count > LATCH) {
+			printk(KERN_WARNING 
+			       "i8253 count too high! resetting..\n");
+			outb_p(0x34, 0x43);
+			outb_p(LATCH & 0xff, 0x40);
+			outb(LATCH >> 8, 0x40);
+			count = LATCH - 1;
+		}
+
 		spin_unlock(&i8253_lock);
 
+		/* Some i8253 clones hold the LATCH value visible
+		   momentarily as they flip back to zero */
+		if (count == LATCH) {
+			count--;
+		}
+
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 	}
- 
+
 	do_timer_interrupt(irq, NULL, regs);
 
 	write_unlock(&xtime_lock);
@@ -670,21 +866,30 @@
  	 */
  
  	dodgy_tsc();
- 	
+
+ 	if(use_cyclone)
+		init_cyclone_clock();
+		
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
 		if (tsc_quotient) {
 			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
+			/* XXX: This is messy
+			 * However, we want to allow for the cyclone timer 
+			 * to work w/ or w/o the TSCs being avaliable
+			 *      -johnstul@us.ibm.com
 			 */
-			x86_udelay_tsc = 1;
+			if(!use_cyclone){
+				/*
+				 *	We could be more selective here I suspect
+				 *	and just enable this for the next intel chips ?
+			 	 */
+				use_tsc = 1;
+				x86_udelay_tsc = 1;
 #ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
+				do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-
+			}
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
 			 * clock/second. Our precision is about 100 ppm.
@@ -699,6 +904,7 @@
 		}
 	}
 
+
 #ifdef CONFIG_VISWS
 	printk("Starting Cobalt Timer system clock\n");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/lib/delay.c linux-2.4.21-rc3/arch/i386/lib/delay.c
--- linux-2.4.20/arch/i386/lib/delay.c	2001-08-12 17:29:44.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/lib/delay.c	2003-05-22 22:06:52.000000000 +0000
@@ -56,10 +56,13 @@
 		:"=&a" (d0)
 		:"0" (loops));
 }
-
+extern void __cyclone_delay(unsigned long loops);
+extern int use_cyclone;
 void __delay(unsigned long loops)
 {
-	if (x86_udelay_tsc)
+	if (use_cyclone)
+		__cyclone_delay(loops);
+	else if (x86_udelay_tsc)
 		__rdtsc_delay(loops);
 	else
 		__loop_delay(loops);
@@ -78,3 +81,8 @@
 {
 	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
 }
+
+void __ndelay(unsigned long nsecs)
+{
+	__const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/lib/usercopy.c linux-2.4.21-rc3/arch/i386/lib/usercopy.c
--- linux-2.4.20/arch/i386/lib/usercopy.c	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/lib/usercopy.c	2003-05-22 22:06:24.000000000 +0000
@@ -95,6 +95,26 @@
 		: "memory");						   \
 } while (0)
 
+/**
+ * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ * 
+ * Copies a NUL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -103,6 +123,24 @@
 	return res;
 }
 
+/**
+ * strncpy_from_user: - Copy a NUL terminated string from userspace.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ * 
+ * Copies a NUL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -138,6 +176,16 @@
 		: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0));	\
 } while (0)
 
+/**
+ * clear_user: - Zero a block of memory in user space.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 clear_user(void *to, unsigned long n)
 {
@@ -146,6 +194,17 @@
 	return n;
 }
 
+/**
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 __clear_user(void *to, unsigned long n)
 {
@@ -153,12 +212,17 @@
 	return n;
 }
 
-/*
- * Return the size of a string (including the ending 0)
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ * @n:   The maximum valid length
  *
- * Return 0 on exception, a value greater than N if too long
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than @n.
  */
-
 long strnlen_user(const char *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/mm/init.c linux-2.4.21-rc3/arch/i386/mm/init.c
--- linux-2.4.20/arch/i386/mm/init.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/i386/mm/init.c	2003-05-22 22:06:38.000000000 +0000
@@ -356,7 +356,7 @@
 
 #if CONFIG_X86_PAE
 	/*
-	 * We will bail out later - printk doesnt work right now so
+	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
 	 */
 	if (cpu_has_pae)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/boot/bootloader.c linux-2.4.21-rc3/arch/ia64/boot/bootloader.c
--- linux-2.4.20/arch/ia64/boot/bootloader.c	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/boot/bootloader.c	2003-05-22 22:06:52.000000000 +0000
@@ -53,6 +53,15 @@
 
 #include "../kernel/fw-emu.c"
 
+/*
+ * Set a break point on this function so that symbols are available to set breakpoints in
+ * the kernel being debugged.
+ */
+static void
+debug_break (void)
+{
+}
+
 static void
 cons_write (const char *buf)
 {
@@ -187,6 +196,7 @@
 
 	ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
 
+	debug_break();
 	asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
 		      :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/config.in linux-2.4.21-rc3/arch/ia64/config.in
--- linux-2.4.20/arch/ia64/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/config.in	2003-05-22 22:06:47.000000000 +0000
@@ -51,8 +51,6 @@
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 fi
 
-bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n
-
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
@@ -65,10 +63,6 @@
 
 if [ "$CONFIG_MCKINLEY" = "y" ]; then
 	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
-	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
-	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC
-	fi
 fi
 
 if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
@@ -185,6 +179,9 @@
     bool 'Network device support' CONFIG_NETDEVICES
     if [ "$CONFIG_NETDEVICES" = "y" ]; then
       source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
     fi
     endmenu
   fi
@@ -256,10 +253,10 @@
   mainmenu_option next_comment
   comment 'Simulated drivers'
 
-  bool 'Simulated Ethernet ' CONFIG_SIMETH
-  bool 'Simulated serial driver support' CONFIG_SIM_SERIAL
+  bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+  bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
   if [ "$CONFIG_SCSI" != "n" ]; then
-    bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
+    bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
   fi
   endmenu
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/dig linux-2.4.21-rc3/arch/ia64/configs/dig
--- linux-2.4.20/arch/ia64/configs/dig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/configs/dig	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,946 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+# CONFIG_IA64_GENERIC is not set
+CONFIG_IA64_DIG=y
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# 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 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# 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_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+CONFIG_SOUND_FORTE=y
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/generic linux-2.4.21-rc3/arch/ia64/configs/generic
--- linux-2.4.20/arch/ia64/configs/generic	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/configs/generic	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,969 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+CONFIG_IA64_GENERIC=y
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# 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 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# 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_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Simulated drivers
+#
+# CONFIG_HP_SIMETH is not set
+# CONFIG_HP_SIMSERIAL is not set
+# CONFIG_HP_SIMSCSI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/ski linux-2.4.21-rc3/arch/ia64/configs/ski
--- linux-2.4.20/arch/ia64/configs/ski	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/configs/ski	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,468 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+CONFIG_IA64_HP_SIM=y
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# 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 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Simulated drivers
+#
+CONFIG_HP_SIMETH=y
+CONFIG_HP_SIMSERIAL=y
+CONFIG_HP_SIMSCSI=y
+
+#
+# Kernel hacking
+#
+# CONFIG_IA64_GRANULE_16MB is not set
+CONFIG_IA64_GRANULE_64MB=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/zx1 linux-2.4.21-rc3/arch/ia64/configs/zx1
--- linux-2.4.20/arch/ia64/configs/zx1	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/configs/zx1	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,956 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_HP_SIM is not set
+CONFIG_IA64_HP_ZX1=y
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_IA64_L1_CACHE_SHIFT=7
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# 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 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# 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_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+CONFIG_SOUND_FORTE=y
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/defconfig linux-2.4.21-rc3/arch/ia64/defconfig
--- linux-2.4.20/arch/ia64/defconfig	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/defconfig	2003-05-22 22:06:26.000000000 +0000
@@ -35,7 +35,6 @@
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
-CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_IA64_BRL_EMU=y
 # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
 CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -164,6 +163,7 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -197,6 +197,7 @@
 #
 CONFIG_FUSION=y
 CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
 # CONFIG_FUSION_ISENSE is not set
 # CONFIG_FUSION_CTL is not set
 # CONFIG_FUSION_LAN is not set
@@ -219,15 +220,6 @@
 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -241,8 +233,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -251,30 +243,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -287,6 +280,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -300,8 +294,10 @@
 CONFIG_SD_EXTRA_DEVS=40
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -345,11 +341,16 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -364,6 +365,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -398,17 +400,19 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -420,11 +424,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -434,13 +440,13 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-# CONFIG_NET_BROADCOM is not set
 # CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
 CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
@@ -501,8 +507,8 @@
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
 # CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_ACPI is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -557,12 +563,19 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_EFI_RTC=y
@@ -579,23 +592,27 @@
 # CONFIG_AGP_I810 is not set
 # CONFIG_AGP_VIA is not set
 # CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_SWORKS is not set
 CONFIG_AGP_I460=y
 CONFIG_AGP_HP_ZX1=y
 CONFIG_DRM=y
-CONFIG_DRM_OLD=y
+# CONFIG_DRM_OLD is not set
 
 #
-# DRM 4.0 drivers
+# DRM 4.1 drivers
 #
-CONFIG_DRM40_TDFX=y
-# CONFIG_DRM40_GAMMA is not set
-# CONFIG_DRM40_R128 is not set
-# CONFIG_DRM40_RADEON is not set
-# CONFIG_DRM40_I810 is not set
-# CONFIG_DRM40_MGA is not set
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
 
 #
 # Multimedia devices
@@ -626,21 +643,10 @@
 #
 # Radio Adapters
 #
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_GEMTEK is not set
 # CONFIG_RADIO_GEMTEK_PCI is not set
 # CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_MIROPCM20_RDS is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
 
 #
 # File systems
@@ -655,9 +661,11 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 CONFIG_JBD_DEBUG=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
@@ -672,6 +680,9 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -702,6 +713,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -716,7 +728,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -796,9 +807,9 @@
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
@@ -808,6 +819,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -830,15 +842,14 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
 #
-CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_UHCI=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
 # CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
+CONFIG_USB_OHCI=y
 
 #
 # USB Device Class drivers
@@ -846,6 +857,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -854,6 +866,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -861,12 +874,12 @@
 #
 # USB Human Interface Devices (HID)
 #
-CONFIG_USB_HID=m
+CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 CONFIG_USB_HIDDEV=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -881,6 +894,7 @@
 # USB Multimedia devices
 #
 # CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_PWC is not set
 # CONFIG_USB_SE401 is not set
@@ -908,39 +922,21 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Bluetooth support
@@ -950,15 +946,15 @@
 #
 # Simulated drivers
 #
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-# CONFIG_SCSI_SIM is not set
+# CONFIG_HP_SIMETH is not set
+# CONFIG_HP_SIMSERIAL is not set
+# CONFIG_HP_SIMSCSI is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_IA64_GRANULE_16MB is not set
-CONFIG_IA64_GRANULE_64MB=y
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_IA64_PRINT_HAZARDS=y
 # CONFIG_DISABLE_VHPT is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/common/sba_iommu.c linux-2.4.21-rc3/arch/ia64/hp/common/sba_iommu.c
--- linux-2.4.20/arch/ia64/hp/common/sba_iommu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/hp/common/sba_iommu.c	2003-05-22 22:06:48.000000000 +0000
@@ -39,8 +39,25 @@
 
 #define PFX "IOC: "
 
+/*
+** This option allows cards capable of 64bit DMA to bypass the IOMMU.  If
+** not defined, all DMA will be 32bit and go through the TLB.
+*/
 #define ALLOW_IOV_BYPASS
+
+/*
+** If a device prefetches beyond the end of a valid pdir entry, it will cause
+** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
+** disconnect on 4k boundaries and prevent such issues.  If the device is
+** particularly agressive, this option will keep the entire pdir valid such
+** that prefetching will hit a valid address.  This could severely impact
+** error containment, and is therefore off by default.  The page that is
+** used for spill-over is poisoned, so that should help debugging somewhat.
+*/
+#undef FULL_VALID_PDIR
+
 #define ENABLE_MARK_CLEAN
+
 /*
 ** The number of debug flags is a clue - this code is fragile.
 */
@@ -52,6 +69,10 @@
 #undef DEBUG_LARGE_SG_ENTRIES
 #undef DEBUG_BYPASS
 
+#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY)
+#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive
+#endif
+
 #define SBA_INLINE	__inline__
 /* #define SBA_INLINE */
 
@@ -196,9 +217,12 @@
 static struct ioc *ioc_list;
 static int reserve_sba_gart = 1;
 
-#define sba_sg_iova(sg) (sg->address)
-#define sba_sg_len(sg) (sg->length)
-#define sba_sg_buffer(sg) (sg->orig_address)
+#define sba_sg_address(sg)	(sg->address ? sg->address : \
+				       page_address((sg)->page) + (sg)->offset)
+
+#ifdef FULL_VALID_PDIR
+static void* prefetch_spill_page;
+#endif
 
 #define GET_IOC(dev)	((struct ioc *) PCI_CONTROLLER(dev)->iommu)
 
@@ -338,10 +362,8 @@
 {
 	while (nents-- > 0) {
 		printk(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg),
-				sba_sg_len(startsg),
-				sba_sg_buffer(startsg));
+				nents, startsg->dma_address,
+				startsg->dma_length, sba_sg_address(startsg));
 		startsg++;
 	}
 }
@@ -352,7 +374,7 @@
 	int the_nents = nents;
 
 	while (the_nents-- > 0) {
-		if (sba_sg_buffer(the_sg) == 0x0UL)
+		if (sba_sg_address(the_sg) == 0x0UL)
 			sba_dump_sg(NULL, startsg, nents);
 		the_sg++;
 	}
@@ -626,7 +648,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -673,6 +695,7 @@
 
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
+#ifndef FULL_VALID_PDIR
 		/*
 		** clear I/O PDIR entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
@@ -680,6 +703,14 @@
 		** been enabled.
 		*/
 		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+		/*
+  		** If we want to maintain the PDIR as valid, put in
+		** the spill page so devices prefetching won't
+		** cause a hard fail.
+		*/
+		ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 	} else {
 		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
 
@@ -689,14 +720,18 @@
 		do {
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
+#ifndef FULL_VALID_PDIR
 			/* clear I/O Pdir entry "valid" bit first */
 			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+			ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM);
 }
 
 /**
@@ -991,32 +1026,28 @@
 
 	dma_sg--;
 	while (nents-- > 0) {
-		int     cnt = sba_sg_len(startsg);
-		sba_sg_len(startsg) = 0;
+		int     cnt = startsg->dma_length;
+		startsg->dma_length = 0;
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
 			printk(" %2d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #endif
 		/*
 		** Look for the start of a new DMA stream
 		*/
-		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
-			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+		if (startsg->dma_address & PIDE_FLAG) {
+			u32 pide = startsg->dma_address & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sba_sg_iova(startsg) = 0;
+			startsg->dma_address = 0;
 			dma_sg++;
-			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+			dma_sg->dma_address = pide | ioc->ibase;
 			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
@@ -1025,13 +1056,13 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+			unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
 			ASSERT(pdirp);
 
 			/* Since multiple Vcontig blocks could make up
 			** one DMA stream, *add* cnt to dma_len.
 			*/
-			sba_sg_len(dma_sg) += cnt;
+			dma_sg->dma_length += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
 			cnt = ROUNDUP(cnt, IOVP_SIZE);
@@ -1091,20 +1122,18 @@
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) (startsg->address); 
+		unsigned long vaddr = (unsigned long) sba_sg_address(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
 		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+		dma_len = vcontig_len = vcontig_end = startsg->length;
 		vcontig_end +=  vaddr;
 		dma_offset = vaddr & ~IOVP_MASK;
 
 		/* PARANOID: clear entries */
-		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
-		sba_sg_iova(startsg) = 0;
-		sba_sg_len(startsg) = 0;
+		startsg->dma_address = startsg->dma_length = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
@@ -1115,6 +1144,9 @@
 
 			startsg++;
 
+			/* PARANOID */
+			startsg->dma_address = startsg->dma_length = 0;
+
 			/* catch brokenness in SCSI layer */
 			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
@@ -1131,15 +1163,12 @@
 			**
 			** append the next transaction?
 			*/
-			vaddr = (unsigned long) sba_sg_iova(startsg);
+			vaddr = (unsigned long) sba_sg_address(startsg);
 			if  (vcontig_end == vaddr)
 			{
-				vcontig_len += sba_sg_len(startsg);
-				vcontig_end += sba_sg_len(startsg);
-				dma_len     += sba_sg_len(startsg);
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				sba_sg_len(startsg) = 0;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
@@ -1158,10 +1187,10 @@
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sba_sg_len(vcontig_sg) = vcontig_len;
+			vcontig_sg->dma_length = vcontig_len;
 
 			vcontig_sg = startsg;
-			vcontig_len = sba_sg_len(startsg);
+			vcontig_len = startsg->length;
 
 			/*
 			** 3) do the entries end/start on page boundaries?
@@ -1171,8 +1200,6 @@
 			{
 				vcontig_end = vcontig_len + vaddr;
 				dma_len += vcontig_len;
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
 				continue;
 			} else {
 				break;
@@ -1184,10 +1211,10 @@
 		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sba_sg_len(vcontig_sg) = vcontig_len;
+		vcontig_sg->dma_length = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
 		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
+		dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
 			| dma_offset);
 		n_mappings++;
@@ -1223,8 +1250,8 @@
 #ifdef ALLOW_IOV_BYPASS
 	if (dev->dma_mask >= ioc->dma_mask) {
 		for (sg = sglist ; filled < nents ; filled++, sg++){
-			sba_sg_buffer(sg) = sba_sg_iova(sg);
-			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+			sg->dma_length = sg->length;
+			sg->dma_address = virt_to_phys(sba_sg_address(sg));
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
@@ -1236,10 +1263,10 @@
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
-		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
-						sba_sg_buffer(sglist),
-						sba_sg_len(sglist), direction);
+		sglist->dma_length = sglist->length;
+		sglist->dma_address = sba_map_single(dev,
+		                                     sba_sg_address(sglist),
+		                                     sglist->length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
@@ -1318,7 +1345,7 @@
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1333,10 +1360,10 @@
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-	while (sba_sg_len(sglist) && nents--) {
+	while (nents && sglist->dma_length) {
 
-		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_len(sglist), direction);
+		sba_unmap_single(dev, sglist->dma_address,
+		                 sglist->dma_length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1344,9 +1371,10 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length + IOVP_SIZE - 1) >> PAGE_SHIFT;
 #endif
-		++sglist;
+		sglist++;
+		nents--;
 	}
 
 	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
@@ -1359,12 +1387,6 @@
 
 }
 
-unsigned long
-sba_dma_address (struct scatterlist *sg)
-{
-	return ((unsigned long)sba_sg_iova(sg));
-}
-
 int
 sba_dma_supported (struct pci_dev *dev, u64 mask)
 {
@@ -1384,6 +1406,9 @@
 	int iov_order, tcnfg;
 	int agp_found = 0;
 	struct pci_dev *device;
+#ifdef FULL_VALID_PDIR
+	unsigned long index;
+#endif
 
 	/*
 	** Firmware programs the base and size of a "safe IOVA space"
@@ -1481,7 +1506,7 @@
 	** Clear I/O TLB of any possible entries.
 	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM);
+	WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM);
 
 	/*
 	** If an AGP device is present, only use half of the IOV space
@@ -1499,6 +1524,34 @@
 		ioc->pdir_size /= 2;
 		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
 	}
+#ifdef FULL_VALID_PDIR
+	/*
+  	** Check to see if the spill page has been allocated, we don't need more than
+	** one across multiple SBAs.
+	*/
+	if (!prefetch_spill_page) {
+		char *spill_poison = "SBAIOMMU POISON";
+		int poison_size = 16;
+		void *poison_addr;
+									
+		prefetch_spill_page = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE));
+		if (!prefetch_spill_page)
+			panic(PFX "Couldn't allocate PDIR spill page\n");
+
+		poison_addr = prefetch_spill_page;
+		for (; (u64)poison_addr < (u64)prefetch_spill_page + IOVP_SIZE ; poison_addr += poison_size)
+			(void)memcpy(poison_addr,spill_poison,poison_size);
+
+		prefetch_spill_page = (void *)virt_to_phys(prefetch_spill_page);
+
+		DBG_INIT("%s() prefetch spill addr: %p\n", __FUNCTION__, prefetch_spill_page);
+	}
+	/*
+  	** Set all the PDIR entries valid w/ the spill page as the target
+	*/
+	for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++)
+		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 }
 
 static void __init
@@ -1525,6 +1578,11 @@
 	ioc->res_map[0] = 0x1;
 	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
 #endif
+#ifdef FULL_VALID_PDIR
+	/* Mark the last resource used so we don't prefetch beyond IOVA space */
+	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */
+	ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 
 	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
 		 ioc->res_size, (void *) ioc->res_map);
@@ -1608,15 +1666,23 @@
 				(info->init)(ioc);
 		}
 	}
-	if (!ioc->name)
-		ioc->name = "Unknown";
+
+	if (!ioc->name) {
+		ioc->name = kmalloc(24, GFP_KERNEL);
+		if (ioc->name)
+			sprintf(ioc->name, "Unknown (%04x:%04x)",
+				ioc->func_id & 0xFFFF,
+				(ioc->func_id >> 16) & 0xFFFF);
+		else
+			ioc->name = "Unknown";
+	}
 
 	ioc_iova_init(ioc);
 	ioc_resource_init(ioc);
 	ioc_sac_init(ioc);
 
 	printk(KERN_INFO PFX
-		"Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
 		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
 		hpa, ioc->iov_size >> 20, ioc->ibase);
 
@@ -1861,7 +1927,6 @@
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
-EXPORT_SYMBOL(sba_dma_address);
 EXPORT_SYMBOL(sba_dma_supported);
 EXPORT_SYMBOL(sba_alloc_consistent);
 EXPORT_SYMBOL(sba_free_consistent);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/sim/Makefile linux-2.4.21-rc3/arch/ia64/hp/sim/Makefile
--- linux-2.4.20/arch/ia64/hp/sim/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/hp/sim/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,8 @@
 #
 # ia64/platform/hp/sim/Makefile
 #
+# Copyright (C) 2002 Hewlett-Packard Co.
+#	David Mosberger-Tang <davidm@hpl.hp.com>
 # Copyright (C) 1999 Silicon Graphics, Inc.
 # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.21-rc3/arch/ia64/hp/zx1/hpzx1_misc.c
--- linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/hp/zx1/hpzx1_misc.c	2003-05-22 22:06:26.000000000 +0000
@@ -17,8 +17,6 @@
 #include <asm/dma.h>
 #include <asm/iosapic.h>
 
-extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
-
 #define PFX "hpzx1: "
 
 static int hpzx1_devices;
@@ -252,40 +250,8 @@
 	 * HWP0003: AGP LBA device
 	 */
 	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-#ifdef CONFIG_IA64_HP_PROTO
-	if (hpzx1_devices) {
-#endif
 	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
 	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
-
-#ifdef CONFIG_IA64_HP_PROTO
-	}
-
-#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
-	/*
-	 * Early protos don't have bridges in the ACPI namespace, so
-	 * if we didn't find anything, add the things we know are
-	 * there.
-	 */
-	if (hpzx1_devices == 0) {
-		u64 hpa, csr_base;
-
-		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x2000);
-		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
-					    0x1000);
-
-			csr_base = 0xfed24000UL;
-			iounmap(hpa);
-			hpa = (u64) ioremap(csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
-					    0x1000);
-		}
-		iounmap(hpa);
-	}
-#endif
 }
 
 extern void sba_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_entry.S linux-2.4.21-rc3/arch/ia64/ia32/ia32_entry.S
--- linux-2.4.20/arch/ia64/ia32/ia32_entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/ia32/ia32_entry.S	2003-05-22 22:06:48.000000000 +0000
@@ -180,7 +180,7 @@
 	data8 sys32_fork
 	data8 sys_read
 	data8 sys_write
-	data8 sys_open		  /* 5 */
+	data8 sys32_open	  /* 5 */
 	data8 sys_close
 	data8 sys32_waitpid
 	data8 sys_creat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_signal.c linux-2.4.21-rc3/arch/ia64/ia32/ia32_signal.c
--- linux-2.4.20/arch/ia64/ia32/ia32_signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/ia32/ia32_signal.c	2003-05-22 22:06:25.000000000 +0000
@@ -39,6 +39,16 @@
 #define __IA32_NR_sigreturn            119
 #define __IA32_NR_rt_sigreturn         173
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 struct sigframe_ia32
 {
        int pretcode;
@@ -143,6 +153,304 @@
 	return err;
 }
 
+
+/*
+ *  SAVE and RESTORE of ia32 fpstate info, from ia64 current state
+ *  Used in exception handler to pass the fpstate to the user, and restore
+ *  the fpstate while returning from the exception handler.
+ *
+ *    fpstate info and their mapping to IA64 regs:
+ *    fpstate    REG(BITS)      Attribute    Comments
+ *    cw         ar.fcr(0:12)                with bits 7 and 6 not used
+ *    sw         ar.fsr(0:15)
+ *    tag        ar.fsr(16:31)               with odd numbered bits not used
+ *                                           (read returns 0, writes ignored)
+ *    ipoff      ar.fir(0:31)
+ *    cssel      ar.fir(32:47)
+ *    dataoff    ar.fdr(0:31)
+ *    datasel    ar.fdr(32:47)
+ *
+ *    _st[(0+TOS)%8]   f8
+ *    _st[(1+TOS)%8]   f9                    (f8, f9 from ptregs)
+ *      : :            :                     (f10..f15 from live reg)
+ *      : :            :
+ *    _st[(7+TOS)%8]   f15                   TOS=sw.top(bits11:13)
+ *
+ *    status     Same as sw     RO
+ *    magic      0                           as X86_FXSR_MAGIC in ia32
+ *    mxcsr      Bits(7:15)=ar.fcr(39:47)
+ *               Bits(0:5) =ar.fsr(32:37)    with bit 6 reserved
+ *    _xmm[0..7] f16..f31                    (live registers)
+ *                                           with _xmm[0]
+ *                                             Bit(64:127)=f17(0:63)
+ *                                             Bit(0:63)=f16(0:63)
+ *    All other fields unused...
+ */
+
+#define __ldfe(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldfe %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __ldf8(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldf8 %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __stfe(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+#define __stf8(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+static int
+save_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	unsigned long new_fsr;
+	unsigned long num128[2];
+	unsigned long mxcsr=0;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	/* Readin fsr, fcr, fir, fdr and copy onto fpstate */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+	/*
+	 * We need to clear the exception state before calling the signal handler. Clear
+	 * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex
+	 * instruction.
+	 */
+	new_fsr = fsr & ~0x80ff;
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(new_fsr));
+
+	__put_user(fcr & 0xffff, &save->cw);
+	__put_user(fsr & 0xffff, &save->sw);
+	__put_user((fsr>>16) & 0xffff, &save->tag);
+	__put_user(fir, &save->ipoff);
+	__put_user((fir>>32) & 0xffff, &save->cssel);
+	__put_user(fdr, &save->dataoff);
+	__put_user((fdr>>32) & 0xffff, &save->datasel);
+	__put_user(fsr & 0xffff, &save->status);
+
+	mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	__put_user( 0, &save->magic); //#define X86_FXSR_MAGIC   0x0000
+
+	/*
+	 * save f8 and f9  from pt_regs
+	 * save f10..f15 from live register set
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	ptp = ia64_task_regs(tsk);
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+	ia64f2ia32f(fpregp, &ptp->f8);
+	copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	ia64f2ia32f(fpregp, &ptp->f9);
+	copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stfe(fpregp, 10);
+	copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 11);
+	copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 12);
+	copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 13);
+	copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 14);
+	copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 15);
+	copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stf8(&num128[0], 16);
+	__stf8(&num128[1], 17);
+	copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 18);
+	__stf8(&num128[1], 19);
+	copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 20);
+	__stf8(&num128[1], 21);
+	copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 22);
+	__stf8(&num128[1], 23);
+	copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 24);
+	__stf8(&num128[1], 25);
+	copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 26);
+	__stf8(&num128[1], 27);
+	copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 28);
+	__stf8(&num128[1], 29);
+	copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 30);
+	__stf8(&num128[1], 31);
+	copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32));
+	return 0;
+}
+
+static int
+restore_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	unsigned int lo, hi;
+	unsigned long num128[2];
+	unsigned long num64, mxcsr;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	/*
+	 * Updating fsr, fcr, fir, fdr.
+	 * Just a bit more complicated than save.
+	 * - Need to make sure that we dont write any value other than the
+	 *   specific fpstate info
+	 * - Need to make sure that the untouched part of frs, fdr, fir, fcr
+	 *   should remain same while writing.
+	 * So, we do a read, change specific fields and write.
+	 */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	/* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->cw);
+	num64 = mxcsr & 0xff10;
+	num64 = (num64 << 32) | (lo & 0x1f3f);
+	fcr = (fcr & (~0xff1000001f3f)) | num64;
+
+	/* setting bits 0..31 with sw and tag and 32..37 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->sw);
+	/* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */
+	if ( !(lo & 0x7f) )
+		lo &= (~0x8080);
+	__get_user(hi, (unsigned int *)&save->tag);
+	num64 = mxcsr & 0x3f;
+	num64 = (num64 << 16) | (hi & 0xffff);
+	num64 = (num64 << 16) | (lo & 0xffff);
+	fsr = (fsr & (~0x3fffffffff)) | num64;
+
+	/* setting bits 0..47 with cssel and ipoff */
+	__get_user(lo, (unsigned int *)&save->ipoff);
+	__get_user(hi, (unsigned int *)&save->cssel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fir = (fir & (~0xffffffffffff)) | num64;
+
+	/* setting bits 0..47 with datasel and dataoff */
+	__get_user(lo, (unsigned int *)&save->dataoff);
+	__get_user(hi, (unsigned int *)&save->datasel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fdr = (fdr & (~0xffffffffffff)) | num64;
+
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(fsr));
+	asm volatile ( "mov ar.fcr=%0;" :: "r"(fcr));
+	asm volatile ( "mov ar.fir=%0;" :: "r"(fir));
+	asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr));
+
+	/*
+	 * restore f8, f9 onto pt_regs
+	 * restore f10..f15 onto live registers
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+
+	ptp = ia64_task_regs(tsk);
+	copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f8, fpregp);
+	copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f9, fpregp);
+
+	copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(10, fpregp);
+	copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(11, fpregp);
+	copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(12, fpregp);
+	copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(13, fpregp);
+	copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(14, fpregp);
+	copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(15, fpregp);
+
+	copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32));
+	__ldf8(16, &num128[0]);
+	__ldf8(17, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32));
+	__ldf8(18, &num128[0]);
+	__ldf8(19, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32));
+	__ldf8(20, &num128[0]);
+	__ldf8(21, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32));
+	__ldf8(22, &num128[0]);
+	__ldf8(23, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32));
+	__ldf8(24, &num128[0]);
+	__ldf8(25, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32));
+	__ldf8(26, &num128[0]);
+	__ldf8(27, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32));
+	__ldf8(28, &num128[0]);
+	__ldf8(29, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32));
+	__ldf8(30, &num128[0]);
+	__ldf8(31, &num128[1]);
+	return 0;
+}
+
 static inline void
 sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
 {
@@ -371,6 +679,9 @@
 	int  err = 0;
 	unsigned long flag;
 
+	if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc)))
+		return -EFAULT;
+
 	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
 	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
 	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
@@ -397,6 +708,11 @@
 	err |= __put_user(regs->r12, &sc->esp_at_signal);
 	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
+	if ( save_ia32_fpstate_live(fpstate) < 0 )
+		err = -EFAULT;
+	else
+		err |= __put_user((u32)(u64)fpstate, &sc->fpstate);
+
 #if 0
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
@@ -418,6 +734,9 @@
 {
 	unsigned int err = 0;
 
+	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
+		return(-EFAULT);
+
 #define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
 #define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
@@ -477,6 +796,16 @@
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
 	}
 
+	{
+		struct _fpstate_ia32 *buf = NULL;
+		u32    fpstate_ptr;
+		err |= get_user(fpstate_ptr, &(sc->fpstate));
+		buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr;
+		if (buf) {
+			err |= restore_ia32_fpstate_live(buf);
+		}
+	}
+
 #if 0
 	{
 		struct _fpstate * buf;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_support.c linux-2.4.21-rc3/arch/ia64/ia32/ia32_support.c
--- linux-2.4.20/arch/ia64/ia32/ia32_support.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/ia32/ia32_support.c	2003-05-22 22:06:26.000000000 +0000
@@ -95,8 +95,6 @@
 	struct pt_regs *regs = ia64_task_regs(t);
 	int nr = smp_processor_id();	/* LDT and TSS depend on CPU number: */
 
-	nr = smp_processor_id();
-
 	eflag = t->thread.eflag;
 	fsr = t->thread.fsr;
 	fcr = t->thread.fcr;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/sys_ia32.c linux-2.4.21-rc3/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.20/arch/ia64/ia32/sys_ia32.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/ia32/sys_ia32.c	2003-05-22 22:06:48.000000000 +0000
@@ -623,7 +623,8 @@
 			/* end address is 4KB aligned but not page aligned. */
 			retval = mprotect_subpage(PAGE_START(end), prot);
 			if (retval < 0)
-				return retval;
+				goto out;
+
 			end = PAGE_START(end);
 		}
 		retval = sys_mprotect(start, end - start, prot);
@@ -2118,8 +2119,8 @@
 };
 
 struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
+	u32 msgp;
+	s32 msgtyp;
 };
 
 #define SEMOP		 1
@@ -2843,20 +2844,6 @@
 	}
 }
 
-static inline void
-ia32f2ia64f (void *dst, void *src)
-{
-	asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory");
-	return;
-}
-
-static inline void
-ia64f2ia32f (void *dst, void *src)
-{
-	asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst),  "r"(src) : "memory");
-	return;
-}
-
 static void
 put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
 	   int tos)
@@ -2913,57 +2900,152 @@
 }
 
 static int
-save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
 	int i, tos;
 
 	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-		return -EIO;
-	__put_user(tsk->thread.fcr, &save->cw);
-	__put_user(tsk->thread.fsr, &save->sw);
-	__put_user(tsk->thread.fsr >> 32, &save->tag);
-	__put_user(tsk->thread.fir, &save->ipoff);
-	__put_user(__USER_CS, &save->cssel);
-	__put_user(tsk->thread.fdr, &save->dataoff);
-	__put_user(__USER_DS, &save->datasel);
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		put_fpreg(i, &save->_st[i], ptp, swp, tos);
+		put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
 	return 0;
 }
 
 static int
-restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
-	int i, tos, ret;
-	int fsrlo, fsrhi;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
 
 	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-		return(-EIO);
-	ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
-	ret |= __get_user(fsrlo, (unsigned int *)&save->sw);
-	ret |= __get_user(fsrhi, (unsigned int *)&save->tag);
-	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
-	ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
-	ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return ret ? -EFAULT : 0;
+		get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+	return 0;
+}
+
+static int
+save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned long mxcsr=0;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
+        /*
+         *  Stack frames start with 16-bytes of temp space
+         */
+        swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+        ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+        for (i = 0; i < 8; i++)
+		put_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	for (i = 0; i < 8; i++) {
+		memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long));
+		memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long));
+		copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32));
+	}
+	return 0;
+}
+
+static int
+restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
+	int mxcsr;
+	unsigned long num64;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+	for (i = 0; i < 8; i++)
+	get_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	num64 = mxcsr & 0xff10;
+	tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32);
+	num64 = mxcsr & 0x3f;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32);
+
+	for (i = 0; i < 8; i++) {
+		copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32));
+		memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long));
+		memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long));
+	}
+	return 0;
 }
 
 extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
@@ -3075,11 +3157,19 @@
 		break;
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_GETFPXREGS:
+		ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_SETFPXREGS:
+		ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
@@ -3825,6 +3915,37 @@
 	return ret;
 }
 
+/*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag.
+ */
+asmlinkage long
+sys32_open (const char * filename, int flags, int mode)
+{
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file *f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
+
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
+
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 struct ncp_mount_data32 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/acpi.c linux-2.4.21-rc3/arch/ia64/kernel/acpi.c
--- linux-2.4.20/arch/ia64/kernel/acpi.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/acpi.c	2003-05-22 22:06:46.000000000 +0000
@@ -102,8 +102,6 @@
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
-# elif defined (CONFIG_IA64_HP_ZX1)
-	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
@@ -112,33 +110,7 @@
 
 #ifdef CONFIG_ACPI
 
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, acpi_buffer *buf)
-{
-	acpi_status result;
-	buf->length = 0;
-	buf->pointer = NULL;
-
-	result = acpi_get_current_resources(obj, buf);
-	if (result != AE_BUFFER_OVERFLOW)
-		return result;
-	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
-	if (!buf->pointer)
-		return -ENOMEM;
-
-	return acpi_get_current_resources(obj, buf);
-}
-
-acpi_resource *
+static acpi_resource *
 acpi_get_crs_next (acpi_buffer *buf, int *offset)
 {
 	acpi_resource *res;
@@ -146,12 +118,12 @@
 	if (*offset >= buf->length)
 		return NULL;
 
-	res = buf->pointer + *offset;
+	res = (acpi_resource *)((char *) buf->pointer + *offset);
 	*offset += res->length;
 	return res;
 }
 
-acpi_resource_data *
+static acpi_resource_data *
 acpi_get_crs_type (acpi_buffer *buf, int *offset, int type)
 {
 	for (;;) {
@@ -163,12 +135,6 @@
 	}
 }
 
-void
-acpi_dispose_crs (acpi_buffer *buf)
-{
-	kfree(buf->pointer);
-}
-
 static void
 acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra)
 {
@@ -210,6 +176,9 @@
 					return;
 				}
 				break;
+			case ACPI_RSTYPE_END_TAG:
+				return;
+				break;
 		}
 	}
 }
@@ -218,13 +187,14 @@
 acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
 {
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 
 	*base = 0;
 	*length = 0;
 	*tra = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
@@ -232,7 +202,7 @@
 
 	acpi_get_crs_addr(&buf, type, base, length, tra);
 
-	acpi_dispose_crs(&buf);
+	acpi_os_free(buf.pointer);
 
 	return AE_OK;
 }
@@ -254,7 +224,8 @@
 {
 	int i, offset = 0;
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 	acpi_resource_vendor *res;
 	acpi_hp_vendor_long *hp_res;
 	efi_guid_t vendor_guid;
@@ -262,42 +233,41 @@
 	*csr_base = 0;
 	*csr_length = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
 	}
 
+	status = AE_NOT_FOUND;
 	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
 	if (!res) {
 		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
+		goto out;
 	}
 
+	status = AE_TYPE; /* Revisit error? */
 	hp_res = (acpi_hp_vendor_long *)(res->reserved);
 
 	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
 		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
 	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
 	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
 		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
-	}
-
-	acpi_dispose_crs(&buf);
+	/* It's probably unaligned, so use memcpy */
+	memcpy(csr_base, hp_res->csr_base, 8);
+	memcpy(csr_length, hp_res->csr_length, 8);
+	status = AE_OK;
 
-	return AE_OK;
+ out:
+	acpi_os_free(buf.pointer);
+	return status;
 }
 #endif /* CONFIG_ACPI */
 
@@ -368,6 +338,7 @@
 acpi_parse_lsapic (acpi_table_entry_header *header)
 {
 	struct acpi_table_lsapic *lsapic;
+	int phys_id;
 
 	lsapic = (struct acpi_table_lsapic *) header;
 	if (!lsapic)
@@ -375,13 +346,21 @@
 
 	acpi_table_print_madt_entry(header);
 
-	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+	phys_id = (lsapic->id << 8) | lsapic->eid;
+
+	if (total_cpus == NR_CPUS) {
+		printk(KERN_ERR PREFIX "Ignoring CPU (0x%04x) (NR_CPUS == %d)\n",
+			phys_id, NR_CPUS);
+		return 0;
+	}
+
+	printk("CPU %d (0x%04x)", total_cpus, phys_id);
 
 	if (lsapic->flags.enabled) {
 		available_cpus++;
 		printk(" enabled");
 #ifdef CONFIG_SMP
-		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+		smp_boot_data.cpu_phys_id[total_cpus] = phys_id;
 		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
@@ -464,9 +443,8 @@
 
 	if (iosapic_init) {
 #ifndef CONFIG_ITANIUM
-		/* PCAT_COMPAT flag indicates dual-8259 setup */
 		iosapic_init(iosapic->address, iosapic->global_irq_base,
-			     acpi_madt->flags.pcat_compat);
+			     has_8259);
 #else
 		/* Firmware on old Itanium systems is broken */
 		iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
@@ -616,59 +594,6 @@
 }
 
 
-#ifdef CONFIG_SERIAL_ACPI
-
-#include <linux/acpi_serial.h>
-
-static int __init
-acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
-{
-	acpi_ser_t *spcr;
-	u32 gsi, gsi_base;
-	char *iosapic_address;
-
-	if (!phys_addr || !size)
-		return -EINVAL;
-
-	if (!iosapic_register_intr)
-		return -ENODEV;
-
-	/*
-	 * ACPI is able to describe serial ports that live at non-standard
-	 * memory addresses and use non-standard interrupts, either via
-	 * direct SAPIC mappings or via PCI interrupts.  We handle interrupt
-	 * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing
-	 * for PCI devices will be handled when processing the PCI Interrupt
-	 * Routing Table (PRT).
-	 */
-
-	spcr = (acpi_ser_t *) __va(phys_addr);
-	setup_serial_acpi(spcr);
-
-	if (spcr->length < sizeof(acpi_ser_t))
-		/* Table not long enough for full info, thus no interrupt */
-		return -ENODEV;
-
-	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
-	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC)) {
-
-		/* We have a UART in memory space with an SAPIC interrupt */
-
-		gsi = (spcr->global_int[3] << 24) |
-		      (spcr->global_int[2] << 16) |
-		      (spcr->global_int[1] << 8)  |
-		      (spcr->global_int[0]);
-
-		if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address))
-			iosapic_register_intr(gsi, 1, 1,
-					      gsi_base, iosapic_address);
-	}
-	return 0;
-}
-
-#endif /*CONFIG_SERIAL_ACPI*/
-
-
 unsigned long __init
 acpi_find_rsdp (void)
 {
@@ -749,10 +674,6 @@
 	if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1)
 		printk(KERN_ERR PREFIX "Can't find FADT\n");
 
-#ifdef CONFIG_SERIAL_ACPI
-	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
-#endif
-
 #ifdef CONFIG_SMP
 	if (available_cpus == 0) {
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/efi.c linux-2.4.21-rc3/arch/ia64/kernel/efi.c
--- linux-2.4.20/arch/ia64/kernel/efi.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/efi.c	2003-05-22 22:06:25.000000000 +0000
@@ -51,66 +51,156 @@
 
 static unsigned long mem_limit = ~0UL;
 
-static efi_status_t
-phys_get_time (efi_time_t *tm, efi_time_cap_t *tc)
-{
-	return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc));
-}
-
-static efi_status_t
-phys_set_time (efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_time), __pa(tm));
-}
+#define efi_call_virt(f, args...)	(*(f))(args)
 
-static efi_status_t
-phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending),
-			     __pa(tm));
-}
-
-static efi_status_t
-phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm));
-}
-
-static efi_status_t
-phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-		   unsigned long *data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr),
-			     __pa(data_size), __pa(data));
-}
-
-static efi_status_t
-phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
-{
-	return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name),
-			     __pa(vendor));
-}
-
-static efi_status_t
-phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
-		   unsigned long data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr,
-			     data_size, __pa(data));
-}
-
-static efi_status_t
-phys_get_next_high_mono_count (u64 *count)
-{
-	return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count));
-}
-
-static void
-phys_reset_system (int reset_type, efi_status_t status,
-		   unsigned long data_size, efi_char16_t *data)
-{
-	efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data));
-}
+#define STUB_GET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)						\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm),	\
+				adjust_arg(tc));						\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_set_time (efi_time_t *tm)								\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)		\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),	\
+				adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)					\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),	\
+				enabled, adjust_arg(tm));					\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,		\
+		       unsigned long *data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable),	\
+				adjust_arg(name), adjust_arg(vendor), adjust_arg(attr),	\
+				adjust_arg(data_size), adjust_arg(data));		\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)	\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable),	\
+				adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,		\
+		       unsigned long data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable),	\
+				adjust_arg(name), adjust_arg(vendor), attr, data_size,	\
+				adjust_arg(data));					\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)					\
+static efi_status_t										\
+prefix##_get_next_high_mono_count (u64 *count)							\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)				\
+				__va(runtime->get_next_high_mono_count), adjust_arg(count));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_RESET_SYSTEM(prefix, adjust_arg)					\
+static void									\
+prefix##_reset_system (int reset_type, efi_status_t status,			\
+		       unsigned long data_size, efi_char16_t *data)		\
+{										\
+	struct ia64_fpreg fr[6];						\
+										\
+	ia64_save_scratch_fpregs(fr);						\
+	efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system),	\
+			  reset_type, status, data_size, adjust_arg(data));	\
+	/* should not return, but just in case... */				\
+	ia64_load_scratch_fpregs(fr);						\
+}
+
+STUB_GET_TIME(phys, __pa)
+STUB_SET_TIME(phys, __pa)
+STUB_GET_WAKEUP_TIME(phys, __pa)
+STUB_SET_WAKEUP_TIME(phys, __pa)
+STUB_GET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_VARIABLE(phys, __pa)
+STUB_SET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa)
+STUB_RESET_SYSTEM(phys, __pa)
+
+STUB_GET_TIME(virt, )
+STUB_SET_TIME(virt, )
+STUB_GET_WAKEUP_TIME(virt, )
+STUB_SET_WAKEUP_TIME(virt, )
+STUB_GET_VARIABLE(virt, )
+STUB_GET_NEXT_VARIABLE(virt, )
+STUB_SET_VARIABLE(virt, )
+STUB_GET_NEXT_HIGH_MONO_COUNT(virt, )
+STUB_RESET_SYSTEM(virt, )
 
 void
 efi_gettimeofday (struct timeval *tv)
@@ -207,7 +297,7 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p, *q;
+	void *efi_map_start, *efi_map_end, *p, *q, *r;
 	efi_memory_desc_t *md, *check_md;
 	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
@@ -252,11 +342,10 @@
 
 			if (!(first_non_wb_addr > granule_addr))
 				continue;	/* couldn't find enough contiguous memory */
-		}
-
-		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
 
-		trim_top(md, first_non_wb_addr);
+			for (r = p; r < q; r += efi_desc_size)
+				trim_top(r, first_non_wb_addr);
+		}
 
 		if (is_available_memory(md)) {
 			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
@@ -540,23 +629,22 @@
 			       efi_desc_size, ia64_boot_param->efi_memdesc_version,
 			       ia64_boot_param->efi_memmap);
 	if (status != EFI_SUCCESS) {
-		printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status);
+		printk("Warning: unable to switch EFI into virtual mode (status=0x%lx)\n", status);
 		return;
 	}
 
 	/*
-	 * Now that EFI is in virtual mode, we arrange for EFI functions to be
-	 * called directly:
+	 * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
 	 */
-	efi.get_time = __va(runtime->get_time);
-	efi.set_time = __va(runtime->set_time);
-	efi.get_wakeup_time = __va(runtime->get_wakeup_time);
-	efi.set_wakeup_time = __va(runtime->set_wakeup_time);
-	efi.get_variable = __va(runtime->get_variable);
-	efi.get_next_variable = __va(runtime->get_next_variable);
-	efi.set_variable = __va(runtime->set_variable);
-	efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count);
-	efi.reset_system = __va(runtime->reset_system);
+	efi.get_time = virt_get_time;
+	efi.set_time = virt_set_time;
+	efi.get_wakeup_time = virt_get_wakeup_time;
+	efi.set_wakeup_time = virt_set_wakeup_time;
+	efi.get_variable = virt_get_variable;
+	efi.get_next_variable = virt_get_next_variable;
+	efi.set_variable = virt_set_variable;
+	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
+	efi.reset_system = virt_reset_system;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/entry.S linux-2.4.21-rc3/arch/ia64/kernel/entry.S
--- linux-2.4.20/arch/ia64/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/entry.S	2003-05-22 22:06:39.000000000 +0000
@@ -1109,7 +1109,7 @@
 	data8 sys_mlock
 	data8 sys_mlockall
 	data8 sys_mprotect			// 1155
-	data8 sys_mremap
+	data8 ia64_mremap
 	data8 sys_msync
 	data8 sys_munlock
 	data8 sys_munlockall
@@ -1170,18 +1170,18 @@
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
 	data8 sys_readahead
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1220
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1225
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_setxattr
+	data8 sys_lsetxattr
+	data8 sys_fsetxattr
+	data8 sys_getxattr			// 1220
+	data8 sys_lgetxattr
+	data8 sys_fgetxattr
+	data8 sys_listxattr
+	data8 sys_llistxattr
+	data8 sys_flistxattr			// 1225
+	data8 sys_removexattr
+	data8 sys_lremovexattr
+	data8 sys_fremovexattr
 	data8 sys_tkill
 	data8 ia64_ni_syscall			// 1230
 	data8 ia64_ni_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/fw-emu.c linux-2.4.21-rc3/arch/ia64/kernel/fw-emu.c
--- linux-2.4.20/arch/ia64/kernel/fw-emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/fw-emu.c	2003-05-22 22:06:25.000000000 +0000
@@ -2,7 +2,7 @@
  * PAL & SAL emulation.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * For the HP simulator, this file gets include in boot/bootloader.c.
  * For SoftSDV, this file gets included in sys_softsdv.c.
@@ -19,10 +19,14 @@
 #include <asm/sal.h>
 
 #define MB	(1024*1024UL)
-#define GB	(1024*MB)
-#define TB	(1024*GB)
 
-#define NUM_MEM_DESCS	4
+#define SIMPLE_MEMMAP	1
+
+#if SIMPLE_MEMMAP
+# define NUM_MEM_DESCS	4
+#else
+# define NUM_MEM_DESCS	16
+#endif
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -381,6 +385,17 @@
 	struct ia64_boot_param *bp;
 	unsigned char checksum = 0;
 	char *cp, *cmd_line;
+	int i = 0;
+#	define MAKE_MD(typ, attr, start, end)		\
+	do {						\
+		md = efi_memmap + i++;			\
+		md->type = typ;				\
+		md->pad = 0;				\
+		md->phys_addr = start;			\
+		md->virt_addr = 0;			\
+		md->num_pages = (end - start) >> 12;	\
+		md->attribute = attr;			\
+	} while (0)
 
 	memset(fw_mem, 0, sizeof(fw_mem));
 
@@ -466,41 +481,30 @@
 
 	sal_systab->checksum = -checksum;
 
+#if SIMPLE_MEMMAP
 	/* simulate free memory at physical address zero */
-	md = &efi_memmap[0];
-	md->type = EFI_BOOT_SERVICES_DATA;
-	md->pad = 0;
-	md->phys_addr = 0*MB;
-	md->virt_addr = 0;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* fill in a memory descriptor: */
-	md = &efi_memmap[1];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 2*MB;
-	md->virt_addr = 0;
-	md->num_pages = (128*MB) >> 12;	/* 128MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
-
-	/* descriptor for firmware emulator: */
-	md = &efi_memmap[2];
-	md->type = EFI_PAL_CODE;
-	md->pad = 0;
-	md->phys_addr = 1*MB;
-	md->virt_addr = 1*MB;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* descriptor for high memory (>4TB): */
-	md = &efi_memmap[3];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 4*TB;
-	md->virt_addr = 0;
-	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
+	MAKE_MD(EFI_BOOT_SERVICES_DATA,		EFI_MEMORY_WB,    0*MB,    1*MB);
+	MAKE_MD(EFI_PAL_CODE,			EFI_MEMORY_WB,    1*MB,    2*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB,    2*MB,  130*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB, 4096*MB, 4128*MB);
+#else
+	MAKE_MD( 4,		   0x9, 0x0000000000000000, 0x0000000000001000);
+	MAKE_MD( 7,		   0x9, 0x0000000000001000, 0x000000000008a000);
+	MAKE_MD( 4,		   0x9, 0x000000000008a000, 0x00000000000a0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000);
+	MAKE_MD( 7,		   0x9, 0x0000000000100000, 0x0000000004400000);
+	MAKE_MD( 2,		   0x9, 0x0000000004400000, 0x0000000004be5000);
+	MAKE_MD( 7,		   0x9, 0x0000000004be5000, 0x000000007f77e000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000);
+	MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000);
+	MAKE_MD( 7,		   0x9, 0x000000007fc3a000, 0x000000007fea0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000);
+	MAKE_MD( 7,		   0x9, 0x000000007fea8000, 0x000000007feab000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000);
+	MAKE_MD( 7,		   0x9, 0x00000000ff400000, 0x0000000104000000);
+#endif
 
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/gate.S linux-2.4.21-rc3/arch/ia64/kernel/gate.S
--- linux-2.4.20/arch/ia64/kernel/gate.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/gate.S	2003-05-22 22:06:39.000000000 +0000
@@ -2,7 +2,7 @@
  * This file contains the code that gets mapped at the upper end of each task's text
  * region.  For now, it contains the signal trampoline code only.
  *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2002 Hewlett-Packard Co
  * 	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -135,7 +135,7 @@
 	;;
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
-(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14 and r16)
+(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14-r18, f6 & f7)
 	;;
 back_from_restore_rbs:
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
@@ -189,20 +189,69 @@
 	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 	.body
 restore_rbs:
+	// On input:
+	//	r14 = bsp1 (bsp at the time of return from signal handler)
+	//	r15 = bsp0 (bsp at the time the signal occurred)
+	//
+	// Here, we need to calculate bspstore0, the value that ar.bspstore needs
+	// to be set to, based on bsp0 and the size of the dirty partition on
+	// the alternate stack (sc_loadrs >> 16).  This can be done with the
+	// following algorithm:
+	//
+	//  bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
+	//
+	// This is what the code below does.
+	//
 	alloc r2=ar.pfs,0,0,0,0			// alloc null frame
 	adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+	adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
-	ld8 r14=[r16]
-	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
+	ld8 r17=[r16]
+	ld8 r16=[r18]			// get new rnat
+	extr.u r18=r15,3,6	// r18 <- rse_slot_num(bsp0)
 	;;
-	mov ar.rsc=r14				// put RSE into enforced lazy mode
-	ld8 r14=[r16]				// get new rnat
+	mov ar.rsc=r17			// put RSE into enforced lazy mode
+	shr.u r17=r17,16
 	;;
-	loadrs					// restore dirty partition
+	sub r14=r14,r17		// r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
+	shr.u r17=r17,3		// r17 <- (sc_loadrs >> 19)
+	;;
+	loadrs			// restore dirty partition
+	extr.u r14=r14,3,6	// r14 <- rse_slot_num(bspstore1)
+	;;
+	add r14=r14,r17		// r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
+	;;
+	shr.u r14=r14,6		// r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
+	;;
+	sub r14=r14,r17		// r14 <- -rse_num_regs(bspstore1, bsp1)
+	movl r17=0x8208208208208209
+	;;
+	add r18=r18,r14		// r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
+	setf.sig f7=r17
+	cmp.lt p7,p0=r14,r0	// p7 <- (r14 < 0)?
+	;;
+(p7)	adds r18=-62,r18	// delta -= 62
+	;;
+	setf.sig f6=r18
+	;;
+	xmpy.h f6=f6,f7
+	;;
+	getf.sig r17=f6
+	;;
+	add r17=r17,r18
+	shr r18=r18,63
+	;;
+	shr r17=r17,5
+	;;
+	sub r17=r17,r18		// r17 = delta/63
+	;;
+	add r17=r14,r17		// r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
+	;;
+	shladd r15=r17,3,r15	// r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
 	;;
 	mov ar.bspstore=r15			// switch back to old register backing store area
 	;;
-	mov ar.rnat=r14				// restore RNaT
+	mov ar.rnat=r16				// restore RNaT
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
 	br.cond.sptk back_from_restore_rbs
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/head.S linux-2.4.21-rc3/arch/ia64/kernel/head.S
--- linux-2.4.20/arch/ia64/kernel/head.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/head.S	2003-05-22 22:06:50.000000000 +0000
@@ -13,6 +13,8 @@
  * Copyright (C) 1999 Intel Corp.
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
+ * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
+ *   -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
  */
 
 #include <linux/config.h>
@@ -262,302 +264,297 @@
 END(ia64_load_debug_regs)
 
 GLOBAL_ENTRY(__ia64_save_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
+	alloc r2=ar.pfs,1,4,0,0
+	adds loc0=96*16-16,in0
+	adds loc1=96*16-16-128,in0
 	;;
-	stf.spill.nta [in0]=f32,32
-	stf.spill.nta [ r3]=f33,32
+	stf.spill.nta [loc0]=f127,-256
+	stf.spill.nta [loc1]=f119,-256
 	;;
-	stf.spill.nta [in0]=f34,32
-	stf.spill.nta [ r3]=f35,32
+	stf.spill.nta [loc0]=f111,-256
+	stf.spill.nta [loc1]=f103,-256
 	;;
-	stf.spill.nta [in0]=f36,32
-	stf.spill.nta [ r3]=f37,32
+	stf.spill.nta [loc0]=f95,-256
+	stf.spill.nta [loc1]=f87,-256
 	;;
-	stf.spill.nta [in0]=f38,32
-	stf.spill.nta [ r3]=f39,32
+	stf.spill.nta [loc0]=f79,-256
+	stf.spill.nta [loc1]=f71,-256
 	;;
-	stf.spill.nta [in0]=f40,32
-	stf.spill.nta [ r3]=f41,32
+	stf.spill.nta [loc0]=f63,-256
+	stf.spill.nta [loc1]=f55,-256
+	adds loc2=96*16-32,in0
 	;;
-	stf.spill.nta [in0]=f42,32
-	stf.spill.nta [ r3]=f43,32
+	stf.spill.nta [loc0]=f47,-256
+	stf.spill.nta [loc1]=f39,-256
+	adds loc3=96*16-32-128,in0
 	;;
-	stf.spill.nta [in0]=f44,32
-	stf.spill.nta [ r3]=f45,32
+	stf.spill.nta [loc2]=f126,-256
+	stf.spill.nta [loc3]=f118,-256
 	;;
-	stf.spill.nta [in0]=f46,32
-	stf.spill.nta [ r3]=f47,32
+	stf.spill.nta [loc2]=f110,-256
+	stf.spill.nta [loc3]=f102,-256
 	;;
-	stf.spill.nta [in0]=f48,32
-	stf.spill.nta [ r3]=f49,32
+	stf.spill.nta [loc2]=f94,-256
+	stf.spill.nta [loc3]=f86,-256
 	;;
-	stf.spill.nta [in0]=f50,32
-	stf.spill.nta [ r3]=f51,32
+	stf.spill.nta [loc2]=f78,-256
+	stf.spill.nta [loc3]=f70,-256
 	;;
-	stf.spill.nta [in0]=f52,32
-	stf.spill.nta [ r3]=f53,32
+	stf.spill.nta [loc2]=f62,-256
+	stf.spill.nta [loc3]=f54,-256
+	adds loc0=96*16-48,in0
 	;;
-	stf.spill.nta [in0]=f54,32
-	stf.spill.nta [ r3]=f55,32
+	stf.spill.nta [loc2]=f46,-256
+	stf.spill.nta [loc3]=f38,-256
+	adds loc1=96*16-48-128,in0
 	;;
-	stf.spill.nta [in0]=f56,32
-	stf.spill.nta [ r3]=f57,32
+	stf.spill.nta [loc0]=f125,-256
+	stf.spill.nta [loc1]=f117,-256
 	;;
-	stf.spill.nta [in0]=f58,32
-	stf.spill.nta [ r3]=f59,32
+	stf.spill.nta [loc0]=f109,-256
+	stf.spill.nta [loc1]=f101,-256
 	;;
-	stf.spill.nta [in0]=f60,32
-	stf.spill.nta [ r3]=f61,32
+	stf.spill.nta [loc0]=f93,-256
+	stf.spill.nta [loc1]=f85,-256
 	;;
-	stf.spill.nta [in0]=f62,32
-	stf.spill.nta [ r3]=f63,32
+	stf.spill.nta [loc0]=f77,-256
+	stf.spill.nta [loc1]=f69,-256
 	;;
-	stf.spill.nta [in0]=f64,32
-	stf.spill.nta [ r3]=f65,32
+	stf.spill.nta [loc0]=f61,-256
+	stf.spill.nta [loc1]=f53,-256
+	adds loc2=96*16-64,in0
 	;;
-	stf.spill.nta [in0]=f66,32
-	stf.spill.nta [ r3]=f67,32
+	stf.spill.nta [loc0]=f45,-256
+	stf.spill.nta [loc1]=f37,-256
+	adds loc3=96*16-64-128,in0
 	;;
-	stf.spill.nta [in0]=f68,32
-	stf.spill.nta [ r3]=f69,32
+	stf.spill.nta [loc2]=f124,-256
+	stf.spill.nta [loc3]=f116,-256
 	;;
-	stf.spill.nta [in0]=f70,32
-	stf.spill.nta [ r3]=f71,32
+	stf.spill.nta [loc2]=f108,-256
+	stf.spill.nta [loc3]=f100,-256
 	;;
-	stf.spill.nta [in0]=f72,32
-	stf.spill.nta [ r3]=f73,32
+	stf.spill.nta [loc2]=f92,-256
+	stf.spill.nta [loc3]=f84,-256
 	;;
-	stf.spill.nta [in0]=f74,32
-	stf.spill.nta [ r3]=f75,32
+	stf.spill.nta [loc2]=f76,-256
+	stf.spill.nta [loc3]=f68,-256
 	;;
-	stf.spill.nta [in0]=f76,32
-	stf.spill.nta [ r3]=f77,32
+	stf.spill.nta [loc2]=f60,-256
+	stf.spill.nta [loc3]=f52,-256
+	adds loc0=96*16-80,in0
 	;;
-	stf.spill.nta [in0]=f78,32
-	stf.spill.nta [ r3]=f79,32
+	stf.spill.nta [loc2]=f44,-256
+	stf.spill.nta [loc3]=f36,-256
+	adds loc1=96*16-80-128,in0
 	;;
-	stf.spill.nta [in0]=f80,32
-	stf.spill.nta [ r3]=f81,32
+	stf.spill.nta [loc0]=f123,-256
+	stf.spill.nta [loc1]=f115,-256
 	;;
-	stf.spill.nta [in0]=f82,32
-	stf.spill.nta [ r3]=f83,32
+	stf.spill.nta [loc0]=f107,-256
+	stf.spill.nta [loc1]=f99,-256
 	;;
-	stf.spill.nta [in0]=f84,32
-	stf.spill.nta [ r3]=f85,32
+	stf.spill.nta [loc0]=f91,-256
+	stf.spill.nta [loc1]=f83,-256
 	;;
-	stf.spill.nta [in0]=f86,32
-	stf.spill.nta [ r3]=f87,32
+	stf.spill.nta [loc0]=f75,-256
+	stf.spill.nta [loc1]=f67,-256
 	;;
-	stf.spill.nta [in0]=f88,32
-	stf.spill.nta [ r3]=f89,32
+	stf.spill.nta [loc0]=f59,-256
+	stf.spill.nta [loc1]=f51,-256
+	adds loc2=96*16-96,in0
 	;;
-	stf.spill.nta [in0]=f90,32
-	stf.spill.nta [ r3]=f91,32
+	stf.spill.nta [loc0]=f43,-256
+	stf.spill.nta [loc1]=f35,-256
+	adds loc3=96*16-96-128,in0
 	;;
-	stf.spill.nta [in0]=f92,32
-	stf.spill.nta [ r3]=f93,32
+	stf.spill.nta [loc2]=f122,-256
+	stf.spill.nta [loc3]=f114,-256
 	;;
-	stf.spill.nta [in0]=f94,32
-	stf.spill.nta [ r3]=f95,32
+	stf.spill.nta [loc2]=f106,-256
+	stf.spill.nta [loc3]=f98,-256
 	;;
-	stf.spill.nta [in0]=f96,32
-	stf.spill.nta [ r3]=f97,32
+	stf.spill.nta [loc2]=f90,-256
+	stf.spill.nta [loc3]=f82,-256
 	;;
-	stf.spill.nta [in0]=f98,32
-	stf.spill.nta [ r3]=f99,32
+	stf.spill.nta [loc2]=f74,-256
+	stf.spill.nta [loc3]=f66,-256
 	;;
-	stf.spill.nta [in0]=f100,32
-	stf.spill.nta [ r3]=f101,32
+	stf.spill.nta [loc2]=f58,-256
+	stf.spill.nta [loc3]=f50,-256
+	adds loc0=96*16-112,in0
 	;;
-	stf.spill.nta [in0]=f102,32
-	stf.spill.nta [ r3]=f103,32
+	stf.spill.nta [loc2]=f42,-256
+	stf.spill.nta [loc3]=f34,-256
+	adds loc1=96*16-112-128,in0
 	;;
-	stf.spill.nta [in0]=f104,32
-	stf.spill.nta [ r3]=f105,32
+	stf.spill.nta [loc0]=f121,-256
+	stf.spill.nta [loc1]=f113,-256
 	;;
-	stf.spill.nta [in0]=f106,32
-	stf.spill.nta [ r3]=f107,32
+	stf.spill.nta [loc0]=f105,-256
+	stf.spill.nta [loc1]=f97,-256
 	;;
-	stf.spill.nta [in0]=f108,32
-	stf.spill.nta [ r3]=f109,32
+	stf.spill.nta [loc0]=f89,-256
+	stf.spill.nta [loc1]=f81,-256
 	;;
-	stf.spill.nta [in0]=f110,32
-	stf.spill.nta [ r3]=f111,32
+	stf.spill.nta [loc0]=f73,-256
+	stf.spill.nta [loc1]=f65,-256
 	;;
-	stf.spill.nta [in0]=f112,32
-	stf.spill.nta [ r3]=f113,32
+	stf.spill.nta [loc0]=f57,-256
+	stf.spill.nta [loc1]=f49,-256
+	adds loc2=96*16-128,in0
 	;;
-	stf.spill.nta [in0]=f114,32
-	stf.spill.nta [ r3]=f115,32
+	stf.spill.nta [loc0]=f41,-256
+	stf.spill.nta [loc1]=f33,-256
+	adds loc3=96*16-128-128,in0
 	;;
-	stf.spill.nta [in0]=f116,32
-	stf.spill.nta [ r3]=f117,32
+	stf.spill.nta [loc2]=f120,-256
+	stf.spill.nta [loc3]=f112,-256
 	;;
-	stf.spill.nta [in0]=f118,32
-	stf.spill.nta [ r3]=f119,32
+	stf.spill.nta [loc2]=f104,-256
+	stf.spill.nta [loc3]=f96,-256
 	;;
-	stf.spill.nta [in0]=f120,32
-	stf.spill.nta [ r3]=f121,32
+	stf.spill.nta [loc2]=f88,-256
+	stf.spill.nta [loc3]=f80,-256
 	;;
-	stf.spill.nta [in0]=f122,32
-	stf.spill.nta [ r3]=f123,32
+	stf.spill.nta [loc2]=f72,-256
+	stf.spill.nta [loc3]=f64,-256
 	;;
-	stf.spill.nta [in0]=f124,32
-	stf.spill.nta [ r3]=f125,32
+	stf.spill.nta [loc2]=f56,-256
+	stf.spill.nta [loc3]=f48,-256
 	;;
-	stf.spill.nta [in0]=f126,32
-	stf.spill.nta [ r3]=f127,32
+	stf.spill.nta [loc2]=f40
+	stf.spill.nta [loc3]=f32
 	br.ret.sptk.many rp
 END(__ia64_save_fpu)
 
 GLOBAL_ENTRY(__ia64_load_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
-	;;
-	ldf.fill.nta f32=[in0],32
-	ldf.fill.nta f33=[ r3],32
-	;;
-	ldf.fill.nta f34=[in0],32
-	ldf.fill.nta f35=[ r3],32
-	;;
-	ldf.fill.nta f36=[in0],32
-	ldf.fill.nta f37=[ r3],32
-	;;
-	ldf.fill.nta f38=[in0],32
-	ldf.fill.nta f39=[ r3],32
-	;;
-	ldf.fill.nta f40=[in0],32
-	ldf.fill.nta f41=[ r3],32
-	;;
-	ldf.fill.nta f42=[in0],32
-	ldf.fill.nta f43=[ r3],32
-	;;
-	ldf.fill.nta f44=[in0],32
-	ldf.fill.nta f45=[ r3],32
-	;;
-	ldf.fill.nta f46=[in0],32
-	ldf.fill.nta f47=[ r3],32
-	;;
-	ldf.fill.nta f48=[in0],32
-	ldf.fill.nta f49=[ r3],32
-	;;
-	ldf.fill.nta f50=[in0],32
-	ldf.fill.nta f51=[ r3],32
-	;;
-	ldf.fill.nta f52=[in0],32
-	ldf.fill.nta f53=[ r3],32
-	;;
-	ldf.fill.nta f54=[in0],32
-	ldf.fill.nta f55=[ r3],32
-	;;
-	ldf.fill.nta f56=[in0],32
-	ldf.fill.nta f57=[ r3],32
-	;;
-	ldf.fill.nta f58=[in0],32
-	ldf.fill.nta f59=[ r3],32
-	;;
-	ldf.fill.nta f60=[in0],32
-	ldf.fill.nta f61=[ r3],32
-	;;
-	ldf.fill.nta f62=[in0],32
-	ldf.fill.nta f63=[ r3],32
-	;;
-	ldf.fill.nta f64=[in0],32
-	ldf.fill.nta f65=[ r3],32
-	;;
-	ldf.fill.nta f66=[in0],32
-	ldf.fill.nta f67=[ r3],32
-	;;
-	ldf.fill.nta f68=[in0],32
-	ldf.fill.nta f69=[ r3],32
-	;;
-	ldf.fill.nta f70=[in0],32
-	ldf.fill.nta f71=[ r3],32
-	;;
-	ldf.fill.nta f72=[in0],32
-	ldf.fill.nta f73=[ r3],32
-	;;
-	ldf.fill.nta f74=[in0],32
-	ldf.fill.nta f75=[ r3],32
-	;;
-	ldf.fill.nta f76=[in0],32
-	ldf.fill.nta f77=[ r3],32
-	;;
-	ldf.fill.nta f78=[in0],32
-	ldf.fill.nta f79=[ r3],32
-	;;
-	ldf.fill.nta f80=[in0],32
-	ldf.fill.nta f81=[ r3],32
-	;;
-	ldf.fill.nta f82=[in0],32
-	ldf.fill.nta f83=[ r3],32
-	;;
-	ldf.fill.nta f84=[in0],32
-	ldf.fill.nta f85=[ r3],32
-	;;
-	ldf.fill.nta f86=[in0],32
-	ldf.fill.nta f87=[ r3],32
-	;;
-	ldf.fill.nta f88=[in0],32
-	ldf.fill.nta f89=[ r3],32
-	;;
-	ldf.fill.nta f90=[in0],32
-	ldf.fill.nta f91=[ r3],32
-	;;
-	ldf.fill.nta f92=[in0],32
-	ldf.fill.nta f93=[ r3],32
-	;;
-	ldf.fill.nta f94=[in0],32
-	ldf.fill.nta f95=[ r3],32
-	;;
-	ldf.fill.nta f96=[in0],32
-	ldf.fill.nta f97=[ r3],32
-	;;
-	ldf.fill.nta f98=[in0],32
-	ldf.fill.nta f99=[ r3],32
-	;;
-	ldf.fill.nta f100=[in0],32
-	ldf.fill.nta f101=[ r3],32
-	;;
-	ldf.fill.nta f102=[in0],32
-	ldf.fill.nta f103=[ r3],32
-	;;
-	ldf.fill.nta f104=[in0],32
-	ldf.fill.nta f105=[ r3],32
-	;;
-	ldf.fill.nta f106=[in0],32
-	ldf.fill.nta f107=[ r3],32
-	;;
-	ldf.fill.nta f108=[in0],32
-	ldf.fill.nta f109=[ r3],32
-	;;
-	ldf.fill.nta f110=[in0],32
-	ldf.fill.nta f111=[ r3],32
-	;;
-	ldf.fill.nta f112=[in0],32
-	ldf.fill.nta f113=[ r3],32
-	;;
-	ldf.fill.nta f114=[in0],32
-	ldf.fill.nta f115=[ r3],32
-	;;
-	ldf.fill.nta f116=[in0],32
-	ldf.fill.nta f117=[ r3],32
-	;;
-	ldf.fill.nta f118=[in0],32
-	ldf.fill.nta f119=[ r3],32
-	;;
-	ldf.fill.nta f120=[in0],32
-	ldf.fill.nta f121=[ r3],32
-	;;
-	ldf.fill.nta f122=[in0],32
-	ldf.fill.nta f123=[ r3],32
-	;;
-	ldf.fill.nta f124=[in0],32
-	ldf.fill.nta f125=[ r3],32
-	;;
-	ldf.fill.nta f126=[in0],32
-	ldf.fill.nta f127=[ r3],32
+	alloc r2=ar.pfs,1,2,0,0
+	adds r3=128,in0
+	adds r14=256,in0
+	adds r15=384,in0
+	mov loc0=512
+	mov loc1=-1024+16
+	;;
+	ldf.fill.nta f32=[in0],loc0
+	ldf.fill.nta f40=[ r3],loc0
+	ldf.fill.nta f48=[r14],loc0
+	ldf.fill.nta f56=[r15],loc0
+	;;
+	ldf.fill.nta f64=[in0],loc0
+	ldf.fill.nta f72=[ r3],loc0
+	ldf.fill.nta f80=[r14],loc0
+	ldf.fill.nta f88=[r15],loc0
+	;;
+	ldf.fill.nta f96=[in0],loc1
+	ldf.fill.nta f104=[ r3],loc1
+	ldf.fill.nta f112=[r14],loc1
+	ldf.fill.nta f120=[r15],loc1
+	;;
+	ldf.fill.nta f33=[in0],loc0
+	ldf.fill.nta f41=[ r3],loc0
+	ldf.fill.nta f49=[r14],loc0
+	ldf.fill.nta f57=[r15],loc0
+	;;
+	ldf.fill.nta f65=[in0],loc0
+	ldf.fill.nta f73=[ r3],loc0
+	ldf.fill.nta f81=[r14],loc0
+	ldf.fill.nta f89=[r15],loc0
+	;;
+	ldf.fill.nta f97=[in0],loc1
+	ldf.fill.nta f105=[ r3],loc1
+	ldf.fill.nta f113=[r14],loc1
+	ldf.fill.nta f121=[r15],loc1
+	;;
+	ldf.fill.nta f34=[in0],loc0
+	ldf.fill.nta f42=[ r3],loc0
+	ldf.fill.nta f50=[r14],loc0
+	ldf.fill.nta f58=[r15],loc0
+	;;
+	ldf.fill.nta f66=[in0],loc0
+	ldf.fill.nta f74=[ r3],loc0
+	ldf.fill.nta f82=[r14],loc0
+	ldf.fill.nta f90=[r15],loc0
+	;;
+	ldf.fill.nta f98=[in0],loc1
+	ldf.fill.nta f106=[ r3],loc1
+	ldf.fill.nta f114=[r14],loc1
+	ldf.fill.nta f122=[r15],loc1
+	;;
+	ldf.fill.nta f35=[in0],loc0
+	ldf.fill.nta f43=[ r3],loc0
+	ldf.fill.nta f51=[r14],loc0
+	ldf.fill.nta f59=[r15],loc0
+	;;
+	ldf.fill.nta f67=[in0],loc0
+	ldf.fill.nta f75=[ r3],loc0
+	ldf.fill.nta f83=[r14],loc0
+	ldf.fill.nta f91=[r15],loc0
+	;;
+	ldf.fill.nta f99=[in0],loc1
+	ldf.fill.nta f107=[ r3],loc1
+	ldf.fill.nta f115=[r14],loc1
+	ldf.fill.nta f123=[r15],loc1
+	;;
+	ldf.fill.nta f36=[in0],loc0
+	ldf.fill.nta f44=[ r3],loc0
+	ldf.fill.nta f52=[r14],loc0
+	ldf.fill.nta f60=[r15],loc0
+	;;
+	ldf.fill.nta f68=[in0],loc0
+	ldf.fill.nta f76=[ r3],loc0
+	ldf.fill.nta f84=[r14],loc0
+	ldf.fill.nta f92=[r15],loc0
+	;;
+	ldf.fill.nta f100=[in0],loc1
+	ldf.fill.nta f108=[ r3],loc1
+	ldf.fill.nta f116=[r14],loc1
+	ldf.fill.nta f124=[r15],loc1
+	;;
+	ldf.fill.nta f37=[in0],loc0
+	ldf.fill.nta f45=[ r3],loc0
+	ldf.fill.nta f53=[r14],loc0
+	ldf.fill.nta f61=[r15],loc0
+	;;
+	ldf.fill.nta f69=[in0],loc0
+	ldf.fill.nta f77=[ r3],loc0
+	ldf.fill.nta f85=[r14],loc0
+	ldf.fill.nta f93=[r15],loc0
+	;;
+	ldf.fill.nta f101=[in0],loc1
+	ldf.fill.nta f109=[ r3],loc1
+	ldf.fill.nta f117=[r14],loc1
+	ldf.fill.nta f125=[r15],loc1
+	;;
+	ldf.fill.nta f38 =[in0],loc0
+	ldf.fill.nta f46 =[ r3],loc0
+	ldf.fill.nta f54 =[r14],loc0
+	ldf.fill.nta f62 =[r15],loc0
+	;;
+	ldf.fill.nta f70 =[in0],loc0
+	ldf.fill.nta f78 =[ r3],loc0
+	ldf.fill.nta f86 =[r14],loc0
+	ldf.fill.nta f94 =[r15],loc0
+	;;
+	ldf.fill.nta f102=[in0],loc1
+	ldf.fill.nta f110=[ r3],loc1
+	ldf.fill.nta f118=[r14],loc1
+	ldf.fill.nta f126=[r15],loc1
+	;;
+	ldf.fill.nta f39 =[in0],loc0
+	ldf.fill.nta f47 =[ r3],loc0
+	ldf.fill.nta f55 =[r14],loc0
+	ldf.fill.nta f63 =[r15],loc0
+	;;
+	ldf.fill.nta f71 =[in0],loc0
+	ldf.fill.nta f79 =[ r3],loc0
+	ldf.fill.nta f87 =[r14],loc0
+	ldf.fill.nta f95 =[r15],loc0
+	;;
+	ldf.fill.nta f103=[in0]
+	ldf.fill.nta f111=[ r3]
+	ldf.fill.nta f119=[r14]
+	ldf.fill.nta f127=[r15]
 	br.ret.sptk.many rp
 END(__ia64_load_fpu)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c linux-2.4.21-rc3/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/ia64_ksyms.c	2003-05-22 22:06:43.000000000 +0000
@@ -57,6 +57,10 @@
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
+#include <asm/pgtable.h>
+EXPORT_SYMBOL(vmalloc_end);
+EXPORT_SYMBOL(ia64_page_valid);
+
 #include <asm/processor.h>
 # ifndef CONFIG_NUMA
 EXPORT_SYMBOL(_cpu_data);
@@ -100,7 +104,7 @@
 
 #else /* !CONFIG_SMP */
 
-EXPORT_SYMBOL(__flush_tlb_all);
+EXPORT_SYMBOL(local_flush_tlb_all);
 
 #endif /* !CONFIG_SMP */
 
@@ -141,6 +145,8 @@
 EXPORT_SYMBOL(ia64_pal_call_phys_static);
 EXPORT_SYMBOL(ia64_pal_call_stacked);
 EXPORT_SYMBOL(ia64_pal_call_static);
+EXPORT_SYMBOL(ia64_load_scratch_fpregs);
+EXPORT_SYMBOL(ia64_save_scratch_fpregs);
 
 extern struct efi efi;
 EXPORT_SYMBOL(efi);
@@ -154,4 +160,8 @@
 EXPORT_SYMBOL(ia64_mv);
 #endif
 EXPORT_SYMBOL(machvec_noop);
-
+#ifdef CONFIG_PERFMON
+#include <asm/perfmon.h>
+EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem);
+EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/iosapic.c linux-2.4.21-rc3/arch/ia64/kernel/iosapic.c
--- linux-2.4.20/arch/ia64/kernel/iosapic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/iosapic.c	2003-05-22 22:06:43.000000000 +0000
@@ -590,7 +590,7 @@
 		      gsi_base, addr);
 
 	DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, global_vector,
+	    isa_irq, gsi,
 	    polarity ? "high" : "low", edge_triggered ? "edge" : "level",
 	    dest, vector);
 
@@ -661,7 +661,7 @@
 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
 			      0, 0, gsi_base, addr);
 
-		DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
+		DBG("PCI: (%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
 		    segment, bus, slot, 'A' + pci_pin, gsi, vector);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq.c linux-2.4.21-rc3/arch/ia64/kernel/irq.c
--- linux-2.4.20/arch/ia64/kernel/irq.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/irq.c	2003-05-22 22:06:40.000000000 +0000
@@ -1060,7 +1060,7 @@
 
 	if (!shared) {
 		desc->depth = 0;
-		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
 		desc->handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq_ia64.c linux-2.4.21-rc3/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.20/arch/ia64/kernel/irq_ia64.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/irq_ia64.c	2003-05-22 22:06:41.000000000 +0000
@@ -178,7 +178,7 @@
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 	platform_irq_init();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/machvec.c linux-2.4.21-rc3/arch/ia64/kernel/machvec.c
--- linux-2.4.20/arch/ia64/kernel/machvec.c	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/machvec.c	2003-05-22 22:06:46.000000000 +0000
@@ -15,7 +15,7 @@
  * into a memory map index.
  */
 unsigned long
-map_nr_dense (unsigned long addr)
+map_nr_dense (void *addr)
 {
 	return MAP_NR_DENSE(addr);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/mca.c linux-2.4.21-rc3/arch/ia64/kernel/mca.c
--- linux-2.4.20/arch/ia64/kernel/mca.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/mca.c	2003-05-22 22:06:43.000000000 +0000
@@ -42,6 +42,9 @@
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -69,10 +72,10 @@
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 u64				ia64_mca_sal_data_area[1356];
-u64				ia64_mca_min_state_save_info;
 u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
-
+/* TODO: need to assign min-state structure to UC memory */
+u64				ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -105,6 +108,11 @@
 	name:       "cpe_hndlr"
 };
 
+#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
+#define MIN_CPE_POLL_INTERVAL (2*60*HZ)  /* 2 minutes */
+
+static struct timer_list cpe_poll_timer;
+
 /*
  *  ia64_mca_log_sal_error_record
  *
@@ -116,7 +124,7 @@
  *  Outputs :   platform error status
  */
 int
-ia64_mca_log_sal_error_record(int sal_info_type)
+ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
 {
 	int platform_err = 0;
 
@@ -131,7 +139,10 @@
 	 */
 
 	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
-	ia64_sal_clear_state_info(sal_info_type);
+	/* temporary: only clear SAL logs on hardware-corrected errors
+		or if we're logging an error after an MCA-initiated reboot */
+	if ((sal_info_type > 1) || (called_from_init))
+		ia64_sal_clear_state_info(sal_info_type);
 
 	return platform_err;
 }
@@ -152,7 +163,7 @@
 	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
 }
 
 /*
@@ -205,7 +216,7 @@
 	/*
 	 *  If there is an MCA error record pending, get it and log it.
 	 */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
 }
 
 /*
@@ -257,15 +268,23 @@
  *
  */
 void
-ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
+ia64_process_min_state_save (pal_min_state_area_t *pmss)
 {
-	int i, max=57;
-	u64 *tpmss_ptr=(u64 *)pmss;
+	int i, max = MIN_STATE_AREA_SIZE;
+	u64 *tpmss_ptr = (u64 *)pmss;
+	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
 
 	/* dump out the min_state_area information */
 
 	for (i=0;i<max;i++) {
 
+		/* copy min-state register info for eventual return to PAL */
+		*return_min_state_ptr++ = *tpmss_ptr;
+
+#if 1
+		tpmss_ptr++;  /* skip to next entry */
+#else
+		/* the printing part */
 		if(!ia64_pmss_dump_bank0) {
 			if(strncmp("B0",min_state_labels[i],2)==0) {
 				tpmss_ptr++;  /* skip to next entry */
@@ -278,6 +297,7 @@
 		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
 				     && !ia64_pmss_dump_bank0))
 			printk("\n");
+#endif
 	}
 }
 
@@ -510,8 +530,7 @@
 					setup_irq(irq, &mca_cpe_irqaction);
 				}
 			ia64_mca_register_cpev(cpev);
-		} else
-			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+		}
 	}
 
 	/* Initialize the areas set aside by the OS to buffer the
@@ -523,19 +542,17 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC);
 	ia64_log_init(SAL_INFO_TYPE_CPE);
 
-	/* Zero the min state save info */
-	ia64_mca_min_state_save_info = 0;
-
 #if defined(MCA_TEST)
 	mca_test();
 #endif /* #if defined(MCA_TEST) */
 
 	printk("Mca related initialization done\n");
 
-#if 0   // Too early in initialization -- error log is lost
+	/* commented out because this is done elsewhere */
+#if 0
 	/* Do post-failure MCA error logging */
 	ia64_mca_check_errors();
-#endif  // Too early in initialization -- error log is lost
+#endif
 }
 
 /*
@@ -701,8 +718,8 @@
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
 
 	/* Register pointer to new min state values */
-	/* NOTE: need to do something with this during recovery phase */
-	ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info;
+	ia64_os_to_sal_handoff_state.imots_new_min_state =
+		(pal_min_state_area_t *)ia64_mca_min_state_save_info;
 }
 
 /*
@@ -727,7 +744,7 @@
 	int platform_err = 0;
 
 	/* Get the MCA error record and log it */
-	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
 
 	/*
 	 *  Do Platform-specific mca error handling if required.
@@ -767,7 +784,7 @@
 		       cmc_irq, smp_processor_id());
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
 }
 
 /*
@@ -803,6 +820,62 @@
 #define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
 
 /*
+ *  ia64_mca_cpe_poll
+ *
+ *	Poll for Corrected Platform Errors (CPEs), dynamically adjust
+ *	polling interval based on occurance of an event.
+ *
+ * Inputs   :   dummy(unused)
+ * Outputs  :   None
+ *
+ */
+static void
+ia64_mca_cpe_poll (unsigned long dummy)
+{
+	int start_index;
+	static int poll_time = MAX_CPE_POLL_INTERVAL;
+
+	start_index = IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE);
+
+	/* Call the interrupt handler */
+	ia64_mca_cpe_int_handler(0, NULL, NULL);
+
+	/*
+	 * If a log was recorded, increase our polling frequency,
+	 * otherwise, backoff.
+	 */
+	if (start_index != IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE)) {
+		poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time/2);
+	} else {
+		poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2);
+	}
+	mod_timer(&cpe_poll_timer, jiffies + poll_time);
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ *	Opportunity to setup things that require initialization later
+ *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *	platform doesn't support an interrupt driven mechanism.
+ *
+ *  Inputs  :   None
+ *  Outputs :   Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0) {
+		init_timer(&cpe_poll_timer);
+		cpe_poll_timer.function = ia64_mca_cpe_poll;
+		ia64_mca_cpe_poll(0);
+	}
+	return 0;
+}
+
+module_init(ia64_mca_late_init);
+
+/*
  * C portion of the OS INIT handler
  *
  * Called from ia64_monarch_init_handler
@@ -837,8 +910,7 @@
 	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
 	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
-				    regs);
+	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area);
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
@@ -962,7 +1034,6 @@
 		return total_len;
 	} else {
 		IA64_LOG_UNLOCK(sal_info_type);
-		prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
 		return 0;
 	}
 }
@@ -1004,28 +1075,13 @@
 void
 ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
 {
-	char str_buf[32];
-
-	sprintf(str_buf, "%2d.%02d",
-		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
-		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
-	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
-	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
-		(lh->timestamp.slh_month >> 4) * 10 +
-		(lh->timestamp.slh_month & 0xf),
-		(lh->timestamp.slh_day >> 4) * 10 +
-		(lh->timestamp.slh_day & 0xf),
-		(lh->timestamp.slh_century >> 4) * 1000 +
-		(lh->timestamp.slh_century & 0xf) * 100 +
-		(lh->timestamp.slh_year >> 4) * 10 +
-		(lh->timestamp.slh_year & 0xf),
-		(lh->timestamp.slh_hour >> 4) * 10 +
-		(lh->timestamp.slh_hour & 0xf),
-		(lh->timestamp.slh_minute >> 4) * 10 +
-		(lh->timestamp.slh_minute & 0xf),
-		(lh->timestamp.slh_second >> 4) * 10 +
-		(lh->timestamp.slh_second & 0xf));
-	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
+	prfunc("+Err Record ID: %d    SAL Rev: %2x.%02x\n", lh->id,
+		lh->revision.major, lh->revision.minor);
+	prfunc("+Time: %02x/%02x/%02x%02x %02d:%02d:%02d    Severity %d\n",
+		lh->timestamp.slh_month, lh->timestamp.slh_day,
+		lh->timestamp.slh_century, lh->timestamp.slh_year,
+		lh->timestamp.slh_hour, lh->timestamp.slh_minute,
+		lh->timestamp.slh_second, lh->severity);
 }
 
 /*
@@ -1684,6 +1740,9 @@
 	if (slpi->valid.psi_static_struct) {
 		spsi = (sal_processor_static_info_t *)p_data;
 
+		/* copy interrupted context PAL min-state info */
+		ia64_process_min_state_save(&spsi->min_state_area);
+
 		/* Print branch register contents if valid */
 		if (spsi->valid.br)
 			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pal.S linux-2.4.21-rc3/arch/ia64/kernel/pal.S
--- linux-2.4.20/arch/ia64/kernel/pal.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/pal.S	2003-05-22 22:06:53.000000000 +0000
@@ -245,3 +245,49 @@
 	br.ret.sptk.many b0
 END(ia64_pal_call_phys_stacked)
 
+/*
+ * Save scratch fp scratch regs (fp10-fp15)
+ *
+ * NOTE: We need to do this since firmware (SAL or PAL) uses more
+ * scratch fp regs than the Linux kernel does.
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_save_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	stf.spill [in0] = f10,32
+	stf.spill [r2]  = f11,32
+	;;
+	stf.spill [in0] = f12,32
+	stf.spill [r2]  = f13,32
+	;;
+	stf.spill [in0] = f14,32
+	stf.spill [r2]  = f15,32
+	br.ret.sptk.many rp
+END(ia64_save_scratch_fpregs)
+
+/*
+ * Load scratch fp scratch regs (fp10-fp15)
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_load_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	ldf.fill  f10 = [in0],32
+	ldf.fill  f11 = [r2],32
+	;;
+	ldf.fill  f12 = [in0],32
+	ldf.fill  f13 = [r2],32
+	;;
+	ldf.fill  f14 = [in0],32
+	ldf.fill  f15 = [r2],32
+	br.ret.sptk.many rp
+END(ia64_load_scratch_fpregs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pci.c linux-2.4.21-rc3/arch/ia64/kernel/pci.c
--- linux-2.4.20/arch/ia64/kernel/pci.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/pci.c	2003-05-22 22:06:42.000000000 +0000
@@ -43,6 +43,8 @@
 extern void ia64_mca_check_errors( void );
 #endif
 
+static unsigned int acpi_root_bridges;
+
 struct pci_fixup pcibios_fixups[1];
 
 struct pci_ops *pci_root_ops;
@@ -167,7 +169,7 @@
  */
 
 static struct pci_controller *
-alloc_pci_controller(int seg)
+alloc_pci_controller (int seg)
 {
 	struct pci_controller *controller;
 
@@ -181,7 +183,7 @@
 }
 
 static struct pci_bus *
-scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
+scan_root_bus (int bus, struct pci_ops *ops, void *sysdata)
 {
 	struct pci_bus *b;
 
@@ -211,24 +213,152 @@
 	return b;
 }
 
+static void
+alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags)
+{
+	struct resource *res;
+
+	res = kmalloc(sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return;
+
+	memset(res, 0, sizeof(*res));
+	res->name = name;
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+
+	request_resource(root, res);
+}
+
+static u64
+add_io_space (acpi_resource_address64 *addr)
+{
+	u64 offset;
+	int sparse = 0;
+	int i;
+
+	if (addr->address_translation_offset == 0)
+		return IO_SPACE_BASE(0);	/* part of legacy IO space */
+
+	if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
+		sparse = 1;
+
+	offset = (u64) ioremap(addr->address_translation_offset, 0);
+	for (i = 0; i < num_io_spaces; i++)
+		if (io_space[i].mmio_base == offset &&
+		    io_space[i].sparse == sparse)
+			return IO_SPACE_BASE(i);
+
+	if (num_io_spaces == MAX_IO_SPACES) {
+		printk("Too many IO port spaces\n");
+		return ~0;
+	}
+
+	i = num_io_spaces++;
+	io_space[i].mmio_base = offset;
+	io_space[i].sparse = sparse;
+
+	return IO_SPACE_BASE(i);
+}
+
+static acpi_status
+count_window (acpi_resource *resource, void *data)
+{
+	unsigned int *windows = (unsigned int *) data;
+	acpi_resource_address64 addr;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(resource, &addr);
+	if (ACPI_SUCCESS(status))
+		if (addr.resource_type == ACPI_MEMORY_RANGE ||
+		    addr.resource_type == ACPI_IO_RANGE)
+			(*windows)++;
+
+	return AE_OK;
+}
+
+struct pci_root_info {
+	struct pci_controller *controller;
+	char *name;
+};
+
+static acpi_status
+add_window (acpi_resource *res, void *data)
+{
+	struct pci_root_info *info = (struct pci_root_info *) data;
+	struct pci_window *window;
+	acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags, offset = 0;
+	struct resource *root;
+
+	status = acpi_resource_to_address64(res, &addr);
+	if (ACPI_SUCCESS(status)) {
+		if (addr.resource_type == ACPI_MEMORY_RANGE) {
+			flags = IORESOURCE_MEM;
+			root = &iomem_resource;
+			offset = addr.address_translation_offset;
+		} else if (addr.resource_type == ACPI_IO_RANGE) {
+			flags = IORESOURCE_IO;
+			root = &ioport_resource;
+			offset = add_io_space(&addr);
+			if (offset == ~0)
+				return AE_OK;
+		} else
+			return AE_OK;
+
+		window = &info->controller->window[info->controller->windows++];
+		window->resource.flags |= flags;
+		window->resource.start  = addr.min_address_range;
+		window->resource.end    = addr.max_address_range;
+		window->offset		= offset;
+
+		alloc_resource(info->name, root, addr.min_address_range + offset,
+			addr.max_address_range + offset, flags);
+	}
+
+	return AE_OK;
+}
+
 struct pci_bus *
-pcibios_scan_root(void *handle, int seg, int bus)
+pcibios_scan_root (void *handle, int seg, int bus)
 {
+	struct pci_root_info info;
 	struct pci_controller *controller;
-	u64 base, size, offset;
+	unsigned int windows = 0;
+	char *name;
 
-	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+	acpi_root_bridges++;
 
 	controller = alloc_pci_controller(seg);
 	if (!controller)
-		return NULL;
+		goto out1;
 
 	controller->acpi_handle = handle;
 
-	acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
-	controller->mem_offset = offset;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, count_window, &windows);
+	controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL);
+	if (!controller->window)
+		goto out2;
+
+	name = kmalloc(16, GFP_KERNEL);
+	if (!name)
+		goto out3;
+
+	sprintf(name, "PCI Bus %02x:%02x", seg, bus);
+	info.controller = controller;
+	info.name = name;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info);
 
 	return scan_root_bus(bus, pci_root_ops, controller);
+
+out3:
+	kfree(controller->window);
+out2:
+	kfree(controller);
+out1:
+	return NULL;
 }
 
 void __init
@@ -249,7 +379,7 @@
 void __init
 pcibios_init (void)
 {
-#	define PCI_BUSES_TO_SCAN 255
+#	define PCI_BUSES_TO_SCAN 256
 	int i = 0;
 	struct pci_controller *controller;
 
@@ -261,43 +391,52 @@
 
 	platform_pci_fixup(0);	/* phase 0 fixups (before buses scanned) */
 
-	printk("PCI: Probing PCI hardware\n");
-	controller = alloc_pci_controller(0);
-	if (controller)
-		for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-			pci_scan_bus(i, pci_root_ops, controller);
+	/* Only probe blindly if ACPI didn't tell us about root bridges */
+	if (!acpi_root_bridges) {
+		printk("PCI: Probing PCI hardware\n");
+		controller = alloc_pci_controller(0);
+		if (controller)
+			for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+				pci_scan_bus(i, pci_root_ops, controller);
+	}
 
 	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
 
 	return;
 }
 
-static void __init
-pcibios_fixup_resource(struct resource *res, u64 offset)
-{
-	res->start += offset;
-	res->end += offset;
-}
-
 void __init
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus)
 {
-	int i;
+	struct pci_controller *controller = PCI_CONTROLLER(dev);
+	struct pci_window *window;
+	int i, j;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		if (!dev->resource[i].start)
 			continue;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			pcibios_fixup_resource(&dev->resource[i],
-				PCI_CONTROLLER(dev)->mem_offset);
+
+#define contains(win, res)	((res)->start >= (win)->start && \
+				 (res)->end   <= (win)->end)
+
+		for (j = 0; j < controller->windows; j++) {
+			window = &controller->window[j];
+			if (((dev->resource[i].flags & IORESOURCE_MEM &&
+			      window->resource.flags & IORESOURCE_MEM) ||
+			     (dev->resource[i].flags & IORESOURCE_IO &&
+			      window->resource.flags & IORESOURCE_IO)) &&
+			    contains(&window->resource, &dev->resource[i])) {
+				dev->resource[i].start += window->offset;
+				dev->resource[i].end   += window->offset;
+			}
+		}
 	}
 }
 
 /*
- *  Called after each bus is probed, but before its children
- *  are examined.
+ *  Called after each bus is probed, but before its children are examined.
  */
-void __init
+void __devinit
 pcibios_fixup_bus (struct pci_bus *b)
 {
 	struct list_head *ln;
@@ -306,7 +445,7 @@
 		pcibios_fixup_device_resources(pci_dev_b(ln), b);
 }
 
-void __init
+void __devinit
 pcibios_update_resource (struct pci_dev *dev, struct resource *root,
 			 struct resource *res, int resource)
 {
@@ -322,7 +461,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_update_irq (struct pci_dev *dev, int irq)
 {
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -330,7 +469,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
 	ranges->io_start -= bus->resource[0]->start;
@@ -339,8 +478,8 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-int
-pcibios_enable_device (struct pci_dev *dev)
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -349,11 +488,13 @@
 	if (!dev)
 		return -EINVAL;
 
- 	platform_pci_enable_device(dev);
-
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		/* Only set up the desired resources.  */
+		if (!(mask & (1 << idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR
@@ -372,6 +513,19 @@
 		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
+	return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+	int ret;
+
+	ret = pcibios_enable_resources(dev, mask);
+	if (ret < 0)
+		return ret;
+
+ 	platform_pci_enable_device(dev);
 
 	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon.c linux-2.4.21-rc3/arch/ia64/kernel/perfmon.c
--- linux-2.4.20/arch/ia64/kernel/perfmon.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/perfmon.c	2003-05-22 22:06:41.000000000 +0000
@@ -8,7 +8,7 @@
  * Modifications by Stephane Eranian, Hewlett-Packard Co.
  * Modifications by David Mosberger-Tang, Hewlett-Packard Co.
  *
- * Copyright (C) 1999-2002  Hewlett Packard Co
+ * Copyright (C) 1999-2003  Hewlett Packard Co
  *               Stephane Eranian <eranian@hpl.hp.com>
  *               David Mosberger-Tang <davidm@hpl.hp.com>
  */
@@ -28,7 +28,6 @@
 #include <asm/bitops.h>
 #include <asm/errno.h>
 #include <asm/page.h>
-#include <asm/pal.h>
 #include <asm/perfmon.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
@@ -56,27 +55,53 @@
 /*
  * Reset register flags
  */
-#define PFM_RELOAD_LONG_RESET	1
-#define PFM_RELOAD_SHORT_RESET	2
+#define PFM_PMD_LONG_RESET	1
+#define PFM_PMD_SHORT_RESET	2
 
 /*
  * Misc macros and definitions
  */
 #define PMU_FIRST_COUNTER	4
+#define PMU_MAX_PMCS		256
+#define PMU_MAX_PMDS		256
 
-#define PFM_IS_DISABLED() pmu_conf.pfm_is_disabled
+/*
+ * type of a PMU register (bitmask).
+ * bitmask structure:
+ * 	bit0   : register implemented
+ * 	bit1   : end marker 
+ * 	bit2-3 : reserved
+ * 	bit4-7 : register type
+ * 	bit8-31: reserved
+ */
+#define PFM_REG_IMPL		0x1 /* register implemented */
+#define PFM_REG_END		0x2 /* end marker */
+#define PFM_REG_MONITOR		(0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */
+#define PFM_REG_COUNTING	(0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+#define PFM_REG_CONTROL		(0x3<<4|PFM_REG_IMPL) /* PMU control register */
+#define	PFM_REG_CONFIG		(0x4<<4|PFM_REG_IMPL) /* refine configuration */
+#define PFM_REG_BUFFER	 	(0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */
+
+#define PMC_IS_LAST(i)	(pmu_conf.pmc_desc[i].type & PFM_REG_END)
+#define PMD_IS_LAST(i)	(pmu_conf.pmd_desc[i].type & PFM_REG_END)
+
+#define PFM_IS_DISABLED() pmu_conf.disabled
 
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
 /* i assume unsigned */
-#define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
-#define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
+#define PMC_IS_IMPL(i)	  (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL))
+#define PMD_IS_IMPL(i)	  (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL))
 
 /* XXX: these three assume that register i is implemented */
 #define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
 #define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
-#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_IS_MONITOR(i)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_DFL_VAL(i)     pmu_conf.pmc_desc[i].default_value
+#define PMC_RSVD_MASK(i)   pmu_conf.pmc_desc[i].reserved_mask
+#define PMD_PMD_DEP(i)	   pmu_conf.pmd_desc[i].dep_pmd[0]
+#define PMC_PMD_DEP(i)	   pmu_conf.pmc_desc[i].dep_pmd[0]
 
 /* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
@@ -106,6 +131,9 @@
 
 #define PFM_REG_RETFLAG_SET(flags, val)	do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)
 
+#define PFM_CPUINFO_CLEAR(v)	local_cpu_data->pfm_syst_info &= ~(v)
+#define PFM_CPUINFO_SET(v)	local_cpu_data->pfm_syst_info |= (v)
+
 #ifdef CONFIG_SMP
 #define cpu_is_online(i) (cpu_online_map & (1UL << i))
 #else
@@ -176,28 +204,17 @@
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
 /*
- * The possible type of a PMU register
- */
-typedef enum { 
-	PFM_REG_NOTIMPL, /* not implemented */
-	PFM_REG_NONE, 	 /* end marker */
-	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
-	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
-	PFM_REG_CONTROL, /* PMU control register */
-	PFM_REG_CONFIG,  /* refine configuration */
-	PFM_REG_BUFFER	 /* PMD used as buffer */
-} pfm_pmu_reg_type_t;
-
-/*
  * 64-bit software counter structure
  */
 typedef struct {
 	u64 val;	/* virtual 64bit counter value */
-	u64 ival;	/* initial value from user */
+	u64 lval;	/* last value */
 	u64 long_reset;	/* reset value on sampling overflow */
 	u64 short_reset;/* reset value on overflow */
 	u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */
-	int flags;	/* notify/do not notify */
+	u64 seed;	/* seed for random-number generator */
+	u64 mask;	/* mask for random-number generator */
+	unsigned int flags; /* notify/do not notify */
 } pfm_counter_t;
 
 /*
@@ -212,7 +229,8 @@
 	unsigned int frozen:1;		/* pmu must be kept frozen on ctxsw in */
 	unsigned int protected:1;	/* allow access to creator of context only */
 	unsigned int using_dbreg:1;	/* using range restrictions (debug registers) */
-	unsigned int reserved:24;
+	unsigned int excl_idle:1;	/* exclude idle task in system wide session */
+	unsigned int reserved:23;
 } pfm_context_flags_t;
 
 /*
@@ -247,7 +265,7 @@
 
 	u64			ctx_saved_psr;		/* copy of psr used for lazy ctxsw */
 	unsigned long		ctx_saved_cpus_allowed;	/* copy of the task cpus_allowed (system wide) */
-	unsigned long		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
+	unsigned int		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
 
 	atomic_t		ctx_saving_in_progress;	/* flag indicating actual save in progress */
 	atomic_t		ctx_is_busy;		/* context accessed by overflow handler */
@@ -260,6 +278,7 @@
 #define ctx_fl_frozen		ctx_flags.frozen
 #define ctx_fl_protected	ctx_flags.protected
 #define ctx_fl_using_dbreg	ctx_flags.using_dbreg
+#define ctx_fl_excl_idle	ctx_flags.excl_idle
 
 /*
  * global information about all sessions
@@ -268,10 +287,10 @@
 typedef struct {
 	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	unsigned int 		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned int		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned int		pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned int		pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
 	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
@@ -281,13 +300,16 @@
  * dep_pmc[]: a bitmask of dependent PMC registers
  */
 typedef struct {
-	pfm_pmu_reg_type_t	type;
+	unsigned int		type;
 	int			pm_pos;
+	unsigned long		default_value;	/* power-on default value */
+	unsigned long		reserved_mask;	/* bitmask of reserved bits */
 	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	unsigned long		dep_pmd[4];
 	unsigned long		dep_pmc[4];
 } pfm_reg_desc_t;
+
 /* assume cnum is a valid monitor */
 #define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
 #define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
@@ -296,23 +318,22 @@
 
 /*
  * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL along with a list of inter-registers dependencies and configurations.
+ * a description of the PMU main characteristics.
  */
 typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
-	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+	unsigned int  disabled;		/* indicates if perfmon is working properly */
+	unsigned long ovfl_val;		/* overflow value for generic counters   */
+	unsigned long impl_pmcs[4];	/* bitmask of implemented PMCS */
+	unsigned long impl_pmds[4];	/* bitmask of implemented PMDS */
+	unsigned int  num_pmcs;		/* number of implemented PMCS */
+	unsigned int  num_pmds;		/* number of implemented PMDS */
+	unsigned int  num_ibrs;		/* number of implemented IBRS */
+	unsigned int  num_dbrs;		/* number of implemented DBRS */
+	unsigned int  num_counters;	/* number of PMD/PMC counters */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register dependencies descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register dependencies descriptions */
 } pmu_config_t;
 
-
 /*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
@@ -336,7 +357,7 @@
 
 #define PFM_CMD_PID		0x1	/* command requires pid argument */
 #define PFM_CMD_ARG_READ	0x2	/* command must read argument(s) */
-#define PFM_CMD_ARG_WRITE	0x4	/* command must write argument(s) */
+#define PFM_CMD_ARG_RW		0x4	/* command must read/write argument(s) */
 #define PFM_CMD_CTX		0x8	/* command needs a perfmon context */
 #define PFM_CMD_NOCHK		0x10	/* command does not need to check task's state */
 
@@ -347,7 +368,7 @@
 
 #define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)
 #define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)
-#define PFM_CMD_WRITE_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_WRITE) != 0)
+#define PFM_CMD_RW_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0)
 #define PFM_CMD_USE_CTX(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0)
 #define PFM_CMD_CHK(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0)
 
@@ -366,15 +387,16 @@
 	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
 	unsigned long pfm_recorded_samples_count;
 	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
 } pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
-static pmu_config_t	pmu_conf; 	/* PMU configuration */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static pfm_stats_t	pfm_stats;
+static pfm_stats_t	pfm_stats[NR_CPUS];
+static pfm_intr_handler_desc_t	*pfm_alternate_intr_handler;
 
 /* sysctl() controls */
 static pfm_sysctl_t pfm_sysctl;
@@ -395,12 +417,10 @@
 };
 static struct ctl_table_header *pfm_sysctl_header;
 
-static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
-
 static void pfm_vm_close(struct vm_area_struct * area);
 
 static struct vm_operations_struct pfm_vm_ops={
-	close: pfm_vm_close
+	.close =  pfm_vm_close
 };
 
 /*
@@ -408,14 +428,15 @@
  */
 static struct {
 	struct task_struct *owner;
-} ____cacheline_aligned pmu_owners[NR_CPUS];
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
+} pmu_owners[NR_CPUS];
 
 
 
 /*
  * forward declarations
  */
-static void ia64_reset_pmu(struct task_struct *);
+static void pfm_reset_pmu(struct task_struct *);
 #ifdef CONFIG_SMP
 static void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx);
 #endif
@@ -429,43 +450,79 @@
 #include "perfmon_generic.h"
 #endif
 
+static inline void
+pfm_clear_psr_pp(void)
+{
+	__asm__ __volatile__ ("rsm psr.pp;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_set_psr_pp(void)
+{
+	__asm__ __volatile__ ("ssm psr.pp;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_clear_psr_up(void)
+{
+	__asm__ __volatile__ ("rum psr.up;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_set_psr_up(void)
+{
+	__asm__ __volatile__ ("sum psr.up;; srlz.i;;"::: "memory");
+}
+
+static inline unsigned long
+pfm_get_psr(void)
+{
+	unsigned long tmp;
+	__asm__ __volatile__ ("mov %0=psr;;": "=r"(tmp) :: "memory");
+	return tmp;
+}
+
+static inline void
+pfm_set_psr_l(unsigned long val)
+{
+	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(val): "memory");
+}
+
+
+
+static inline void
+pfm_freeze_pmu(void)
+{
+	ia64_set_pmc(0,1UL);
+	ia64_srlz_d();
+}
+
+static inline void
+pfm_unfreeze_pmu(void)
+{
+	ia64_set_pmc(0,0UL);
+	ia64_srlz_d();
+}
+
+
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
-	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.perf_ovfl_val);
+	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val);
 }
 
 static inline void
 pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
 {
-	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.perf_ovfl_val;
+	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.ovfl_val;
 	/*
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
+	ia64_set_pmd(i, val & pmu_conf.ovfl_val);
 }
 
 /*
- * finds the number of PM(C|D) registers given
- * the bitvector returned by PAL
- */
-static unsigned long __init
-find_num_pm_regs(long *buffer)
-{
-	int i=3; /* 4 words/per bitvector */
-
-	/* start from the most significant word */
-	while (i>=0 && buffer[i] == 0 ) i--;
-	if (i< 0) {
-		printk(KERN_ERR "perfmon: No bit set in pm_buffer\n");
-		return 0;
-	}
-	return 1+ ia64_fls(buffer[i]) + 64 * i;
-}
-
-
-/*
  * Generates a unique (per CPU) timestamp
  */
 static inline unsigned long
@@ -477,31 +534,6 @@
 	return ia64_get_itc();
 }
 
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long
-uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-	unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-
-	if (!pgd_none(*pgd)) {
-		pmd = pmd_offset(pgd, adr);
-		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, adr);
-			pte = *ptep;
-			if (pte_present(pte)) {
-				ret = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-			}
-		}
-	}
-	DBprintk(("[%d] uv2kva(%lx-->%lx)\n", current->pid, adr, ret));
-	return ret;
-}
-
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the
  * area and marking the pages as reserved.
@@ -767,15 +799,14 @@
 	psb = kmalloc(sizeof(*psb), GFP_KERNEL);
 	if (psb == NULL) {
 		DBprintk(("Can't allocate sampling buffer descriptor\n"));
-		pfm_rvfree(smpl_buf, size);
-		return -ENOMEM;
+		goto error_kmalloc;
 	}
 
 	/* allocate vma */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) {
 		DBprintk(("Cannot allocate vma\n"));
-		goto error;
+		goto error_kmem;
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
@@ -875,11 +906,127 @@
 	return 0;
 
 error:
-	pfm_rvfree(smpl_buf, size);
+	kmem_cache_free(vm_area_cachep, vma);
+error_kmem:
 	kfree(psb);
+error_kmalloc:
+	pfm_rvfree(smpl_buf, size);
 	return -ENOMEM;
 }
 
+static int
+pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	unsigned long m, undo_mask;
+	unsigned int n, i;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	if (is_syswide) {
+		/* 
+		 * cannot mix system wide and per-task sessions
+		 */
+		if (pfm_sessions.pfs_task_sessions > 0UL) {
+			DBprintk(("system wide not possible, %u conflicting task_sessions\n", 
+			  	pfm_sessions.pfs_task_sessions));
+			goto abort;
+		}
+
+		m = cpu_mask; undo_mask = 0UL; n = 0;
+		DBprintk(("cpu_mask=0x%lx\n", cpu_mask));
+		for(i=0; m; i++, m>>=1) {
+
+			if ((m & 0x1) == 0UL) continue;
+
+			if (pfm_sessions.pfs_sys_session[i]) goto undo;
+
+			DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id()));
+
+			pfm_sessions.pfs_sys_session[i] = task;
+			undo_mask |= 1UL << i;
+			n++;
+		}
+		pfm_sessions.pfs_sys_sessions += n;
+	} else {
+		if (pfm_sessions.pfs_sys_sessions) goto abort;
+		pfm_sessions.pfs_task_sessions++;
+	}
+	UNLOCK_PFS();
+	return 0;
+undo:
+	DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",
+  		pfm_sessions.pfs_sys_session[i]->pid, i));
+
+	for(i=0; undo_mask; i++, undo_mask >>=1) {
+		pfm_sessions.pfs_sys_session[i] = NULL;
+	}
+abort:
+	UNLOCK_PFS();
+
+	return -EBUSY;
+
+}
+
+static int
+pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	pfm_context_t *ctx;
+	unsigned long m;
+	unsigned int n, i;
+
+	ctx = task ? task->thread.pfm_context : NULL;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n",
+		task->pid,
+		pfm_sessions.pfs_sys_sessions,
+		pfm_sessions.pfs_task_sessions,
+		pfm_sessions.pfs_sys_use_dbregs,
+		is_syswide,
+		cpu_mask));
+		
+
+	if (is_syswide) {
+		m = cpu_mask; n = 0;
+		for(i=0; m; i++, m>>=1) {
+			if ((m & 0x1) == 0UL) continue;
+			pfm_sessions.pfs_sys_session[i] = NULL;
+			n++;
+		}
+		/* 
+		 * would not work with perfmon+more than one bit in cpu_mask
+		 */
+		if (ctx && ctx->ctx_fl_using_dbreg) {
+			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
+				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
+			} else {
+				pfm_sessions.pfs_sys_use_dbregs--;
+			}
+		}
+		pfm_sessions.pfs_sys_sessions -= n;
+
+		DBprintk(("CPU%d sys_sessions=%u\n", 
+			smp_processor_id(), pfm_sessions.pfs_sys_sessions));
+	} else {
+		pfm_sessions.pfs_task_sessions--;
+		DBprintk(("[%d] task_sessions=%u\n", 
+			task->pid, pfm_sessions.pfs_task_sessions));
+	}
+
+	UNLOCK_PFS();
+
+	return 0;
+}
+
+
+
 /*
  * XXX: do something better here
  */
@@ -895,6 +1042,7 @@
 static int
 pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx)
 {
+	unsigned long smpl_pmds = pfx->ctx_smpl_regs[0];
 	int ctx_flags;
 	int cpu;
 
@@ -961,6 +1109,11 @@
 		}
 #endif
 	}
+	/* verify validity of smpl_regs */
+	if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) {
+		DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds));
+		return -EINVAL;
+	}
 	/* probably more to add here */
 
 	return 0;
@@ -972,7 +1125,7 @@
 {
 	pfarg_context_t tmp;
 	void *uaddr = NULL;
-	int ret, cpu = 0;
+	int ret;
 	int ctx_flags;
 	pid_t notify_pid;
 
@@ -984,47 +1137,15 @@
 	 */
 	if (task != current) return -EINVAL;
 
-	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+	if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 	ret = pfx_is_sane(task, &tmp);
 	if (ret < 0) return ret;
 
 	ctx_flags = tmp.ctx_flags;
 
-	ret =  -EBUSY;
-
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-
-		/* at this point, we know there is at least one bit set */
-		cpu = ffz(~tmp.ctx_cpu_mask);
-
-		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
-
-		if (pfm_sessions.pfs_task_sessions > 0) {
-			DBprintk(("system wide not possible, task_sessions=%ld\n", pfm_sessions.pfs_task_sessions));
-			goto abort;
-		}
-
-		if (pfm_sessions.pfs_sys_session[cpu]) {
-			DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",pfm_sessions.pfs_sys_session[cpu]->pid, cpu));
-			goto abort;
-		}
-		pfm_sessions.pfs_sys_session[cpu] = task;
-		/*
-		 * count the number of system wide sessions
-		 */
-		pfm_sessions.pfs_sys_sessions++;
-
-	} else if (pfm_sessions.pfs_sys_sessions == 0) {
-		pfm_sessions.pfs_task_sessions++;
-	} else {
-		/* no per-process monitoring while there is a system wide session */
-		goto abort;
-	}
-
-	UNLOCK_PFS();
+	ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask);
+	if (ret) goto abort;
 
 	ret = -ENOMEM;
 
@@ -1040,8 +1161,8 @@
 
 	if (notify_pid == current->pid) {
 
-		ctx->ctx_notify_task = task = current;
-		current->thread.pfm_context = ctx;
+		ctx->ctx_notify_task = current;
+		task->thread.pfm_context = ctx;
 
 	} else if (notify_pid!=0) {
 		struct task_struct *notify_task;
@@ -1057,7 +1178,10 @@
 			/*
 			 * check if we can send this task a signal
 			 */
-			if (pfm_bad_permissions(notify_task)) goto buffer_error;
+			if (pfm_bad_permissions(notify_task)) {
+				read_unlock(&tasklist_lock);
+				goto buffer_error;
+			}
 
 			/* 
 		 	 * make visible
@@ -1067,7 +1191,7 @@
 		 	 * okay because child will do the scan for nothing which
 		 	 * won't hurt.
 		 	 */
-			current->thread.pfm_context = ctx;
+			task->thread.pfm_context = ctx;
 
 			/*
 			 * will cause task to check on exit for monitored
@@ -1104,6 +1228,7 @@
 	ctx->ctx_fl_inherit   = ctx_flags & PFM_FL_INHERIT_MASK;
 	ctx->ctx_fl_block     = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
 	ctx->ctx_fl_system    = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+	ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
 	ctx->ctx_fl_frozen    = 0;
 	/*
 	 * setting this flag to 0 here means, that the creator or the task that the
@@ -1114,9 +1239,10 @@
 	ctx->ctx_fl_protected = 0;
 
 	/* for system wide mode only (only 1 bit set) */
-	ctx->ctx_cpu         = cpu;
+	ctx->ctx_cpu = ffz(~tmp.ctx_cpu_mask);
 
-	atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */
+	/* SMP only, means no CPU */
+	atomic_set(&ctx->ctx_last_cpu,-1); 
 
 	/* may be redudant with memset() but at least it's easier to remember */
 	atomic_set(&ctx->ctx_saving_in_progress, 0); 
@@ -1124,7 +1250,7 @@
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-	if (copy_to_user(req, &tmp, sizeof(tmp))) {
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
 	}
@@ -1132,9 +1258,9 @@
 	DBprintk(("context=%p, pid=%d notify_task=%p\n",
 			(void *)ctx, task->pid, ctx->ctx_notify_task));
 
-	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d\n", 
+	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d\n", 
 			(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, 
-			ctx->ctx_fl_block, ctx->ctx_fl_system));
+			ctx->ctx_fl_block, ctx->ctx_fl_system, ctx->ctx_fl_excl_idle));
 
 	/*
 	 * when no notification is required, we can make this visible at the last moment
@@ -1147,9 +1273,9 @@
 	 */
 	if (ctx->ctx_fl_system) {
 		ctx->ctx_saved_cpus_allowed = task->cpus_allowed;
-		task->cpus_allowed = 1UL << cpu;
+		task->cpus_allowed = tmp.ctx_cpu_mask;
 		task->need_resched = 1;
-		DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid,task->cpus_allowed));
+		DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid, task->cpus_allowed));
 	}
 
 	return 0;
@@ -1157,32 +1283,40 @@
 buffer_error:
 	pfm_context_free(ctx);
 error:
-	/*
-	 * undo session reservation
-	 */
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-		pfm_sessions.pfs_sys_session[cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
+	pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask);
 abort:
-	UNLOCK_PFS();
+	/* make sure we don't leave anything behind */
+	task->thread.pfm_context = NULL;
 
 	return ret;
 }
 
+static inline unsigned long
+pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
+{
+	unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;
+	unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;
+	extern unsigned long carta_random32 (unsigned long seed);
+
+	if (reg->flags & PFM_REGFL_RANDOM) {
+		new_seed = carta_random32(old_seed);
+		val -= (old_seed & mask);	/* counter values are negative numbers! */
+		if ((mask >> 32) != 0)
+			/* construct a full 64-bit random value: */
+			new_seed |= carta_random32(old_seed >> 32) << 32;
+		reg->seed = new_seed;
+	}
+	reg->lval = val;
+	return val;
+}
+
 static void
 pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
 {
 	unsigned long mask = ovfl_regs[0];
 	unsigned long reset_others = 0UL;
 	unsigned long val;
-	int i;
-
-	DBprintk(("masks=0x%lx\n", mask));
+	int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
 
 	/*
 	 * now restore reset value on sampling overflowed counters
@@ -1190,15 +1324,11 @@
 	mask >>= PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
 		if (mask & 0x1) {
-			val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
-
+			val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 			reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0];
 
-			DBprintk(("[%d] %s reset soft_pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+			DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid,
+				  is_long_reset ? "long" : "short", i, val));
 
 			/* upper part is ignored on rval */
 			pfm_write_soft_counter(ctx, i, val);
@@ -1212,23 +1342,17 @@
 
 		if ((reset_others & 0x1) == 0) continue;
 
-		val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
+		val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 
 		if (PMD_IS_COUNTING(i)) {
 			pfm_write_soft_counter(ctx, i, val);
 		} else {
 			ia64_set_pmd(i, val);
 		}
-
-		DBprintk(("[%d] %s reset_others pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+		DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid,
+			  is_long_reset ? "long" : "short", i, val));
 	}
 	ia64_srlz_d();
-	/* just in case ! */
-	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
@@ -1236,23 +1360,28 @@
 {
 	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long value, reset_pmds;
+	unsigned int cnum, reg_flags, flags;
 	int i;
-	int ret = 0, reg_retval = 0;
+	int ret = -EINVAL;
 
 	/* we don't quite support this right now */
 	if (task != current) return -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
+
 	/* XXX: ctx locking may be required here */
 
 	for (i = 0; i < count; i++, req++) {
 
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
-
-		cnum = tmp.reg_num;
+		cnum       = tmp.reg_num;
+		reg_flags  = tmp.reg_flags;
+		value      = tmp.reg_value;
+		reset_pmds = tmp.reg_reset_pmds[0];
+		flags      = 0;
 
 		/* 
 		 * we reject all non implemented PMC as well
@@ -1261,8 +1390,7 @@
 		 */
 		if (!PMC_IS_IMPL(cnum) || cnum < 4) {
 			DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum));
-			ret = -EINVAL;
-			goto abort_mission;
+			goto error;
 		}
 		/*
 		 * A PMC used to configure monitors must be:
@@ -1271,73 +1399,83 @@
 		 * any other configuration is rejected.
 		 */
 		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
-			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); 
 
-			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
-				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
-				ret = -EINVAL;
-				goto abort_mission;
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system));
+				goto error;
 			}
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			pfm_monitor_t *p = (pfm_monitor_t *)&value;
 			/*
 		 	 * enforce generation of overflow interrupt. Necessary on all
 		 	 * CPUs.
 		 	 */
 			p->pmc_oi = 1;
 
-			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
+			if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
-				 * must have a target for the signal
-				 */
+			 	 * must have a target for the signal
+			 	 */
 				if (ctx->ctx_notify_task == NULL) {
-					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
-					ret = -EINVAL;
-					goto abort_mission;
+					DBprintk(("cannot set ovfl_notify: no notify_task\n"));
+					goto error;
 				}
+				flags |= PFM_REGFL_OVFL_NOTIFY;
+			}
 
-				ctx->ctx_soft_pmds[cnum].flags |= PFM_REGFL_OVFL_NOTIFY;
+			if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;
+
+			/* verify validity of reset_pmds */
+			if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) {
+				DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));
+				goto error;
 			}
-			/*
-			 * copy reset vector
-			 */
-			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = tmp.reg_reset_pmds[0];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
+		} else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
+				DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum));
+				goto error;
 		}
+
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
+		if (PMC_WR_FUNC(cnum)) {
+			ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs);
+			if (ret) goto error;
+			ret = -EINVAL;
+		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		/*
 		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 *
+		 * If this fails, then the software state is not modified
 		 */
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * Now we commit the changes to the software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
-		}
 
 		/* 
-		 * We can proceed with this register!
+		 * full flag update each time a register is programmed
 		 */
+		ctx->ctx_soft_pmds[cnum].flags = flags;
+
+		if (PMC_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds;
+
+			/* mark all PMDS to be accessed as used */
+			CTX_USED_PMD(ctx, reset_pmds);
+		}
 
 		/*
 		 * Needed in case the user does not initialize the equivalent
@@ -1349,16 +1487,26 @@
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
-		th->pmc[cnum] = tmp.reg_value;
+		th->pmc[cnum] = value;
 
-		ia64_set_pmc(cnum, tmp.reg_value);
+		ia64_set_pmc(cnum, value);
 
 		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
-			  task->pid, cnum, tmp.reg_value, 
+			  task->pid, cnum, value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
 			  ctx->ctx_used_pmds[0]));
 
 	}
+
+	return 0;
+
+error:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1366,9 +1514,10 @@
 pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned long value, hw_value;
 	unsigned int cnum;
 	int i;
-	int ret = 0, reg_retval = 0;
+	int ret = -EINVAL;
 
 	/* we don't quite support this right now */
 	if (task != current) return -EINVAL;
@@ -1378,73 +1527,99 @@
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-
 	/* XXX: ctx locking may be required here */
 
+
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum  = tmp.reg_num;
+		value = tmp.reg_value;
 
-		cnum = tmp.reg_num;
 		if (!PMD_IS_IMPL(cnum)) {
-			ret = -EINVAL;
+			DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum));
 			goto abort_mission;
 		}
 
-		/* update virtualized (64bits) counter */
-		if (PMD_IS_COUNTING(cnum)) {
-			ctx->ctx_soft_pmds[cnum].ival = tmp.reg_value;
-			ctx->ctx_soft_pmds[cnum].val  = tmp.reg_value & ~pmu_conf.perf_ovfl_val;
-			ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset;
-			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
-
-		}
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
-
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		if (PMD_WR_FUNC(cnum)) {
+			unsigned long v = value;
+			ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs);
+			if (ret) goto abort_mission;
+			value = v;
+			ret = -EINVAL;
+		}
+		hw_value = value;
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * now commit changes to software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
+
+		/* update virtualized (64bits) counter */
+		if (PMD_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].lval = value;
+			ctx->ctx_soft_pmds[cnum].val  = value & ~pmu_conf.ovfl_val;
+
+			hw_value = value & pmu_conf.ovfl_val;
+
+			ctx->ctx_soft_pmds[cnum].long_reset  = tmp.reg_long_reset;
+			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
+
+			ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed;
+			ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask;
 		}
 
 		/* keep track of what we use */
 		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+
 		/* mark this register as used as well */
 		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
+		ia64_set_pmd(cnum, hw_value);
 
 		/* to go away */
 		ia64_srlz_d();
 
-		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
+		DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
 				task->pid, cnum,
+				value, hw_value,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
-				ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val,
+				ia64_get_pmd(cnum) & pmu_conf.ovfl_val,
 				PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',
 				ctx->ctx_used_pmds[0],
 				ctx->ctx_soft_pmds[cnum].reset_pmds[0]));
 	}
+
+	return 0;
+
+abort_mission:
+	/*
+	 * for now, we have only one possibility for error
+	 */
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	/*
+	 * we change the return value to EFAULT in case we cannot write register return code.
+	 * The caller first must correct this error, then a resubmission of the request will
+	 * eventually yield the EINVAL.
+	 */
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1452,10 +1627,13 @@
 pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	struct thread_struct *th = &task->thread;
-	unsigned long val=0;
-	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long val, lval;
+	pfarg_reg_t *req = (pfarg_reg_t *)arg;
+	unsigned int cnum, reg_flags = 0;
 	int i, ret = 0;
+#if __GNUC__ < 3
+	int foo;
+#endif
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1471,11 +1649,17 @@
 	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long ctx_val = ~0UL;
-
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		cnum = tmp.reg_num;
+#if __GNUC__ < 3
+		foo = __get_user(cnum, &req->reg_num);
+		if (foo) return -EFAULT;
+		foo = __get_user(reg_flags, &req->reg_flags);
+		if (foo) return -EFAULT;
+#else
+		if (__get_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT;
+#endif
+		lval = 0UL;
 
 		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
 		/*
@@ -1523,36 +1707,47 @@
 			/*
 			 * XXX: need to check for overflow
 			 */
+			val &= pmu_conf.ovfl_val;
+			val += ctx->ctx_soft_pmds[cnum].val;
 
-			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
+			lval = ctx->ctx_soft_pmds[cnum].lval;
 		} 
 
-		tmp.reg_value = val;
-
 		/*
 		 * execute read checker, if any
 		 */
 		if (PMD_RD_FUNC(cnum)) {
-			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
+			unsigned long v = val;
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs);
+			val = v;
 		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+		PFM_REG_RETFLAG_SET(reg_flags, ret);
 
 		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
 					cnum, ret, val, ia64_get_pmc(cnum)));
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		/*
+		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 */
+		if (__put_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__put_user(val, &req->reg_value)) return -EFAULT;
+		if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT;
+		if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT;
 	}
+
 	return 0;
+
 abort_mission:
-	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
 	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	__put_user(reg_flags, &req->reg_flags);
 
+	return -EINVAL;
 }
 
 #ifdef PFM_PMU_USES_DBR
@@ -1594,7 +1789,7 @@
 	else
 		pfm_sessions.pfs_ptrace_use_dbregs++;
 
-	DBprintk(("ptrace_use_dbregs=%lu  sys_use_dbregs=%lu by [%d] ret = %d\n", 
+	DBprintk(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n", 
 		  pfm_sessions.pfs_ptrace_use_dbregs, 
 		  pfm_sessions.pfs_sys_use_dbregs, 
 		  task->pid, ret));
@@ -1660,9 +1855,12 @@
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
 	if (task == current) {
-		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+		DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", 
+			task->pid, 
+			ctx->ctx_fl_frozen,
+			ctx->ctx_ovfl_regs[0]));
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -1678,8 +1876,7 @@
 		}
 
 		/* simply unfreeze */
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 
 		return 0;
 	} 
@@ -1721,44 +1918,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_SMP
-/*
- * On UP kernels, we do not need to constantly set the psr.pp bit
- * when a task is scheduled. The psr.pp bit can only be changed in
- * the kernel because of a user request. Given we are on a UP non preeemptive 
- * kernel we know that no other task is running, so we cna simply update their
- * psr.pp from their saved state. There is this no impact on the context switch
- * code compared to the SMP case.
- */
-static void
-pfm_tasklist_toggle_pp(unsigned int val)
-{
-	struct task_struct *p;
-	struct pt_regs *regs;
-
-	DBprintk(("invoked by [%d] pp=%u\n", current->pid, val));
-
-	read_lock(&tasklist_lock);
-
-	for_each_task(p) {
-       		regs = (struct pt_regs *)((unsigned long) p + IA64_STK_OFFSET);
-
-		/*
-		 * position on pt_regs saved on stack on 1st entry into the kernel
-		 */
-		regs--;
-
-		/*
-		 * update psr.pp
-		 */
-		ia64_psr(regs)->pp = val;
-	}
-	read_unlock(&tasklist_lock);
-}
-#endif
-
-
-
 static int
 pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
@@ -1783,22 +1942,17 @@
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+
 		ia64_psr(regs)->pp = 0;
 
 	} else {
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		/*
@@ -1960,14 +2114,9 @@
 	int i, ret = 0;
 
 	/*
-	 * for range restriction: psr.db must be cleared or the
-	 * the PMU will ignore the debug registers.
-	 *
-	 * XXX: may need more in system wide mode,
-	 * no task can have this bit set?
+	 * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w
+	 * ensuring that no real breakpoint can be installed via this call.
 	 */
-	if (ia64_psr(regs)->db == 1) return -EINVAL;
-
 
 	first_time = ctx->ctx_fl_using_dbreg == 0;
 
@@ -2036,9 +2185,8 @@
 	 * Now install the values into the registers
 	 */
 	for (i = 0; i < count; i++, req++) {
-
 		
-		if (copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
 		
 		rnum      = tmp.dbreg_num;
 		dbreg.val = tmp.dbreg_value;
@@ -2071,7 +2219,7 @@
 
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
 
 		/*
 		 * Debug registers, just like PMC, can only be modified
@@ -2126,7 +2274,7 @@
 		 * XXX: for now we can only come here on EINVAL
 		 */
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL);
-		copy_to_user(req, &tmp, sizeof(tmp));
+		if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT;
 	}
 	return ret;
 }
@@ -2167,7 +2315,7 @@
 	tmp.ft_version      = PFM_VERSION;
 	tmp.ft_smpl_version = PFM_SMPL_VERSION;
 
-	if (copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
+	if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
 
 	return 0;
 }
@@ -2196,16 +2344,13 @@
 
 	if (ctx->ctx_fl_system) {
 		
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 1;
-#else
-		pfm_tasklist_toggle_pp(1);
-#endif
+		PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP);
+
 		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
 		/* start monitoring at kernel level */
-		__asm__ __volatile__ ("ssm psr.pp;;"::: "memory");
+		pfm_set_psr_pp();
 
 		/* enable dcr pp */
 		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
@@ -2221,7 +2366,7 @@
 		ia64_psr(regs)->up = 1;
 
 		/* start monitoring at kernel level */
-		__asm__ __volatile__ ("sum psr.up;;"::: "memory");
+		pfm_set_psr_up();
 
 		ia64_srlz_i();
 	}
@@ -2234,13 +2379,16 @@
 	   struct pt_regs *regs)
 {
 	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	if (task != current) {
+		DBprintk(("task [%d] != current [%d]\n", task->pid, current->pid));
+		return -EINVAL;
+	}
 
 	if (ctx->ctx_fl_system == 0 && PMU_OWNER()  && PMU_OWNER() != current) 
 		pfm_lazy_save_regs(PMU_OWNER());
 
 	/* reset all registers to stable quiet state */
-	ia64_reset_pmu(task);
+	pfm_reset_pmu(task);
 
 	/* make sure nothing starts */
 	if (ctx->ctx_fl_system) {
@@ -2248,13 +2396,12 @@
 		ia64_psr(regs)->up = 0; /* just to make sure! */
 
 		/* make sure monitoring is stopped */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 1;
-		local_cpu_data->pfm_dcr_pp    = 0;
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+		PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE);
+		if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE);
 	} else {
 		/*
 		 * needed in case the task was a passive task during
@@ -2265,7 +2412,7 @@
 		ia64_psr(regs)->up = 0;
 
 		/* make sure monitoring is stopped */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		DBprintk(("clearing psr.sp for [%d]\n", current->pid));
@@ -2283,8 +2430,7 @@
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
 	/* simply unfreeze */
-	ia64_set_pmc(0, 0);
-	ia64_srlz_d();
+	pfm_unfreeze_pmu();
 
 	return 0;
 }
@@ -2295,32 +2441,30 @@
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
-	int i;
+	int i, ret = -EINVAL;
 
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
 
 		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
 
-		tmp.reg_value = reset_pmcs[cnum];
+		tmp.reg_value = PMC_DFL_VAL(cnum);
 
 		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
 	return 0;
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
-	/* 
-	 * XXX: if this fails, we stick with the original failure, flag not updated!
-	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT;
+
+	return ret;
 }
 
 /*
@@ -2328,21 +2472,21 @@
  */
 static pfm_cmd_desc_t pfm_cmd_tab[]={
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
-/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
-/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)},
 /* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
+/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
 /* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2360,8 +2504,8 @@
 /* 30 */{ NULL, 0, 0, 0}, /* not used */
 /* 31 */{ NULL, 0, 0, 0}, /* not used */
 #ifdef PFM_PMU_USES_DBR
-/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
-/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
+/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
+/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
 #endif
 };
 #define PFM_CMD_COUNT	(sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
@@ -2379,11 +2523,15 @@
 	for (;;) {
 
 		task_lock(task);
+		DBprintk((" [%d] state=%ld\n", task->pid, task->state));
 		if (!task_has_cpu(task)) break;
 		task_unlock(task);
 
 		do {
-			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
+			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) {
+				DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state));
+				return -EBUSY;
+			}
 			barrier();
 			cpu_relax();
 		} while (task_has_cpu(task));
@@ -2398,7 +2546,7 @@
 	return ret;
 }
 
-asmlinkage int
+asmlinkage long
 sys_perfmonctl (pid_t pid, int cmd, void *arg, int count, long arg5, long arg6, long arg7, 
 		long arg8, long stack)
 {
@@ -2406,7 +2554,8 @@
 	struct task_struct *task = current;
 	pfm_context_t *ctx;
 	size_t sz;
-	int ret, narg;
+	long ret;
+	int narg;
 
 	/* 
 	 * reject any call if perfmon was disabled at initialization time
@@ -2426,7 +2575,7 @@
 
 	if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT;
 
-	if (PFM_CMD_WRITE_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
+	if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
 
 	if (PFM_CMD_USE_PID(cmd))  {
 		/* 
@@ -2484,15 +2633,9 @@
 	return ret;
 }
 
-#if __GNUC__ >= 3
-void asmlinkage
-pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
-		      u64 arg6, u64 arg7, long info)
-#else
 void asmlinkage
 pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
 		      u64 arg6, u64 arg7, long info)
-#endif
 {
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
@@ -2537,7 +2680,7 @@
 		 * use the local reference
 		 */
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -2550,8 +2693,7 @@
 			ctx->ctx_psb->psb_index = 0;
 		}
 
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 
 		/* state restored, can go back to work (user mode) */
 	}
@@ -2577,12 +2719,12 @@
 	DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
 
 	/*
-	* XXX: there is a small chance that we could run out on index before resetting
-	* but index is unsigned long, so it will take some time.....
-	* We use > instead of == because fetch_and_add() is off by one (see below)
-	*
-	* This case can happen in non-blocking mode or with multiple processes.
-	* For non-blocking, we need to reload and continue.
+	 * XXX: there is a small chance that we could run out on index before resetting
+	 * but index is unsigned long, so it will take some time.....
+	 * We use > instead of == because fetch_and_add() is off by one (see below)
+	 *
+	 * This case can happen in non-blocking mode or with multiple processes.
+	 * For non-blocking, we need to reload and continue.
 	 */
 	if (idx > psb->psb_entries) return 0;
 
@@ -2596,13 +2738,12 @@
 	 */
 	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
-	h->rate = 0; /* XXX: add the sampling rate used here */
-	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
+	h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL;
+	h->ip   = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL;
 	h->regs = ovfl_mask; 			/* which registers overflowed */
 
 	/* guaranteed to monotonically increase on each cpu */
 	h->stamp  = pfm_get_stamp();
-	h->period = 0UL; /* not yet used */
 
 	/* position for first pmd */
 	e = (unsigned long *)(h+1);
@@ -2617,15 +2758,13 @@
 
 		if (PMD_IS_COUNTING(j)) {
 			*e  =  pfm_read_soft_counter(ctx, j);
-			/* check if this pmd overflowed as well */
-			*e +=  ovfl_mask & (1UL<<j) ? 1 + pmu_conf.perf_ovfl_val : 0;
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
 		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
-	pfm_stats.pfm_recorded_samples_count++;
+	pfm_stats[smp_processor_id()].pfm_recorded_samples_count++;
 
 	/*
 	 * make the new entry visible to user, needs to be atomic
@@ -2642,7 +2781,7 @@
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
-		pfm_stats.pfm_full_smpl_buffer_count++;
+		pfm_stats[smp_processor_id()].pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2719,23 +2858,13 @@
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
-		 * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use
-		 * val to count the number of times we overflowed. Otherwise we would loose the 
-		 * current value in the PMD (which can be >0). So to make sure we don't loose
-		 * the residual counts we set val to contain full 64bits value of the counter.
+		 * Note that the pmd is not necessarily 0 at this point as qualified events
+		 * may have happened before the PMU was frozen. The residual count is not
+		 * taken into consideration here but will be with any read of the pmd via
+		 * pfm_read_pmds().
 		 */
 		old_val = ctx->ctx_soft_pmds[i].val;
-		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
-
-		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
-			  i, ctx->ctx_soft_pmds[i].val, old_val, 
-			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
-
-		/*
-		 * now that we have extracted the hardware counter, we can clear it to ensure
-		 * that a subsequent PFM_READ_PMDS will not include it again.
-		 */
-		ia64_set_pmd(i, 0UL);
+		ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 
 		/*
 		 * check for overflow condition
@@ -2744,12 +2873,13 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
-
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
 			}
 		}
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", 
+			  i, ctx->ctx_soft_pmds[i].val, old_val, 
+			  ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify));
 	}
 
 	/*
@@ -2784,7 +2914,7 @@
 	 */
 	if (ovfl_notify == 0UL) {
 		if (ovfl_pmds) 
-			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2932,13 +3062,21 @@
 }
 
 static void
-perfmon_interrupt (int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
 {
 	u64 pmc0;
 	struct task_struct *task;
 	pfm_context_t *ctx;
 
-	pfm_stats.pfm_ovfl_intr_count++;
+	pfm_stats[smp_processor_id()].pfm_ovfl_intr_count++;
+
+	/*
+	 * if an alternate handler is registered, just bypass the default one
+	 */
+	if (pfm_alternate_intr_handler) {
+		(*pfm_alternate_intr_handler->handler)(irq, arg, regs);
+		return;
+	}
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2983,11 +3121,20 @@
 		pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs);
 
 		/*
-		 * We always clear the overflow status bits and either unfreeze
-		 * or keep the PMU frozen.
+		 * we can only update pmc0 when the overflow
+		 * is for the current context. In UP the current
+		 * task may not be the one owning the PMU
 		 */
-		ia64_set_pmc(0, pmc0);
-		ia64_srlz_d();
+		if (task == current) {
+			/*
+		 	* We always clear the overflow status bits and either unfreeze
+		 	* or keep the PMU frozen.
+		 	*/
+			ia64_set_pmc(0, pmc0);
+			ia64_srlz_d();
+		} else {
+			task->thread.pmc[0] = pmc0;
+		}
 
 #ifdef CONFIG_SMP
 		/*
@@ -2996,42 +3143,38 @@
 		atomic_set(&ctx->ctx_is_busy, 0);
 #endif
 	} else {
-		pfm_stats.pfm_spurious_ovfl_intr_count++;
-
-		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER());
+		pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++;
 	}
 }
 
 /* for debug only */
 static int
-perfmon_proc_info(char *page)
+pfm_proc_info(char *page)
 {
 	char *p = page;
 	int i;
 
-	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
-	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
-	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
-	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
+	p += sprintf(p, "fastctxsw              : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask              : 0x%lx\n", pmu_conf.ovfl_val);
 
-#ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d syst_wide   : %d\n"
-			"CPU%d dcr_pp      : %d\n", 
-			smp_processor_id(), 
-			local_cpu_data->pfm_syst_wide, 
-			smp_processor_id(), 
-			local_cpu_data->pfm_dcr_pp);
-#endif
+	for(i=0; i < NR_CPUS; i++) {
+		if (cpu_is_online(i) == 0) continue;
+		p += sprintf(p, "CPU%-2d overflow intrs   : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d spurious intrs   : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
+		p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count);
+		p += sprintf(p, "CPU%-2d syst_wide        : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0);
+		p += sprintf(p, "CPU%-2d dcr_pp           : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0);
+		p += sprintf(p, "CPU%-2d exclude idle     : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0);
+		p += sprintf(p, "CPU%-2d owner            : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
+	}
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions    : %lu\n"
-			"sys_sessions     : %lu\n"
-			"sys_use_dbregs   : %lu\n"
-			"ptrace_use_dbregs: %lu\n", 
+
+	p += sprintf(p, "proc_sessions          : %u\n"
+			"sys_sessions           : %u\n"
+			"sys_use_dbregs         : %u\n"
+			"ptrace_use_dbregs      : %u\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -3039,30 +3182,6 @@
 
 	UNLOCK_PFS();
 
-	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d owner : %-6d\n",
-					i, 
-					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
-		}
-	}
-
-	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
-				i,
-				pmd_desc[i].type, 
-				pmd_desc[i].dep_pmd[0], 
-				pmd_desc[i].dep_pmc[0]); 
-	}
-
-	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
-				i, 
-				pmc_desc[i].type, 
-				pmc_desc[i].dep_pmd[0], 
-				pmc_desc[i].dep_pmc[0]); 
-	}
-
 	return p - page;
 }
 
@@ -3070,7 +3189,7 @@
 static int
 perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	int len = perfmon_proc_info(page);
+	int len = pfm_proc_info(page);
 
 	if (len <= off+count) *eof = 1;
 
@@ -3083,21 +3202,60 @@
 	return len;
 }
 
-#ifdef CONFIG_SMP
+/*
+ * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens
+ * during pfm_enable() hence before pfm_start(). We cannot assume monitoring
+ * is active or inactive based on mode. We must rely on the value in 
+ * local_cpu_data->pfm_syst_info
+ */
 void
-pfm_syst_wide_update_task(struct task_struct *task, int mode)
+pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
 {
-	struct pt_regs *regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET);
+	struct pt_regs *regs;
+	unsigned long dcr;
+	unsigned long dcr_pp;
 
-	regs--;
+	dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0;
 
 	/*
-	 * propagate the value of the dcr_pp bit to the psr
+	 * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 
+	 * on every CPU, so we can rely on the pid to identify the idle task.
 	 */
-	ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0;
+	if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) {
+		regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET);
+		regs--;
+		ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0;
+		return;
+	}
+	/*
+	 * we are the idle task  and there is exclusion.
+	 *
+	 * if monitoring has started
+	 */
+	if (dcr_pp) {
+		dcr = ia64_get_dcr();
+		/* 
+		 * context switching in? 
+		 */
+		if (is_ctxswin) {
+			/* mask monitoring for the idle task */
+			ia64_set_dcr(dcr & ~IA64_DCR_PP);
+			pfm_clear_psr_pp();
+			ia64_srlz_i();
+			return;
+		}
+		/* 
+		 * context switching out
+		 * restore normal kernel level settings 
+		 *
+		 * Due to inlining this odd if-then-else construction generates 
+		 * better code.
+	         */
+		ia64_set_dcr(dcr |IA64_DCR_PP);
+		pfm_set_psr_pp();
+		ia64_srlz_i();
+	}
 }
-#endif
-
 
 void
 pfm_save_regs (struct task_struct *task)
@@ -3107,11 +3265,10 @@
 
 	ctx = task->thread.pfm_context;
 
-
 	/*
 	 * save current PSR: needed because we modify it
 	 */
-	__asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory");
+	psr = pfm_get_psr();
 
 	/*
 	 * stop monitoring:
@@ -3120,7 +3277,7 @@
 	 * We do not need to set psr.sp because, it is irrelevant in kernel.
 	 * It will be restored from ipsr when going back to user level
 	 */
-	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+	pfm_clear_psr_up();
 	ia64_srlz_i();
 
 	ctx->ctx_saved_psr = psr;
@@ -3371,7 +3528,7 @@
 				atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 		psr = ctx->ctx_saved_psr;
-		__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
+		pfm_set_psr_l(psr);
 
 		return;
 	}
@@ -3409,7 +3566,7 @@
 	 */
 	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val);
 	}
 
 	/* 
@@ -3433,8 +3590,7 @@
 	 * fl_frozen==1 when we are in blocking mode waiting for restart
 	 */
 	if (ctx->ctx_fl_frozen == 0) {
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 	}
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
@@ -3444,55 +3600,51 @@
 	 * restore the psr we changed in pfm_save_regs()
 	 */
 	psr = ctx->ctx_saved_psr;
-	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
-
+	pfm_set_psr_l(psr);
 }
 
 /*
  * XXX: make this routine able to work with non current context
  */
 static void
-ia64_reset_pmu(struct task_struct *task)
+pfm_reset_pmu(struct task_struct *task)
 {
 	struct thread_struct *t = &task->thread;
 	pfm_context_t *ctx = t->pfm_context;
-	unsigned long mask;
 	int i;
 
 	if (task != current) {
-		printk("perfmon: invalid task in ia64_reset_pmu()\n");
+		printk("perfmon: invalid task in pfm_reset_pmu()\n");
 		return;
 	}
 
 	/* Let's make sure the PMU is frozen */
-	ia64_set_pmc(0,1);
+	pfm_freeze_pmu();
 
 	/*
 	 * install reset values for PMC. We skip PMC0 (done above)
 	 * XX: good up to 64 PMCS
 	 */
-	mask = pmu_conf.impl_regs[0] >> 1;
-	for(i=1; mask; mask>>=1, i++) {
-		if (mask & 0x1) {
-			ia64_set_pmc(i, reset_pmcs[i]);
-			/*
-			 * When restoring context, we must restore ALL pmcs, even the ones 
-			 * that the task does not use to avoid leaks and possibly corruption
-			 * of the sesion because of configuration conflicts. So here, we 
-			 * initialize the entire set used in the context switch restore routine.
-	 		 */
-			t->pmc[i] = reset_pmcs[i];
-			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
-						 
-		}
+	for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+		/*
+		 * When restoring context, we must restore ALL pmcs, even the ones 
+		 * that the task does not use to avoid leaks and possibly corruption
+		 * of the sesion because of configuration conflicts. So here, we 
+		 * initialize the entire set used in the context switch restore routine.
+	 	 */
+		t->pmc[i] = PMC_DFL_VAL(i);
+		DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i]));
 	}
+
 	/*
 	 * clear reset values for PMD. 
-	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
+	 * XXX: good up to 64 PMDS.
 	 */
-	mask = pmu_conf.impl_regs[4];
-	for(i=0; mask; mask>>=1, i++) {
-		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+	for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmd(i, 0UL);
 		t->pmd[i] = 0UL;
 	}
 
@@ -3521,13 +3673,13 @@
 	  *
 	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1;
 	/*
 	 * We must include all the PMD in this mask to avoid picking
 	 * up stale value and leak information, especially directly
 	 * at the user level when psr.sp=0
 	 */
-	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0];
 
 	/* 
 	 * Keep track of the pmds we want to sample
@@ -3537,7 +3689,7 @@
 	 *
 	 * We ignore the unimplemented pmds specified by the user
 	 */
-	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0];
 	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
@@ -3586,26 +3738,20 @@
 	 */
 	if (ctx->ctx_fl_system) {
 
-
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 0;
-		local_cpu_data->pfm_dcr_pp    = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE);
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE);
 	} else  {
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		/* no more save/restore on ctxsw */
@@ -3637,8 +3783,7 @@
 	 * This destroys the overflow information. This is required to make sure
 	 * next process does not start with monitoring on if not requested
 	 */
-	ia64_set_pmc(0, 1);
-	ia64_srlz_d();
+	pfm_freeze_pmu();
 
 	/*
 	 * We don't need to restore psr, because we are on our way out
@@ -3670,10 +3815,14 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
+			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", 
+				task->pid, 
+				i, 
+				ctx->ctx_soft_pmds[i].val, 
+				val & pmu_conf.ovfl_val));
 
 			/* collect latest results */
-			ctx->ctx_soft_pmds[i].val += val & pmu_conf.perf_ovfl_val;
+			ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val;
 
 			/*
 			 * now everything is in ctx_soft_pmds[] and we need
@@ -3686,7 +3835,7 @@
 			 * take care of overflow inline
 			 */
 			if (pmc0 & (1UL << i)) {
-				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
+				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
@@ -3820,18 +3969,12 @@
 	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
 		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
-			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val;
+		} else {
+			thread->pmd[i]	      	   = 0UL; /* reset to initial state */
 		}
-		/* what about the other pmds? zero or keep as is */
-
 	}
-	/*
-	 * clear BTB index register
-	 * XXX: CPU-model specific knowledge!
-	 */
-	thread->pmd[16] = 0;
-
 
 	nctx->ctx_fl_frozen    = 0;
 	nctx->ctx_ovfl_regs[0] = 0UL;
@@ -3866,6 +4009,11 @@
 
 	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
 
+	/*
+	 * propagate kernel psr in new context (used for first ctxsw in
+	 */
+	nctx->ctx_saved_psr = pfm_get_psr();
+
 	/* link with new task */
 	thread->pfm_context = nctx;
 
@@ -3994,31 +4142,15 @@
 
 	UNLOCK_CTX(ctx);
 
-	LOCK_PFS();
+	pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu);
 
 	if (ctx->ctx_fl_system) {
-
-		pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-		DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu));
-
-		/* update perfmon debug register usage counter */
-		if (ctx->ctx_fl_using_dbreg) {
-			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
-				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
-			} else
-				pfm_sessions.pfs_sys_use_dbregs--;
-		}
-
 		/*
 	 	 * remove any CPU pinning
 	 	 */
 		task->cpus_allowed = ctx->ctx_saved_cpus_allowed;
 		task->need_resched = 1;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
-	UNLOCK_PFS();
+	} 
 
 	pfm_context_free(ctx);
 	/* 
@@ -4178,125 +4310,165 @@
 }
 
 static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"perfmon"
+	.handler = pfm_interrupt_handler,
+	.flags   = SA_INTERRUPT,
+	.name    = "perfmon"
 };
 
-
-static void
-pfm_pmu_snapshot(void)
+int
+pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
 {
-	int i;
+	int ret;
+
+	/* some sanity checks */
+	if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
+
+	/* do the easy test first */
+	if (pfm_alternate_intr_handler) return -EBUSY;
 
-	for (i=0; i < IA64_NUM_PMC_REGS; i++) {
-		if (i >= pmu_conf.num_pmcs) break;
-		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
+	/* reserve our session */
+	ret = pfm_reserve_session(NULL, 1, cpu_online_map);
+	if (ret) return ret;
+
+	if (pfm_alternate_intr_handler) {
+		printk("perfmon: install_alternate, intr_handler not NULL after reserve\n");
+		return -EINVAL;
 	}
-#ifdef CONFIG_MCKINLEY
-	/*
-	 * set the 'stupid' enable bit to power the PMU!
+
+	pfm_alternate_intr_handler = hdl;
+
+	return 0;
+}
+
+int
+pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
+{
+	if (hdl == NULL) return -EINVAL;
+
+	/* cannot remove someone else's handler! */
+	if (pfm_alternate_intr_handler != hdl) return -EINVAL;
+
+	pfm_alternate_intr_handler = NULL;
+
+	/* 
+	 * XXX: assume cpu_online_map has not changed since reservation 
 	 */
-	reset_pmcs[4] |= 1UL << 23;
-#endif
+	pfm_unreserve_session(NULL, 1, cpu_online_map);
+
+	return 0;
 }
 
 /*
  * perfmon initialization routine, called from the initcall() table
  */
 int __init
-perfmon_init (void)
+pfm_init(void)
 {
-	pal_perf_mon_info_u_t pm_info;
-	s64 status;
+	unsigned int n, n_counters, i;
 
-	pmu_conf.pfm_is_disabled = 1;
+	pmu_conf.disabled = 1;
 
-	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
+	printk("perfmon: version %u.%u IRQ %u\n", 
 		PFM_VERSION_MAJ, 
 		PFM_VERSION_MIN, 
-		PFM_SMPL_VERSION_MAJ, 
-		PFM_SMPL_VERSION_MIN, 
 		IA64_PERFMON_VECTOR);
 
-	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
-		printk("perfmon: PAL call failed (%ld), perfmon disabled\n", status);
-		return -1;
-	}
-
-	pmu_conf.perf_ovfl_val = (1UL << pm_info.pal_perf_mon_info_s.width) - 1;
-	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
-	pmu_conf.num_pmcs      = find_num_pm_regs(pmu_conf.impl_regs);
-	pmu_conf.num_pmds      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
-
-	printk("perfmon: %u bits counters\n", pm_info.pal_perf_mon_info_s.width);
-
-	printk("perfmon: %lu PMC/PMD pairs, %lu PMCs, %lu PMDs\n", 
-	       pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
+	/*
+	 * compute the number of implemented PMD/PMC from the
+	 * description tables
+	 */
+	n = 0;
+	for (i=0; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63);
+		n++;
+	}
+	pmu_conf.num_pmcs = n;
+
+	n = 0; n_counters = 0;
+	for (i=0; PMD_IS_LAST(i) == 0;  i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63);
+		n++;
+		if (PMD_IS_COUNTING(i)) n_counters++;
+	}
+	pmu_conf.num_pmds      = n;
+	pmu_conf.num_counters  = n_counters;
+
+	printk("perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", 
+	       pmu_conf.num_pmcs, 
+	       pmu_conf.num_pmds,
+	       pmu_conf.num_counters,
+	       ffz(pmu_conf.ovfl_val));
 
 	/* sanity check */
 	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
-		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon is DISABLED\n");
-		return -1; /* no need to continue anyway */
-	}
-
-	if (ia64_pal_debug_info(&pmu_conf.num_ibrs, &pmu_conf.num_dbrs)) {
-		printk(KERN_WARNING "perfmon: unable to get number of debug registers\n");
-		pmu_conf.num_ibrs = pmu_conf.num_dbrs = 0;
+		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
+		return -1;
 	}
-	/* PAL reports the number of pairs */
-	pmu_conf.num_ibrs <<=1;
-	pmu_conf.num_dbrs <<=1;
 
 	/*
-	 * take a snapshot of all PMU registers. PAL is supposed
-	 * to configure them with stable/safe values, i.e., not
-	 * capturing anything.
-	 * We take a snapshot now, before we make any modifications. This
-	 * will become our master copy. Then we will reuse the snapshot
-	 * to reset the PMU in pfm_enable(). Using this technique, perfmon
-	 * does NOT have to know about the specific values to program for
-	 * the PMC/PMD. The safe values may be different from one CPU model to
-	 * the other.
+	 * for now here for debug purposes
 	 */
-	pfm_pmu_snapshot();
+	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
+	if (perfmon_dir == NULL) {
+		printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
+		return -1; 
+	}
 
 	/*
-	 * setup the register configuration descriptions for the CPU
+	 * create /proc/sys/kernel/perfmon
 	 */
-	pmu_conf.pmc_desc = pmc_desc;
-	pmu_conf.pmd_desc = pmd_desc;
-
-	/* we are all set */
-	pmu_conf.pfm_is_disabled = 0;
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
 
 	/*
-	 * for now here for debug purposes
+	 * initialize all our spinlocks
 	 */
-	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
-
-	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
-
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
+	/* we are all set */
+	pmu_conf.disabled = 0;
+
 	return 0;
 }
 
-__initcall(perfmon_init);
+__initcall(pfm_init);
 
 void
-perfmon_init_percpu (void)
+pfm_init_percpu(void)
 {
+	int i;
+
 	if (smp_processor_id() == 0)
 		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
 
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
+
+	/*
+	 * we first initialize the PMU to a stable state.
+	 * the values may have been changed from their power-up
+	 * values by software executed before the kernel took over.
+	 *
+	 * At this point, pmu_conf has not yet been initialized
+	 *
+	 * On McKinley, this code is ineffective until PMC4 is initialized.
+	 */
+	for (i=1; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+	}
+
+	for (i=0; PMD_IS_LAST(i); i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		ia64_set_pmd(i, 0UL);
+	}
+	pfm_freeze_pmu();
 }
 
 #else /* !CONFIG_PERFMON */
 
-asmlinkage int
+asmlinkage long
 sys_perfmonctl (int pid, int cmd, void *req, int count, long arg5, long arg6, 
 		long arg7, long arg8, long stack)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_generic.h linux-2.4.21-rc3/arch/ia64/kernel/perfmon_generic.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_generic.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/perfmon_generic.h	2003-05-22 22:06:26.000000000 +0000
@@ -1,29 +1,48 @@
+/*
+ * This file contains the architected PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
 #define RDEP(x)	(1UL<<(x))
 
-#ifdef CONFIG_ITANIUM
-#error "This file should not be used when CONFIG_ITANIUM is defined"
+#if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY)
+#error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined"
 #endif
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd1  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd2  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd3  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd1  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd2  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd3  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_gen_pmd_desc,
+	pmc_desc:	pfm_gen_pmc_desc
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h linux-2.4.21-rc3/arch/ia64/kernel/perfmon_itanium.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/perfmon_itanium.h	2003-05-22 22:06:24.000000000 +0000
@@ -15,46 +15,59 @@
 static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_ita_pmd_desc,
+	pmc_desc:	pfm_ita_pmc_desc
+};
+
+
 static int
 pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.21-rc3/arch/ia64/kernel/perfmon_mckinley.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/perfmon_mckinley.h	2003-05-22 22:06:39.000000000 +0000
@@ -12,51 +12,86 @@
 #error "This file is only valid when CONFIG_MCKINLEY is defined"
 #endif
 
+static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL,  pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL,  pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG  , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG  , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 47) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_mck_pmd_desc,
+	pmc_desc:	pfm_mck_pmc_desc
+};
+
+
+/*
+ * PMC reserved fields must have their power-up values preserved
+ */
+static int
+pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	unsigned long tmp1, tmp2, ival = *val;
+
+	/* remove reserved areas from user value */
+	tmp1 = ival & PMC_RSVD_MASK(cnum);
+
+	/* get reserved fields values */
+	tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+
+	*val = tmp1 | tmp2;
+
+	DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", 
+		  cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); 
+	return 0;
+}
+
 static int
 pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
@@ -65,6 +100,9 @@
 	int ret = 0, check_case1 = 0;
 	unsigned long val8 = 0, val14 = 0, val13 = 0;
 
+	/* first preserve the reserved fields */
+	pfm_mck_reserved(task, cnum, val, regs);
+
 	/*
 	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
 	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
@@ -105,8 +143,11 @@
 		case  8: val8 = *val;
 			 val13 = th->pmc[13];
 			 val14 = th->pmc[14];
+			 *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 check_case1 = 1;
 			 break;
+		case  9: *val |= 1UL << 2; /* bit 2 must always be 1 */
+			 break;
 		case 13: val8  = th->pmc[8];
 			 val13 = *val;
 			 val14 = th->pmc[14];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/process.c linux-2.4.21-rc3/arch/ia64/kernel/process.c
--- linux-2.4.20/arch/ia64/kernel/process.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/process.c	2003-05-22 22:06:43.000000000 +0000
@@ -161,6 +161,10 @@
 void
 ia64_save_extra (struct task_struct *task)
 {
+#ifdef CONFIG_PERFMON
+	unsigned long info;
+#endif
+
 	if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
 		ia64_save_debug_regs(&task->thread.dbr[0]);
 
@@ -168,10 +172,9 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_save_regs(task);
 
-# ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide)
-		pfm_syst_wide_update_task(task, 0);
-# endif
+	info = local_cpu_data->pfm_syst_info;
+	if (info & PFM_CPUINFO_SYST_WIDE)
+		pfm_syst_wide_update_task(task, info, 0);
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -183,6 +186,10 @@
 void
 ia64_load_extra (struct task_struct *task)
 {
+#ifdef CONFIG_PERFMON
+	unsigned long info;
+#endif
+
 	if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
 		ia64_load_debug_regs(&task->thread.dbr[0]);
 
@@ -190,10 +197,9 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_load_regs(task);
 
-# ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide)
-		pfm_syst_wide_update_task(task, 1);
-# endif
+	info = local_cpu_data->pfm_syst_info;
+	if (info & PFM_CPUINFO_SYST_WIDE)
+		pfm_syst_wide_update_task(task, info, 1);
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -224,7 +230,7 @@
  *	|                     | <-- sp (lowest addr)
  *	+---------------------+
  *
- * Note: if we get called through kernel_thread() then the memory
+ * Note: if we get called through arch_kernel_thread() then the memory
  * above "(highest addr)" is valid kernel stack memory that needs to
  * be copied as well.
  *
@@ -479,7 +485,7 @@
 }
 
 pid_t
-kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
+arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
 {
 	struct task_struct *parent = current;
 	int result, tid;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ptrace.c linux-2.4.21-rc3/arch/ia64/kernel/ptrace.c
--- linux-2.4.20/arch/ia64/kernel/ptrace.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/ptrace.c	2003-05-22 22:06:53.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
@@ -459,6 +460,60 @@
 	pt->loadrs = 0;
 }
 
+static inline void
+sync_user_rbs_one_thread (struct task_struct *p, int make_writable)
+{
+	struct switch_stack *sw;
+	unsigned long urbs_end;
+	struct pt_regs *pt;
+
+	sw = (struct switch_stack *) (p->thread.ksp + 16);
+	pt = ia64_task_regs(p);
+	urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
+	ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
+	if (make_writable)
+		user_flushrs(p, pt);
+}
+
+struct task_list {
+	struct task_list *next;
+	struct task_struct *task;
+};
+
+#ifdef CONFIG_SMP
+
+static inline void
+collect_task (struct task_list **listp, struct task_struct *p, int make_writable)
+{
+	struct task_list *e;
+
+	e = kmalloc(sizeof(*e), GFP_KERNEL);
+	if (!e)
+		/* oops, can't collect more: finish at least what we collected so far... */
+		return;
+
+	get_task_struct(p);
+	e->task = p;
+	e->next = *listp;
+	*listp = e;
+}
+
+static inline struct task_list *
+finish_task (struct task_list *list, int make_writable)
+{
+	struct task_list *next = list->next;
+
+	sync_user_rbs_one_thread(list->task, make_writable);
+	free_task_struct(list->task);
+	kfree(list);
+	return next;
+}
+
+#else
+# define collect_task(list, p, make_writable)	sync_user_rbs_one_thread(p, make_writable)
+# define finish_task(list, make_writable)	(NULL)
+#endif
+
 /*
  * Synchronize the RSE backing store of CHILD and all tasks that share the address space
  * with it.  CHILD_URBS_END is the address of the end of the register backing store of
@@ -472,7 +527,6 @@
 threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable)
 {
 	struct switch_stack *sw;
-	unsigned long urbs_end;
 	struct task_struct *p;
 	struct mm_struct *mm;
 	struct pt_regs *pt;
@@ -492,20 +546,27 @@
 		if (make_writable)
 			user_flushrs(child, pt);
 	} else {
+		/*
+		 * Note: we can't call ia64_sync_user_rbs() while holding the
+		 * tasklist_lock because that may cause a dead-lock: ia64_sync_user_rbs()
+		 * may indirectly call tlb_flush_all(), which triggers an IPI.
+		 * Furthermore, tasklist_lock is acquired by fork() with interrupts
+		 * disabled, so with the right timing, the IPI never completes, hence
+		 * tasklist_lock never gets released, hence fork() never completes...
+		 */
+		struct task_list *list = NULL;
+
 		read_lock(&tasklist_lock);
 		{
 			for_each_task(p) {
-				if (p->mm == mm && p->state != TASK_RUNNING) {
-					sw = (struct switch_stack *) (p->thread.ksp + 16);
-					pt = ia64_task_regs(p);
-					urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
-					ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
-					if (make_writable)
-						user_flushrs(p, pt);
-				}
+				if (p->mm == mm && p->state != TASK_RUNNING)
+					collect_task(&list, p, make_writable);
 			}
 		}
 		read_unlock(&tasklist_lock);
+
+		while (list)
+			list = finish_task(list, make_writable);
 	}
 	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;	/* set the flag in the child thread only */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/setup.c linux-2.4.21-rc3/arch/ia64/kernel/setup.c
--- linux-2.4.20/arch/ia64/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/setup.c	2003-05-22 22:06:27.000000000 +0000
@@ -65,6 +65,8 @@
 struct screen_info screen_info;
 
 unsigned long ia64_iobase;	/* virtual address for I/O accesses */
+struct io_space io_space[MAX_IO_SPACES];
+unsigned int num_io_spaces;
 
 unsigned char aux_device_present = 0xaa;        /* XXX remove this when legacy I/O is gone */
 
@@ -338,6 +340,11 @@
 	}
 	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
 
+	/* setup legacy IO port space */
+	io_space[0].mmio_base = ia64_iobase;
+	io_space[0].sparse = 1;
+	num_io_spaces = 1;
+
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/signal.c linux-2.4.21-rc3/arch/ia64/kernel/signal.c
--- linux-2.4.20/arch/ia64/kernel/signal.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/signal.c	2003-05-22 22:06:48.000000000 +0000
@@ -41,6 +41,16 @@
 
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 long
 ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
 {
@@ -354,6 +364,15 @@
 	return err;
 }
 
+/*
+ * Check whether the register-backing store is already on the signal stack.
+ */
+static inline int
+rbs_on_sig_stack (unsigned long bsp)
+{
+	return (bsp - current->sas_ss_sp < current->sas_ss_size);
+}
+
 static long
 setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
 	     struct sigscratch *scr)
@@ -366,10 +385,16 @@
 
 	frame = (void *) scr->pt.r12;
 	tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
-	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) {
-		new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
+	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
 		frame = (void *) ((current->sas_ss_sp + current->sas_ss_size)
 				  & ~(STACK_ALIGN - 1));
+  		/*
+		 * We need to check for the register stack being on the signal stack
+		 * separately, because it's switched separately (memory stack is switched
+		 * in the kernel, register stack is switched in the signal trampoline).
+  		 */
+		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
+			new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
 	}
 	frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smp.c linux-2.4.21-rc3/arch/ia64/kernel/smp.c
--- linux-2.4.20/arch/ia64/kernel/smp.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/smp.c	2003-05-22 22:06:53.000000000 +0000
@@ -188,8 +188,20 @@
 void
 smp_flush_tlb_all (void)
 {
-	smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1);
-	__flush_tlb_all();
+	smp_call_function((void (*)(void *))local_flush_tlb_all, 0, 1, 1);
+	local_flush_tlb_all();
+}
+
+void
+smp_flush_tlb_mm (struct mm_struct *mm)
+{
+	local_flush_tlb_mm(mm);
+
+	/* this happens for the common case of a single-threaded fork():  */
+	if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
+		return;
+
+	smp_call_function((void (*)(void *))local_flush_tlb_mm, mm, 1, 1);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smpboot.c linux-2.4.21-rc3/arch/ia64/kernel/smpboot.c
--- linux-2.4.20/arch/ia64/kernel/smpboot.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/smpboot.c	2003-05-22 22:06:38.000000000 +0000
@@ -89,7 +89,7 @@
 struct smp_boot_data smp_boot_data __initdata;
 
 /* Set when the idlers are all forked */
-volatile int smp_threads_ready;
+int smp_threads_ready;
 
 unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */
 
@@ -321,7 +321,7 @@
 	extern void ia64_init_itm(void);
 
 #ifdef CONFIG_PERFMON
-	extern void perfmon_init_percpu(void);
+	extern void pfm_init_percpu(void);
 #endif
 
 	cpuid = smp_processor_id();
@@ -356,7 +356,7 @@
 #endif
 
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 
 	local_irq_enable();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/sys_ia64.c linux-2.4.21-rc3/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.20/arch/ia64/kernel/sys_ia64.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/sys_ia64.c	2003-05-22 22:06:48.000000000 +0000
@@ -253,6 +253,29 @@
 	return addr;
 }
 
+asmlinkage unsigned long
+ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
+	     unsigned long new_addr)
+{
+	extern unsigned long do_mremap (unsigned long addr,
+					unsigned long old_len,
+					unsigned long new_len,
+					unsigned long flags,
+					unsigned long new_addr);
+
+	down_write(&current->mm->mmap_sem);
+	{
+		addr = do_mremap(addr, old_len, new_len, flags, new_addr);
+	}
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *) addr))
+		return addr;
+
+	force_successful_syscall_return();
+	return addr;
+}
+
 asmlinkage long
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/traps.c linux-2.4.21-rc3/arch/ia64/kernel/traps.c
--- linux-2.4.20/arch/ia64/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/traps.c	2003-05-22 22:06:52.000000000 +0000
@@ -142,7 +142,8 @@
 	siginfo.si_isr = 0;
 
 	switch (break_num) {
-	      case 0: /* unknown error */
+	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+		die_if_kernel("Bad break", regs, break_num);
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/unaligned.c linux-2.4.21-rc3/arch/ia64/kernel/unaligned.c
--- linux-2.4.20/arch/ia64/kernel/unaligned.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/unaligned.c	2003-05-22 22:06:52.000000000 +0000
@@ -5,6 +5,10 @@
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 2002/12/09   Fix rotating register handling (off-by-1 error, missing fr-rotation).  Fix
+ *		get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
+ *		stacked register returns an undefined value; it does NOT trigger a
+ *		"rsvd register fault").
  * 2001/10/11	Fix unaligned access to rotating registers in s/w pipelined loops.
  * 2001/08/13	Correct size of extended floats (float_fsz) from 16 to 10 bytes.
  * 2001/01/17	Add support emulation of unaligned kernel accesses.
@@ -275,6 +279,15 @@
 #	undef F
 }
 
+static inline unsigned long
+rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+	reg += rrb;
+	if (reg >= sor)
+		reg -= sor;
+	return reg;
+}
+
 static void
 set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
 {
@@ -286,26 +299,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
-
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
-
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) >= sof) {
+	if (ridx >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
 		DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
 		return;
 	}
 
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
+
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -333,7 +342,7 @@
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -367,26 +376,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
+	if (ridx >= sof) {
+		/* read of out-of-frame register returns an undefined value; 0 in our case.  */
+		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+		goto fail;
+	}
+
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
 
 	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
 	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
-	if ((r1 - 32) >= sof) {
-		/* this should never happen, as the "rsvd register fault" has higher priority */
-		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
-		return;
-	}
-
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		*val = *addr;
@@ -406,13 +411,13 @@
 	 */
 	if (regs->r12 >= TASK_SIZE) {
 		DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
-		return;
+		goto fail;
 	}
 
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -427,6 +432,13 @@
 		ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 		*nat = (rnats & nat_mask) != 0;
 	}
+	return;
+
+  fail:
+	*val = 0;
+	if (nat)
+		*nat = 0;
+	return;
 }
 
 
@@ -485,7 +497,16 @@
 	DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
 }
 
-#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
+/*
+ * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
+ * range from 32-127, result is in the range from 0-95.
+ */
+static inline unsigned long
+fph_index (struct pt_regs *regs, long regnum)
+{
+	unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+	return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
 
 static void
 setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
@@ -506,7 +527,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_sync_fph(current);
-		current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
+		current->thread.fph[fph_index(regs, regnum)] = *fpval;
 	} else {
 		/*
 		 * pt_regs or switch_stack ?
@@ -565,7 +586,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_flush_fph(current);
-		*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
+		*fpval = current->thread.fph[fph_index(regs, regnum)];
 	} else {
 		/*
 		 * f0 = 0.0, f1= 1.0. Those registers are constant and are thus
@@ -650,8 +671,8 @@
 	 * just in case.
 	 */
 	if (ld.x6_op == 1 || ld.x6_op == 3) {
-		printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
-		die_if_kernel("unaligned reference on specualtive load with register update\n",
+		printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
+		die_if_kernel("unaligned reference on speculative load with register update\n",
 			      regs, 30);
 	}
 
@@ -1080,8 +1101,8 @@
 		 * For this reason we keep this sanity check
 		 */
 		if (ld.x6_op == 1 || ld.x6_op == 3)
-			printk("%s %s: register update on speculative load pair, "
-			       "error\n",KERN_ERR, __FUNCTION__);
+			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+			       __FUNCTION__);
 
 		setreg(ld.r3, ifa, 0, regs);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/unwind.c linux-2.4.21-rc3/arch/ia64/kernel/unwind.c
--- linux-2.4.20/arch/ia64/kernel/unwind.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/kernel/unwind.c	2003-05-22 22:06:47.000000000 +0000
@@ -1997,16 +1997,18 @@
 {
 	extern char __start_gate_section[], __stop_gate_section[];
 	unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base;
-	const struct unw_table_entry *entry, *first;
+	const struct unw_table_entry *entry, *first, *unw_table_end;
+	extern int ia64_unw_end;
 	size_t info_size, size;
 	char *info;
 
 	start = (unsigned long) __start_gate_section - segbase;
 	end   = (unsigned long) __stop_gate_section - segbase;
+	unw_table_end = (struct unw_table_entry *) &ia64_unw_end;
 	size  = 0;
 	first = lookup(&unw.kernel_table, start);
 
-	for (entry = first; entry->start_offset < end; ++entry)
+	for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry)
 		size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
 	size += 8;	/* reserve space for "end of table" marker */
 
@@ -2021,7 +2023,7 @@
 	lp = unw.gate_table;
 	info = (char *) unw.gate_table + size;
 
-	for (entry = first; entry->start_offset < end; ++entry, lp += 3) {
+	for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry, lp += 3) {
 		info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
 		info -= info_size;
 		memcpy(info, (char *) segbase + entry->info_offset, info_size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/Makefile linux-2.4.21-rc3/arch/ia64/lib/Makefile
--- linux-2.4.20/arch/ia64/lib/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/lib/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -11,7 +11,7 @@
 
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o					\
+	carta_random.o checksum.o clear_page.o csum_partial_copy.o					\
 	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o			\
 	flush.o ip_fast_csum.o io.o do_csum.o						\
 	memset.o strlen.o swiotlb.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/carta_random.S linux-2.4.21-rc3/arch/ia64/lib/carta_random.S
--- linux-2.4.20/arch/ia64/lib/carta_random.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/lib/carta_random.S	2003-05-22 22:06:53.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ * Fast, simple, yet decent quality random number generator based on
+ * a paper by David G. Carta ("Two Fast Implementations of the
+ * `Minimal Standard' Random Number Generator," Communications of the
+ * ACM, January, 1990).
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <asm/asmmacro.h>
+
+#define a	r2
+#define m	r3
+#define lo	r8
+#define hi	r9
+#define t0	r16
+#define t1	r17
+#define	seed	r32
+
+GLOBAL_ENTRY(carta_random32)
+	movl	a = (16807 << 16) | 16807
+	;;
+	pmpyshr2.u t0 = a, seed, 0
+	pmpyshr2.u t1 = a, seed, 16
+	;;
+	unpack2.l t0 = t1, t0
+	dep	m = -1, r0, 0, 31
+	;;
+	zxt4	lo = t0
+	shr.u	hi = t0, 32
+	;;
+	dep	t0 = 0, hi, 15, 49	// t0 = (hi & 0x7fff)
+	;;
+	shl	t0 = t0, 16		// t0 = (hi & 0x7fff) << 16
+	shr	t1 = hi, 15		// t1 = (hi >> 15)
+	;;
+	add	lo = lo, t0
+	;;
+	cmp.gtu	p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	;;
+	add	lo = lo, t1
+	;;
+	cmp.gtu p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	br.ret.sptk.many rp
+END(carta_random32)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/memcpy_mck.S linux-2.4.21-rc3/arch/ia64/lib/memcpy_mck.S
--- linux-2.4.20/arch/ia64/lib/memcpy_mck.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/lib/memcpy_mck.S	2003-05-22 22:06:39.000000000 +0000
@@ -6,7 +6,10 @@
  *	in1:	source address
  *	in2:	number of bytes to copy
  * Output:
- * 	0 if success, or number of byte NOT copied if error occurred.
+ *	for bcopy:     return nothing
+ *	for memcpy:    return dest
+ * 	for copy_user: 0 if success,
+ *		       or number of bytes NOT copied if error occurred.
  *
  * Copyright (C) 2002 Intel Corp.
  * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
@@ -21,15 +24,6 @@
 # define EK(y,x...)	x
 #endif
 
-GLOBAL_ENTRY(bcopy)
-	.regstk 3,0,0,0
-	mov r8=in0
-	mov in0=in1
-	;;
-	mov in1=r8
-	;;
-END(bcopy)
-
 /* McKinley specific optimization */
 
 #define retval		r8
@@ -82,10 +76,19 @@
 #define in1		r33
 #define in2		r34
 
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0		// swap the src and dest arguments
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)			// fall through to memcpy
 GLOBAL_ENTRY(memcpy)
 	and	r28=0x7,in0
 	and	r29=0x7,in1
 	mov	f6=f0
+	mov	retval=in0
 	br.cond.sptk .common_code
 	;;
 END(memcpy)
@@ -97,7 +100,7 @@
 	mov	f6=f1
 	mov	saved_in0=in0	// save dest pointer
 	mov	saved_in1=in1	// save src pointer
-	mov	saved_in2=in2	// save len
+	mov	retval=r0	// initialize return value
 	;;
 .common_code:
 	cmp.gt	p15,p0=8,in2	// check for small size
@@ -105,7 +108,7 @@
 	cmp.ne	p14,p0=0,r29	// check src alignment
 	add	src0=0,in1
 	sub	r30=8,r28	// for .align_dest
-	mov	retval=r0	// initialize return value
+	mov	saved_in2=in2	// save len
 	;;
 	add	dst0=0,in0
 	add	dst1=1,in0	// dest odd index
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/swiotlb.c linux-2.4.21-rc3/arch/ia64/lib/swiotlb.c
--- linux-2.4.20/arch/ia64/lib/swiotlb.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/lib/swiotlb.c	2003-05-22 22:06:50.000000000 +0000
@@ -351,7 +351,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -417,23 +417,23 @@
 int
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
-	void *addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
-		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
-			if (sg->address)
-				sg->address = addr;
-			else {
-				sg->page = virt_to_page(addr);
-				sg->offset = (u64) addr & ~PAGE_MASK;
-			}
-		}
+		void * virt_address = SG_ENT_VIRT_ADDRESS(sg);
+		unsigned long phys_address = virt_to_phys(virt_address);
+
+		sg->dma_length = sg->length;
+		if (phys_address & ~hwdev->dma_mask)
+			sg->dma_address = virt_to_phys(map_single(hwdev,
+			                                          virt_address,
+			                                          sg->length,
+			                                          direction));
+		else
+			sg->dma_address = phys_address;
 	}
 	return nelems;
 }
@@ -451,14 +451,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
-			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-			if (sg->address)
-				sg->address = sg->orig_address;
-			else {
-				sg->page = virt_to_page(sg->orig_address);
-				sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
-			}
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg))) {
+			unmap_single(hwdev, phys_to_virt(sg->dma_address),
+			             sg->dma_length, direction);
 		} else if (direction == PCI_DMA_FROMDEVICE)
 			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
 }
@@ -479,14 +474,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
-			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-}
-
-unsigned long
-swiotlb_dma_address (struct scatterlist *sg)
-{
-	return SG_ENT_PHYS_ADDRESS(sg);
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg)))
+			sync_single(hwdev, phys_to_virt(sg->dma_address),
+			            sg->dma_length, direction);
 }
 
 /*
@@ -507,7 +497,6 @@
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 EXPORT_SYMBOL(swiotlb_sync_single);
 EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
 EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/Makefile linux-2.4.21-rc3/arch/ia64/mm/Makefile
--- linux-2.4.20/arch/ia64/mm/Makefile	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/mm/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -9,6 +9,8 @@
 
 O_TARGET := mm.o
 
+export-objs := init.o
+
 obj-y	 := init.o fault.o tlb.o extable.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/fault.c linux-2.4.21-rc3/arch/ia64/mm/fault.c
--- linux-2.4.20/arch/ia64/mm/fault.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/mm/fault.c	2003-05-22 22:06:52.000000000 +0000
@@ -58,7 +58,6 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 	/*
 	 * If fault is in region 5 and we are in the kernel, we may already
          * have the mmap_sem (VALID_PAGE macro is called during mmap). There
@@ -67,7 +66,6 @@
   	 */
 	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
 		goto bad_area_no_up;
-#endif
 
 	down_read(&mm->mmap_sem);
 
@@ -148,9 +146,7 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
-#ifdef CONFIG_VIRTUAL_MEM_MAP
   bad_area_no_up:
-#endif
 	if ((isr & IA64_ISR_SP)
 	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/init.c linux-2.4.21-rc3/arch/ia64/mm/init.c
--- linux-2.4.20/arch/ia64/mm/init.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/mm/init.c	2003-05-22 22:06:42.000000000 +0000
@@ -5,6 +5,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 
@@ -35,15 +36,14 @@
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
+#define LARGE_GAP 0x40000000 /* Use virtual mem map if a hole is > than this */
 
 static unsigned long totalram_pages;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 unsigned long vmalloc_end = VMALLOC_END_INIT;
 
 static struct page *vmem_map;
 static unsigned long num_dma_physpages;
-#endif
 
 int
 do_check_pgt_cache (int low, int high)
@@ -114,8 +114,8 @@
 
 	addr = (unsigned long) &__init_begin;
 	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
-		clear_bit(PG_reserved, &virt_to_page(addr)->flags);
-		set_page_count(virt_to_page(addr), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)addr)->flags);
+		set_page_count(virt_to_page((void *)addr), 1);
 		free_page(addr);
 		++totalram_pages;
 	}
@@ -164,10 +164,10 @@
 		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
-		if (!VALID_PAGE(virt_to_page(start)))
+		if (!VALID_PAGE(virt_to_page((void *)start)))
 			continue;
-		clear_bit(PG_reserved, &virt_to_page(start)->flags);
-		set_page_count(virt_to_page(start), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)start)->flags);
+		set_page_count(virt_to_page((void *)start), 1);
 		free_page(start);
 		++totalram_pages;
 	}
@@ -357,10 +357,6 @@
 	ia64_tlb_init();
 }
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
-#include <asm/pgtable.h>
-
 static int
 create_mem_map_page_table (u64 start, u64 end, void *arg)
 {
@@ -413,8 +409,8 @@
 
 	/* Should we use platform_map_nr here? */
 
-	map_start = vmem_map + MAP_NR_DENSE(start);
-	map_end   = vmem_map + MAP_NR_DENSE(end);
+	map_start = mem_map + MAP_NR_DENSE(start);
+	map_end   = mem_map + MAP_NR_DENSE(end);
 
 	if (map_start < args->start)
 		map_start = args->start;
@@ -444,15 +440,19 @@
 arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start,
 	struct page *end, int zone, unsigned long start_paddr, int highmem)
 {
-	struct memmap_init_callback_data args;
+	if (!vmem_map) 
+		memmap_init(start,end,zone,page_to_phys(start),highmem);
+	else {
+		struct memmap_init_callback_data args;
 
-	args.memmap_init = memmap_init;
-	args.start = start;
-	args.end = end;
-	args.zone = zone;
-	args.highmem = highmem;
+		args.memmap_init = memmap_init;
+		args.start = start;
+		args.end = end;
+		args.zone = zone;
+		args.highmem = highmem;
 
-	efi_memmap_walk(virtual_memmap_init, &args);
+		efi_memmap_walk(virtual_memmap_init, &args);
+	}
 
 	return page_to_phys(end);
 }
@@ -475,8 +475,6 @@
 	return __get_user(byte, (char *) page) == 0;
 }
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 static int
 count_pages (u64 start, u64 end, void *arg)
 {
@@ -486,47 +484,75 @@
 	return 0;
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+static int
+find_largest_hole(u64 start, u64 end, void *arg)
+{
+	u64 *max_gap = arg;
+	static u64 last_end = PAGE_OFFSET;
+
+	/* NOTE: this algorithm assumes efi memmap table is ordered */
+
+	if (*max_gap < (start - last_end))
+		*max_gap = start - last_end;
+	last_end = end;
+	return 0;
+}
+#endif
+
 /*
  * Set up the page tables.
  */
 void
 paging_init (void)
 {
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+	unsigned long zholes_size[MAX_NR_ZONES];
+#ifndef CONFIG_DISCONTIGMEM
+	unsigned long max_gap;
+#endif
 
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
+	memset(zholes_size, 0, sizeof(zholes_size));
 
 	num_physpages = 0;
 	efi_memmap_walk(count_pages, &num_physpages);
 
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-	{
-		unsigned long zholes_size[MAX_NR_ZONES];
-		unsigned long map_size;
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-		memset(zholes_size, 0, sizeof(zholes_size));
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] = (max_low_pfn - max_dma)
+					- (num_physpages - num_dma_physpages);
+		}
+	}
 
-		num_dma_physpages = 0;
-		efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+#ifdef CONFIG_DISCONTIGMEM
+	free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+#else
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
 
-		if (max_low_pfn < max_dma) {
-			zones_size[ZONE_DMA] = max_low_pfn;
-			zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
-		} else {
-			zones_size[ZONE_DMA] = max_dma;
-			zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
-			if (num_physpages > num_dma_physpages) {
-				zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-				zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
-							    - (num_physpages - num_dma_physpages));
-			}
-		}
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *)0;
+		free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+	}
+	else {
+		unsigned long map_size;
 
-		/* allocate virtual mem_map: */
+		/* allocate virtual mem_map */
 
 		map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page));
 		vmalloc_end -= map_size;
@@ -536,15 +562,7 @@
 		free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size);
 		printk("Virtual mem_map starts at 0x%p\n", mem_map);
 	}
-#else /* !CONFIG_VIRTUAL_MEM_MAP */
-	if (max_low_pfn < max_dma)
-		zones_size[ZONE_DMA] = max_low_pfn;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-	}
-	free_area_init(zones_size);
-#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+#endif
 }
 
 static int
@@ -554,7 +572,7 @@
 	unsigned long *count = arg;
 	struct page *pg;
 
-	for (pg = virt_to_page(start); pg < virt_to_page(end); ++pg)
+	for (pg = virt_to_page((void *)start); pg < virt_to_page((void *)end); ++pg)
 		if (PageReserved(pg))
 			++num_reserved;
 	*count += num_reserved;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/tlb.c linux-2.4.21-rc3/arch/ia64/mm/tlb.c
--- linux-2.4.20/arch/ia64/mm/tlb.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/mm/tlb.c	2003-05-22 22:06:50.000000000 +0000
@@ -100,7 +100,7 @@
 }
 
 void
-__flush_tlb_all (void)
+local_flush_tlb_all (void)
 {
 	unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
 
@@ -185,5 +185,5 @@
 	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
 	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
-	__flush_tlb_all();		/* nuke left overs from bootstrapping... */
+	local_flush_tlb_all();		/* nuke left overs from bootstrapping... */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,777 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
-# CONFIG_LNE390 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,772 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
-# CONFIG_LNE390 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-dig-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-dig-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-dig-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-dig-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-generic-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-generic-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Simulated drivers
-#
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-generic-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-generic-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Simulated drivers
-#
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-hp-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-hp-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-hp-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-hp-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,334 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-CONFIG_IA64_HP_SIM=y
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_NFS_FS is not set
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Simulated drivers
-#
-CONFIG_SIMETH=y
-CONFIG_SIM_SERIAL=y
-CONFIG_SCSI_SIM=y
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-prom-medusa linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-prom-medusa
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	1970-01-01 00:00:00.000000000 +0000
@@ -1,529 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	1970-01-01 00:00:00.000000000 +0000
@@ -1,738 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-dig-numa linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-dig-numa
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-dig-numa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-dig-numa	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_NUMA=y
-CONFIG_DISCONTIGMEM=y
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,730 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	1970-01-01 00:00:00.000000000 +0000
@@ -1,732 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-# CONFIG_SERIAL_SGI_L1_PROTOCOL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	1970-01-01 00:00:00.000000000 +0000
@@ -1,537 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-sp linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,730 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/Makefile linux-2.4.21-rc3/arch/ia64/sn/fakeprom/Makefile
--- linux-2.4.20/arch/ia64/sn/fakeprom/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -3,7 +3,7 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-#  Copyright (c) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+#  Copyright (c) 2000-2002 Silicon Graphics, Inc.  All rights reserved.
 #
 
 TOPDIR=../../../..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/README linux-2.4.21-rc3/arch/ia64/sn/fakeprom/README
--- linux-2.4.20/arch/ia64/sn/fakeprom/README	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/README	2003-05-22 22:06:53.000000000 +0000
@@ -1,3 +1,35 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
 This directory contains the files required to build
 the fake PROM image that is currently being used to
 boot IA64 kernels running under the SGI Medusa kernel.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fpmem.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fpmem.c	2003-05-22 22:06:41.000000000 +0000
@@ -54,10 +54,10 @@
 #define PROMRESERVED_SIZE	(1*MB)
 
 #ifdef CONFIG_IA64_SGI_SN1
-#define PHYS_ADDRESS(_n, _x)		(((long)_n<<33L) | (long)_x)
+#define PHYS_ADDRESS(_n, _x)		(((long)_n<<33) | (long)_x)
 #define MD_BANK_SHFT 30
 #else
-#define PHYS_ADDRESS(_n, _x)		(((long)_n<<38L) | (long)_x | 0x3000000000UL)
+#define PHYS_ADDRESS(_n, _x)		(((long)_n<<38) | (long)_x | 0x3000000000UL)
 #define MD_BANK_SHFT 34
 #endif
 
@@ -94,7 +94,7 @@
 int
 IsCpuPresent(int cnode, int cpu)
 {
-	return  sn_memmap[cnode].cpuconfig & (1<<cpu);
+	return  sn_memmap[cnode].cpuconfig & (1UL<<cpu);
 }
 
 
@@ -205,7 +205,17 @@
 				 */
 				numbytes = numbytes * 31 / 32;
 #endif
-				numbytes -= 1000;
+				/*
+				 * Only emulate the memory prom grabs
+				 * if we have lots of memory, to allow
+				 * us to simulate smaller memory configs than
+				 * we can actually run on h/w.  Otherwise,
+				 * linux throws away a whole "granule".
+				 */
+				if (cnode == 0 && bank == 0 &&
+				    numbytes > 128*1024*1024) {
+					numbytes -= 1000;
+				}
 
                                 /*
                                  * Check for the node 0 hole. Since banks cant
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fprom.lds linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fprom.lds
--- linux-2.4.20/arch/ia64/sn/fakeprom/fprom.lds	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fprom.lds	2003-05-22 22:06:51.000000000 +0000
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
 
 OUTPUT_FORMAT("elf64-ia64-little")
 OUTPUT_ARCH(ia64)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fpromasm.S linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fpromasm.S
--- linux-2.4.20/arch/ia64/sn/fakeprom/fpromasm.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fpromasm.S	2003-05-22 22:06:39.000000000 +0000
@@ -180,7 +180,7 @@
 
 
 // Now call main & pass it the current LID value.
-	alloc 		r0=ar.pfs,0,0,2,0
+	alloc 		r2=ar.pfs,0,0,2,0
 	mov    		r32=r26
 	mov   		r33=r8;;
 	br.call.sptk.few rp=fmain
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fw-emu.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/fw-emu.c	2003-05-22 22:06:51.000000000 +0000
@@ -46,10 +46,26 @@
 #include <asm/sn/sn2/addrs.h>
 #include <asm/sn/sn2/shub_mmr.h>
 #endif
-#include <asm/acpi-ext.h>
+#include <linux/acpi.h>
 #include "fpmem.h"
 
-#define zzACPI_1_0	1		/* Include ACPI 1.0 tables */
+#define RSDP_NAME               "RSDP"
+#define RSDP_SIG                "RSD PTR "  /* RSDT Pointer signature */
+#define APIC_SIG                "APIC"      /* Multiple APIC Description Table */
+#define DSDT_SIG                "DSDT"      /* Differentiated System Description Table */
+#define FADT_SIG                "FACP"      /* Fixed ACPI Description Table */
+#define FACS_SIG                "FACS"      /* Firmware ACPI Control Structure */
+#define PSDT_SIG                "PSDT"      /* Persistent System Description Table */
+#define RSDT_SIG                "RSDT"      /* Root System Description Table */
+#define XSDT_SIG                "XSDT"      /* Extended  System Description Table */
+#define SSDT_SIG                "SSDT"      /* Secondary System Description Table */
+#define SBST_SIG                "SBST"      /* Smart Battery Specification Table */
+#define SPIC_SIG                "SPIC"      /* IOSAPIC table */
+#define SRAT_SIG                "SRAT"      /* SRAT table */
+#define SLIT_SIG                "SLIT"      /* SLIT table */
+#define BOOT_SIG                "BOOT"      /* Boot table */
+#define ACPI_SRAT_REVISION 1
+#define ACPI_SLIT_REVISION 1
 
 #define OEMID			"SGI"
 #ifdef CONFIG_IA64_SGI_SN1
@@ -77,11 +93,7 @@
 #define CPUS_PER_FSB		2
 #define CPUS_PER_FSB_MASK	(CPUS_PER_FSB-1)
 
-#ifdef ACPI_1_0
-#define NUM_EFI_DESCS		3
-#else
 #define NUM_EFI_DESCS		2
-#endif
 
 #define RSDP_CHECKSUM_LENGTH	20
 
@@ -139,22 +151,16 @@
 		    + sizeof(struct ia64_sal_systab)
 		    + sizeof(struct ia64_sal_desc_entry_point)
 		    + sizeof(struct ia64_sal_desc_ap_wakeup)
-#ifdef ACPI_1_0
-		    + sizeof(acpi_rsdp_t)
-		    + sizeof(acpi_rsdt_t)
-		    + sizeof(acpi_sapic_t)
-		    + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t))
-#endif
-		    + sizeof(acpi20_rsdp_t)
-		    + sizeof(acpi_xsdt_t)
-		    + sizeof(acpi_slit_t)
+		    + sizeof(struct acpi20_table_rsdp)
+		    + sizeof(struct acpi_table_xsdt)
+		    + sizeof(struct acpi_table_slit)
 		    +   MAX_SN_NODES*MAX_SN_NODES+8
-		    + sizeof(acpi_madt_t)
+		    + sizeof(struct acpi_table_madt)
 		    +   16*MAX_CPUS
 		    + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t))
-		    + sizeof(acpi_srat_t)
-		    +   MAX_CPUS*sizeof(srat_cpu_affinity_t)
-		    +   MAX_SN_NODES*sizeof(srat_memory_affinity_t)
+		    + sizeof(struct acpi_table_srat)
+		    +   MAX_CPUS*sizeof(struct acpi_table_processor_affinity)
+		    +   MAX_SN_NODES*sizeof(struct acpi_table_memory_affinity)
 		    + sizeof(ia64_sal_desc_ptc_t) +
 		    + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) +
 		    + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) +
@@ -280,6 +286,7 @@
 	} else if (index == SAL_GET_STATE_INFO) {
 		;
 	} else if (index == SAL_GET_STATE_INFO_SIZE) {
+		r9 = 10000;
 		;
 	} else if (index == SAL_CLEAR_STATE_INFO) {
 		;
@@ -334,6 +341,8 @@
 		status = -1;
 	} else if (index == SN_SAL_CONSOLE_POLL) {
 		status = -1;
+	} else if (index == SN_SAL_SYSCTL_IOBRICK_MODULE_GET) {
+		status = -1;
 	} else {
 		status = -1;
 	}
@@ -402,7 +411,7 @@
 }
 
 void
-acpi_table_init(acpi_desc_table_hdr_t *p, char *sig, int siglen, int revision, int oem_revision)
+acpi_table_initx(struct acpi_table_header *p, char *sig, int siglen, int revision, int oem_revision)
 {
 	memcpy(p->signature, sig, siglen);
 	memcpy(p->oem_id, OEMID, 6);
@@ -410,12 +419,12 @@
 	memcpy(p->oem_table_id+4, PRODUCT, 4);
 	p->revision = revision;
 	p->oem_revision = (revision<<16) + oem_revision;
-	p->creator_id = 1;
-	p->creator_revision = 1;
+	memcpy(p->asl_compiler_id, "FPRM", 4);
+	p->asl_compiler_revision = 1;
 }
 
 void
-acpi_checksum(acpi_desc_table_hdr_t *p, int length)
+acpi_checksum(struct acpi_table_header *p, int length)
 {
 	u8	*cp, *cpe, checksum;
 
@@ -428,16 +437,22 @@
 }
 
 void
-acpi_checksum_rsdp20(acpi20_rsdp_t *p, int length)
+acpi_checksum_rsdp20(struct acpi20_table_rsdp *p, int length)
 {
 	u8	*cp, *cpe, checksum;
 
 	p->checksum = 0;
+	p->ext_checksum = 0;
 	p->length = length;
 	checksum = 0;
-	for (cp=(u8*)p, cpe=cp+RSDP_CHECKSUM_LENGTH; cp<cpe; cp++)
+	for (cp=(u8*)p, cpe=cp+20; cp<cpe; cp++)
 		checksum += *cp;
 	p->checksum = -checksum;
+
+	checksum = 0;
+	for (cp=(u8*)p, cpe=cp+length; cp<cpe; cp++)
+		checksum += *cp;
+	p->ext_checksum = -checksum;
 }
 
 int
@@ -462,21 +477,15 @@
 	static ia64_sal_desc_ptc_t *sal_ptc;
 	static ia64_sal_ptc_domain_info_t *sal_ptcdi;
 	static ia64_sal_ptc_domain_proc_entry_t *sal_ptclid;
-#ifdef ACPI_1_0
-	static acpi_rsdp_t *acpi_rsdp;
-	static acpi_rsdt_t *acpi_rsdt;
-	static acpi_sapic_t *acpi_sapic;
-	static acpi_entry_lsapic_t *acpi_lsapic;
-#endif
-	static acpi20_rsdp_t *acpi20_rsdp;
-	static acpi_xsdt_t *acpi_xsdt;
-	static acpi_slit_t *acpi_slit;
-	static acpi_madt_t *acpi_madt;
-	static acpi20_entry_lsapic_t *lsapic20;
+	static struct acpi20_table_rsdp *acpi20_rsdp;
+	static struct acpi_table_xsdt *acpi_xsdt;
+	static struct acpi_table_slit *acpi_slit;
+	static struct acpi_table_madt *acpi_madt;
+	static struct acpi_table_lsapic *lsapic20;
 	static struct ia64_sal_systab *sal_systab;
-	static acpi_srat_t *acpi_srat;
-	static srat_cpu_affinity_t *srat_cpu_affinity;
-	static srat_memory_affinity_t *srat_memory_affinity;
+	static struct acpi_table_srat *acpi_srat;
+	static struct acpi_table_processor_affinity *srat_cpu_affinity;
+	static struct acpi_table_memory_affinity *srat_memory_affinity;
 	static efi_memory_desc_t *efi_memmap, *md;
 	static unsigned long *pal_desc, *sal_desc;
 	static struct ia64_sal_desc_entry_point *sal_ed;
@@ -525,16 +534,10 @@
 	acpi_xsdt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_xsdt) + 64); 
 			/* save space for more OS defined table pointers. */
 
-#ifdef ACPI_1_0
-	acpi_rsdp   = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdp));
-	acpi_rsdt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdt));
-	acpi_sapic  = (void *) cp; cp += sizeof(*acpi_sapic);
-	acpi_lsapic = (void *) cp; cp += num_cpus*sizeof(*acpi_lsapic);
-#endif
 	acpi_slit   = (void *) cp; cp += ALIGN8(sizeof(*acpi_slit) + 8 + (max_nasid+1)*(max_nasid+1));
-	acpi_madt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + 8 * num_cpus+ 8);
-	acpi_srat   = (void *) cp; cp += ALIGN8(sizeof(acpi_srat_t));
-	cp         += sizeof(srat_cpu_affinity_t)*num_cpus + sizeof(srat_memory_affinity_t)*num_nodes;
+	acpi_madt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + sizeof(struct acpi_table_lsapic) * (num_cpus+1));
+	acpi_srat   = (void *) cp; cp += ALIGN8(sizeof(struct acpi_table_srat));
+	cp         += sizeof(struct acpi_table_processor_affinity)*num_cpus + sizeof(struct acpi_table_memory_affinity)*num_nodes;
 	vendor 	    = (char *) cp; cp += ALIGN8(40);
 	efi_memmap  = (void *) cp; cp += ALIGN8(8*32*sizeof(*efi_memmap));
 	sal_ptcdi   = (void *) cp; cp += ALIGN8(CPUS_PER_FSB*(1+num_nodes)*sizeof(*sal_ptcdi));
@@ -585,11 +588,6 @@
 	efi_tables->guid = SAL_SYSTEM_TABLE_GUID;
 	efi_tables->table = __fwtab_pa(base_nasid, sal_systab);
 	efi_tables++;
-#ifdef ACPI_1_0
-	efi_tables->guid = ACPI_TABLE_GUID;
-	efi_tables->table = __fwtab_pa(base_nasid, acpi_rsdp);
-	efi_tables++;
-#endif
 	efi_tables->guid = ACPI_20_TABLE_GUID;
 	efi_tables->table = __fwtab_pa(base_nasid, acpi20_rsdp);
 	efi_tables++;
@@ -600,65 +598,32 @@
 	fix_function_pointer(&efi_reset_system);
 	fix_function_pointer(&efi_set_virtual_address_map);
 
-#ifdef ACPI_1_0
-	/* fill in the ACPI system table - has a pointer to the ACPI table header */
-	memcpy(acpi_rsdp->signature, "RSD PTR ", 8);
-	acpi_rsdp->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt);
-
-	acpi_table_init(&acpi_rsdt->header, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN, 1, 1);
-	acpi_rsdt->header.length = sizeof(acpi_rsdt_t);
-	acpi_rsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_sapic);
-
-	memcpy(acpi_sapic->header.signature, "SPIC ", 4);
-	acpi_sapic->header.length = sizeof(acpi_sapic_t)+num_cpus*sizeof(acpi_entry_lsapic_t);
-
-	for (cnode=0; cnode<num_nodes; cnode++) {
-		nasid = GetNasid(cnode);
-		for(cpu=0; cpu<CPUS_PER_NODE; cpu++) {
-			if (!IsCpuPresent(cnode, cpu))
-				continue;
-			acpi_lsapic->type = ACPI_ENTRY_LOCAL_SAPIC;
-			acpi_lsapic->length = sizeof(acpi_entry_lsapic_t);
-			acpi_lsapic->acpi_processor_id = cnode*4+cpu;
-			acpi_lsapic->flags = LSAPIC_ENABLED|LSAPIC_PRESENT;
-#if defined(CONFIG_IA64_SGI_SN1)
-			acpi_lsapic->eid = cpu;
-			acpi_lsapic->id = nasid;
-#else
-			acpi_lsapic->eid = nasid&0xffff;
-			acpi_lsapic->id = (cpu<<4) | (nasid>>16);
-#endif
-			acpi_lsapic++;
-		}
-	}
-#endif
-
 
 	/* fill in the ACPI20 system table - has a pointer to the ACPI table header */
 	memcpy(acpi20_rsdp->signature, "RSD PTR ", 8);
-	acpi20_rsdp->xsdt = (struct acpi_xsdt*)__fwtab_pa(base_nasid, acpi_xsdt);
+	acpi20_rsdp->xsdt_address = (u64)__fwtab_pa(base_nasid, acpi_xsdt);
 	acpi20_rsdp->revision = 2;
-	acpi_checksum_rsdp20(acpi20_rsdp, sizeof(acpi20_rsdp_t));
+	acpi_checksum_rsdp20(acpi20_rsdp, sizeof(struct acpi20_table_rsdp));
 
 	/* Set up the XSDT table  - contains pointers to the other ACPI tables */
-	acpi_table_init(&acpi_xsdt->header, ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN, 1, 1);
-	acpi_xsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_madt);
-	acpi_xsdt->entry_ptrs[1] = __fwtab_pa(base_nasid, acpi_slit);
-	acpi_xsdt->entry_ptrs[2] = __fwtab_pa(base_nasid, acpi_srat);
-	acpi_checksum(&acpi_xsdt->header, sizeof(acpi_xsdt_t) + 16);
-
-	/* Set up the MADT table */
-	acpi_table_init(&acpi_madt->header, ACPI_MADT_SIG, ACPI_MADT_SIG_LEN, 1, 1);
-	lsapic20 = (acpi20_entry_lsapic_t*) (acpi_madt + 1);
+	acpi_table_initx(&acpi_xsdt->header, XSDT_SIG, 4, 1, 1);
+	acpi_xsdt->entry[0] = __fwtab_pa(base_nasid, acpi_madt);
+	acpi_xsdt->entry[1] = __fwtab_pa(base_nasid, acpi_slit);
+	acpi_xsdt->entry[2] = __fwtab_pa(base_nasid, acpi_srat);
+	acpi_checksum(&acpi_xsdt->header, sizeof(struct acpi_table_xsdt) + 16);
+
+	/* Set up the APIC table */
+	acpi_table_initx(&acpi_madt->header, APIC_SIG, 4, 1, 1);
+	lsapic20 = (struct acpi_table_lsapic*) (acpi_madt + 1);
 	for (cnode=0; cnode<num_nodes; cnode++) {
 		nasid = GetNasid(cnode);
 		for(cpu=0; cpu<CPUS_PER_NODE; cpu++) {
 			if (!IsCpuPresent(cnode, cpu))
 				continue;
-			lsapic20->type = ACPI20_ENTRY_LOCAL_SAPIC;
-			lsapic20->length = sizeof(acpi_entry_lsapic_t);
-			lsapic20->acpi_processor_id = cnode*4+cpu;
-			lsapic20->flags = LSAPIC_ENABLED|LSAPIC_PRESENT;
+			lsapic20->header.type = ACPI_MADT_LSAPIC;
+			lsapic20->header.length = sizeof(struct acpi_table_lsapic);
+			lsapic20->acpi_id = cnode*4+cpu;
+			lsapic20->flags.enabled = 1;
 #if defined(CONFIG_IA64_SGI_SN1)
 			lsapic20->eid = cpu;
 			lsapic20->id = nasid;
@@ -666,20 +631,20 @@
 			lsapic20->eid = nasid&0xffff;
 			lsapic20->id = (cpu<<4) | (nasid>>16);
 #endif
-			lsapic20 = (acpi20_entry_lsapic_t*) ((long)lsapic20+sizeof(acpi_entry_lsapic_t));
+			lsapic20 = (struct acpi_table_lsapic*) ((long)lsapic20+sizeof(struct acpi_table_lsapic));
 		}
 	}
 	acpi_checksum(&acpi_madt->header, (char*)lsapic20 - (char*)acpi_madt);
 
 	/* Set up the SRAT table */
-	acpi_table_init(&acpi_srat->header, ACPI_SRAT_SIG, ACPI_SRAT_SIG_LEN, ACPI_SRAT_REVISION, 1);
+	acpi_table_initx(&acpi_srat->header, SRAT_SIG, 4, ACPI_SRAT_REVISION, 1);
 	ptr = acpi_srat+1;
 	for (cnode=0; cnode<num_nodes; cnode++) {
 		nasid = GetNasid(cnode);
 		srat_memory_affinity = ptr;
 		ptr = srat_memory_affinity+1;
-		srat_memory_affinity->type = SRAT_MEMORY_STRUCTURE;
-		srat_memory_affinity->length = sizeof(srat_memory_affinity_t);
+		srat_memory_affinity->header.type = ACPI_SRAT_MEMORY_AFFINITY;
+		srat_memory_affinity->header.length = sizeof(struct acpi_table_memory_affinity);
 		srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid);
 		srat_memory_affinity->base_addr_lo = 0;
 		srat_memory_affinity->length_lo = 0;
@@ -691,7 +656,7 @@
 		srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32;
 #endif
 		srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY;
-		srat_memory_affinity->flags = SRAT_MEMORY_FLAGS_ENABLED;
+		srat_memory_affinity->flags.enabled = 1;
 	}
 
 	for (cnode=0; cnode<num_nodes; cnode++) {
@@ -701,15 +666,15 @@
 				continue;
 			srat_cpu_affinity = ptr;
 			ptr = srat_cpu_affinity + 1;
-			srat_cpu_affinity->type = SRAT_CPU_STRUCTURE;
-			srat_cpu_affinity->length = sizeof(srat_cpu_affinity_t);
+			srat_cpu_affinity->header.type = ACPI_SRAT_PROCESSOR_AFFINITY;
+			srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity);
 			srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid);
-			srat_cpu_affinity->flags = SRAT_CPU_FLAGS_ENABLED;
+			srat_cpu_affinity->flags.enabled = 1;
 #if defined(CONFIG_IA64_SGI_SN1)
 			srat_cpu_affinity->apic_id = nasid;
-			srat_cpu_affinity->local_sapic_eid = cpu;
+			srat_cpu_affinity->lsapic_eid = cpu;
 #else
-			srat_cpu_affinity->local_sapic_eid = nasid&0xffff;
+			srat_cpu_affinity->lsapic_eid = nasid&0xffff;
 			srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16);
 #endif
 		}
@@ -718,9 +683,9 @@
 
 
 	/* Set up the SLIT table */
-	acpi_table_init(&acpi_slit->header, ACPI_SLIT_SIG, ACPI_SLIT_SIG_LEN, ACPI_SLIT_REVISION, 1);
+	acpi_table_initx(&acpi_slit->header, SLIT_SIG, 4, ACPI_SLIT_REVISION, 1);
 	acpi_slit->localities = PROXIMITY_DOMAIN(max_nasid)+1;
-	cp=acpi_slit->entries;
+	cp=acpi_slit->entry;
 	memset(cp, 255, acpi_slit->localities*acpi_slit->localities);
 
 	for (i=0; i<=max_nasid; i++)
@@ -728,7 +693,7 @@
 			if (nasid_present(i) && nasid_present(j))
 				*(cp+PROXIMITY_DOMAIN(i)*acpi_slit->localities+PROXIMITY_DOMAIN(j)) = 10 + MIN(254, 5*ABS(i-j));
 
-	cp = acpi_slit->entries + acpi_slit->localities*acpi_slit->localities;
+	cp = acpi_slit->entry + acpi_slit->localities*acpi_slit->localities;
 	acpi_checksum(&acpi_slit->header, cp - (char*)acpi_slit);
 
 
@@ -738,6 +703,8 @@
 	sal_systab->sal_rev_minor = 1;
 	sal_systab->sal_rev_major = 0;
 	sal_systab->entry_count = 3;
+	sal_systab->sal_b_rev_major = 0x1; /* set the SN SAL rev to */
+	sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */
 
 	strcpy(sal_systab->oem_id, "SGI");
 	strcpy(sal_systab->product_id, "SN1");
@@ -792,11 +759,6 @@
 	 * table. We dont build enough table & the kernel aborts.
 	 * Note that the PROM hasd thhhe same problem!!
 	 */
-#ifdef DOESNT_WORK
-	for (checksum=0, cp=(char*)acpi_rsdp, cpe=cp+RSDP_CHECKSUM_LENGTH; cp<cpe; ++cp)
-		checksum += *cp;
-	acpi_rsdp->checksum = -checksum;
-#endif
 
 	md = &efi_memmap[0];
 	num_memmd = build_efi_memmap((void *)md, mdsize) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/klgraph_init.c linux-2.4.21-rc3/arch/ia64/sn/fakeprom/klgraph_init.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/klgraph_init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/klgraph_init.c	2003-05-22 22:06:26.000000000 +0000
@@ -49,8 +49,9 @@
 klgraph_init(void)
 {
 
-	u64	*temp;
-
+#ifdef CONFIG_IA64_SGI_SN1
+	u64 *temp;
+#endif
 	/*
 	 * Initialize some hub/xbow registers that allows access to 
 	 * Xbridge etc.  These are normally done in PROM.
@@ -109,6 +110,8 @@
 // [PI]       *(volatile u32 *)0xc00000080f000288L = 0xba98;
 #endif	/* CONFIG_IA64_SGI_SN1 */
 
+#ifdef CONFIG_IA64_SGI_SN1
+
 	/*
 	 * kldir entries initialization - mankato
 	 */
@@ -282,6 +285,7 @@
 	convert(0x8000000000002560, 0xffffffffffffffff, 0xffffffffffffffff);
 	convert(0x8000000000002570, 0xffffffffffffffff, 0xffffffffffffffff);
 	convert(0x8000000000002580, 0x000000000000ffff, 0x0000000000000000);
+#endif
 	
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/main.c linux-2.4.21-rc3/arch/ia64/sn/fakeprom/main.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/main.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/fakeprom/main.c	2003-05-22 22:06:47.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
@@ -98,7 +98,7 @@
 
 	/*
 	 * Enable all FSB flashed interrupts.
-	 * ZZZ - I'd really like defines for this......
+	 * I'd really like defines for this......
 	 */
 	base = (long*)0x80000e0000000000LL;		/* base of synergy regs */
 	for (off = 0x2a0; off < 0x2e0; off+=8)		/* offset for VEC_MASK_{0-3}_A/B */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/Makefile linux-2.4.21-rc3/arch/ia64/sn/io/Makefile
--- linux-2.4.20/arch/ia64/sn/io/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/Makefile	2003-05-22 22:06:39.000000000 +0000
@@ -5,41 +5,29 @@
 #
 # Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
 #
-#
-# Makefile for the linux kernel.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
+# Makefile for the sn kernel routines.
 
 EXTRA_CFLAGS    := -DLITTLE_ENDIAN
 
-O_TARGET := sgiio.o
-
-ifeq ($(CONFIG_MODULES),y)
-export-objs = pciio.o hcl.o pci_dma.o
+ifdef CONFIG_IA64_SGI_SN2
+EXTRA_CFLAGS    += -DSHUB_SWAP_WAR
 endif
 
-obj-y  := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \
-		hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \
-		module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \
-		ml_iograph.o hcl_util.o cdl.o hubdev.o hubspc.o \
-		alenlist.o pci_bus_cvlink.o \
-		eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o \
-		ifconfig_net.o efi-rtc.o io.o
-
-obj-$(CONFIG_IA64_SGI_SN1)   += sn1/ml_SN_intr.o sn1/mem_refcnt.o sn1/hubcounters.o \
-				sn1/ip37.o sn1/huberror.o sn1/hub_intr.o sn1/pcibr.o
-
-obj-$(CONFIG_IA64_SGI_SN2)   += sn2/ml_SN_intr.o sn2/shub_intr.o sn2/shuberror.o \
-				sn2/bte_error.o \
-				sn2/pcibr/pcibr_dvr.o sn2/pcibr/pcibr_ate.o \
-				sn2/pcibr/pcibr_config.o sn2/pcibr/pcibr_dvr.o \
-				sn2/pcibr/pcibr_hints.o \
-				sn2/pcibr/pcibr_idbg.o sn2/pcibr/pcibr_intr.o \
-				sn2/pcibr/pcibr_rrb.o sn2/pcibr/pcibr_slot.o 
+O_TARGET := sgiio.o
+ 
+export-objs := hcl.o pci_dma.o
+
+obj-y :=	stubs.o sgi_if.o xswitch.o klgraph_hack.o \
+		hcl.o labelcl.o invent.o sgi_io_sim.o \
+		klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \
+		alenlist.o pci.o pci_dma.o ate_utils.o \
+		ifconfig_net.o io.o ifconfig_bus.o
+
+obj-$(CONFIG_IA64_SGI_SN1)	+= sn1/snio.o
+obj-$(CONFIG_IA64_SGI_SN2)	+= sn2/snio.o
+obj-$(CONFIG_PCIBA)		+= pciba.o
 
-obj-$(CONFIG_PCIBA) += pciba.o
+subdir-$(CONFIG_IA64_SGI_SN1)	+= sn1
+subdir-$(CONFIG_IA64_SGI_SN2)	+= sn2
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/cdl.c linux-2.4.21-rc3/arch/ia64/sn/io/cdl.c
--- linux-2.4.20/arch/ia64/sn/io/cdl.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/cdl.c	2003-05-22 22:06:39.000000000 +0000
@@ -7,6 +7,7 @@
  * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
 #include <asm/io.h>
@@ -19,6 +20,8 @@
 /* these get called directly in cdl_add_connpt in fops bypass hack */
 extern int pcibr_attach(devfs_handle_t);
 extern int xbow_attach(devfs_handle_t);
+extern int pic_attach(devfs_handle_t);
+
 
 /*
  *    cdl: Connection and Driver List
@@ -35,13 +38,24 @@
     int (*attach) (devfs_handle_t);
 } dummy_reg;
 
+#ifdef CONFIG_IA64_SGI_SN1
 #define MAX_SGI_IO_INFRA_DRVR 4
-struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] =
+#else
+#define MAX_SGI_IO_INFRA_DRVR 7
+#endif
+static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] =
 {
 	{ XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops  */},
 	{ BRIDGE_WIDGET_PART_NUM,  BRIDGE_WIDGET_MFGR_NUM,  pcibr_attach /* &pcibr_fops */},
+#ifndef CONFIG_IA64_SGI_SN1
+	{ PIC_WIDGET_PART_NUM_BUS0,  PIC_WIDGET_MFGR_NUM,   pic_attach /* &pic_fops */},
+	{ PIC_WIDGET_PART_NUM_BUS1,  PIC_WIDGET_MFGR_NUM,   pic_attach /* &pic_fops */},
+#endif
 	{ XXBOW_WIDGET_PART_NUM,   XXBOW_WIDGET_MFGR_NUM,   xbow_attach /* &xbow_fops */},
 	{ XBOW_WIDGET_PART_NUM,    XBOW_WIDGET_MFGR_NUM,    xbow_attach /* &xbow_fops */},
+#ifndef CONFIG_IA64_SGI_SN1
+	{ PXBOW_WIDGET_PART_NUM,   XXBOW_WIDGET_MFGR_NUM,   xbow_attach /* &xbow_fops */},
+#endif
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hcl.c linux-2.4.21-rc3/arch/ia64/sn/io/hcl.c
--- linux-2.4.20/arch/ia64/sn/io/hcl.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/hcl.c	2003-05-22 22:06:39.000000000 +0000
@@ -6,7 +6,7 @@
  *
  *  hcl - SGI's Hardware Graph compatibility layer.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -155,7 +155,7 @@
 	/*
 	 * Create the hwgraph_root on devfs.
 	 */
-	rv = hwgraph_path_add(NULL, "hw", &hwgraph_root);
+	rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
 	if (rv)
 		printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv);
 
@@ -183,9 +183,9 @@
 	/*
 	 * Create the directory that links Linux bus numbers to our Xwidget.
 	 */
-	rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum);
+	rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum);
 	if (linux_busnum == NULL) {
-		panic("HCL: Unable to create hw/linux/busnum\n");
+		panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS);
 		return(0);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hcl_util.c linux-2.4.21-rc3/arch/ia64/sn/io/hcl_util.c
--- linux-2.4.20/arch/ia64/sn/io/hcl_util.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/hcl_util.c	2003-05-22 22:06:48.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -96,6 +96,33 @@
 	}
 }
 
+static devfs_handle_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE;
+extern int maxcpus;
+
+void
+mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid)
+{
+	if (cpuid == CPU_NONE)
+		return;
+
+	(void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT,
+			(arbitrary_info_t)cpuid);
+	{
+		char cpuid_buffer[10];
+
+		if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) {
+			(void)hwgraph_path_add( hwgraph_root,
+						EDGE_LBL_CPUNUM,
+						&hwgraph_all_cpuids);
+		}
+
+		sprintf(cpuid_buffer, "%ld", cpuid);
+		(void)hwgraph_edge_add( hwgraph_all_cpuids,
+							vhdl,
+							cpuid_buffer);
+	}
+}
+
 /*
 ** If the specified device represents a node, return its
 ** compact node ID; otherwise, return CNODEID_NONE.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hubdev.c linux-2.4.21-rc3/arch/ia64/sn/io/hubdev.c
--- linux-2.4.20/arch/ia64/sn/io/hubdev.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/hubdev.c	2003-05-22 22:06:50.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hubspc.c linux-2.4.21-rc3/arch/ia64/sn/io/hubspc.c
--- linux-2.4.20/arch/ia64/sn/io/hubspc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/hubspc.c	2003-05-22 22:06:48.000000000 +0000
@@ -161,69 +161,8 @@
 				sizeof(invent_miscinfo_t));
 }
 
-#define FPROM_CONFIG_ADDR	MD_JUNK_BUS_TIMING
-#define FPROM_ENABLE_MASK	MJT_FPROM_ENABLE_MASK
-#define FPROM_ENABLE_SHFT	MJT_FPROM_ENABLE_SHFT
-#define FPROM_SETUP_MASK	MJT_FPROM_SETUP_MASK
-#define FPROM_SETUP_SHFT	MJT_FPROM_SETUP_SHFT
+#endif  /* CONFIG_IA64_SGI_SN1 */
 
-/*ARGSUSED*/
-int
-cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len)
-{
-        int 		errcode = 0;
-	caddr_t 	kvaddr;
-	devfs_handle_t		node;
-	cnodeid_t 	cnode;
-
-	node = prominfo_nodeget(dev);
-
-	if (!node)
-		return EIO;
-        
-
-	kvaddr = hubdev_prombase_get(node);
-	cnode  = hubdev_cnodeid_get(node);
-#ifdef	HUBSPC_DEBUG
-	printk("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr);
-#endif
-
-	if (len > RBOOT_SIZE)
-		len = RBOOT_SIZE;
-        /*
-         * Map in the prom space
-         */
-	errcode = v_mapphys(vt, kvaddr, len);
-
-	if (errcode == 0 ){
-		/*
-		 * Set the MD configuration registers suitably.
-		 */
-		nasid_t		nasid;
-		uint64_t	value;
-		volatile hubreg_t	*regaddr;
-
-		nasid = COMPACT_TO_NASID_NODEID(cnode);
-		regaddr = REMOTE_HUB_ADDR(nasid, FPROM_CONFIG_ADDR);
-		value = HUB_L(regaddr);
-		value &= ~(FPROM_SETUP_MASK | FPROM_ENABLE_MASK);
-		{
-			value |= (((long)CONFIG_FPROM_SETUP << FPROM_SETUP_SHFT) | 
-				  ((long)CONFIG_FPROM_ENABLE << FPROM_ENABLE_SHFT));
-		}
-		HUB_S(regaddr, value);
-
-	}
-        return (errcode);
-}
-#endif	/* CONFIG_IA64_SGI_SN1 */
-
-/*ARGSUSED*/
-int
-cpuprom_unmap(devfs_handle_t dev, vhandl_t *vt)
-{
-        return 0;
-}
 
 /***********************************************************************/
 /* Base Hub Space Driver                                               */
@@ -245,13 +184,14 @@
         hubdev_register(mem_refcnt_attach);
 #endif
 
+#ifdef CONFIG_IA64_SGI_SN1
 	/* L1 system controller link */
 	if ( !IS_RUNNING_ON_SIMULATOR() ) {
 		/* initialize the L1 link */
 		extern void l1_init(void);
 		l1_init();
 	}
-
+#endif	/* CONFIG_IA64_SGI_SN1 */
 #ifdef	HUBSPC_DEBUG
 	printk("hubspc_init: Completed\n");
 #endif	/* HUBSPC_DEBUG */
@@ -283,7 +223,7 @@
 
 	/* check validity of request */
 	if( len == 0 ) {
-		return ENXIO;
+		return -ENXIO;
         }
 
 	return errcode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/ifconfig_bus.c linux-2.4.21-rc3/arch/ia64/sn/io/ifconfig_bus.c
--- linux-2.4.20/arch/ia64/sn/io/ifconfig_bus.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/ifconfig_bus.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,345 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ *  ifconfig_bus - SGI's Persistent PCI Bus Numbering.
+ *
+ * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+
+#include <asm/sn/sgi.h>
+#include <linux/devfs_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm//sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+
+#define SGI_IFCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING"
+#define SGI_IFCONFIG_BUS_VERSION "1.0"
+
+/*
+ * Some Global definitions.
+ */
+devfs_handle_t ioconfig_bus_handle = NULL;
+unsigned long ioconfig_bus_debug = 0;
+
+#define IFCONFIG_BUS_DEBUG 1
+#ifdef IFCONFIG_BUS_DEBUG
+#define DBG(x...)	printk(x)
+#else
+#define DBG(x...)
+#endif
+
+u64 ioconfig_file = 0;
+u64 ioconfig_file_size = 0;
+
+
+/*
+ * PCI Bus Name for PCI
+ * 		 module/001c02/Ibrick/xtalk/14/pci - only 1 bus per widget
+ *
+ * PCI Bus Name for PCI-X
+ *		 module/001c02/Ibrick/xtalk/14/pci-x/0 - PCI bus 0 on Widget 14
+ *		 module/001c02/Ibrick/xtalk/14/pci-x/1 - PCI bus 1 on Widget 14
+ */
+
+struct	pcipath_to_busnum{
+	unsigned int  num;			/* persistent bus number */
+	unsigned int  len;			/* pci path length */
+	unsigned char	path[120];		/* pci path name */
+};
+
+struct  pcipath_to_busnum *ioconfig_bus_table;
+u64 ioconfig_bus_table_size = 0;
+
+
+struct pcipath_to_busnum pcibus_names[256];
+
+/*
+ * highest_pcibus_num : The highest PCI bus number allocated.  Use for next 
+ *			PCI Bus Number to be assigned.
+ * pcibus_names_index : The starting entry of any new configuration.  It also 
+ *			tracks the number of old config in the table.
+ * current_index : Next free index in the table for new config.
+ *		   current_index - pcibus_names_index = number new config.
+ */
+
+int	highest_pcibus_num = 0;
+int	pcibus_names_index = 0; /* Start of new config */
+int	current_index = 0; /* Next entry for new config */
+
+/*
+ * ioconfig_get_busnum():
+ *	ioconfig_get_busnum() returns the bus number given a pci path name.
+ *	If the pci path name exist in the persistent naming table, the
+ *	corresponding bun number is returned.  If the pci path name does not
+ *	exist, the next bus number is assigned to that path, added to the
+ *	persistent naming table and the new bus num returned.
+ */
+void
+ioconfig_get_busnum(char *pci_path, int *bus_num)
+{
+	struct	pcipath_to_busnum *temp;
+	int index;
+
+	*bus_num = -1;
+	temp = ioconfig_bus_table;
+	for (index = 0; index < current_index; ioconfig_bus_table++, index++) {
+		if ( (strncmp(pci_path, ioconfig_bus_table->path, strlen(pci_path) == 0)) ){
+			*bus_num = ioconfig_bus_table->num;
+			return;
+		}
+	}
+
+	/*
+	 * This is a new path and it is not in the config table.
+	 * Add it to the end.
+	 */
+	*bus_num = highest_pcibus_num;
+	highest_pcibus_num++;
+	ioconfig_bus_table->num = *bus_num;
+	strcpy((char *)&(ioconfig_bus_table->path), pci_path);
+	ioconfig_bus_table->len = strlen(pci_path);
+	current_index++;
+
+}
+
+void
+dump_ioconfig_table(struct pcipath_to_busnum *ioconfig_bus_table)
+{
+
+	int index = 0;
+	struct pcipath_to_busnum *temp;
+
+	temp = ioconfig_bus_table;
+	while (index < pcibus_names_index) {
+		printk("Bus Number %d PCI path %s\n", temp->num, temp->path);
+		temp++;
+		index++;
+	}
+		
+}
+/*
+ * nextline
+ *	This routine returns the nextline in the buffer.
+ */
+int nextline(char *buffer, char **next, char *line)
+{
+
+	char *temp;
+
+	if (buffer[0] == 0x0) {
+		return(0);
+	}
+
+	temp = buffer;
+	while (*temp != 0) {
+		*line = *temp;
+		if (*temp != '\n'){
+			*line = *temp;
+			temp++; line++;
+		} else
+			break;
+	}
+
+	if (*temp == 0)
+		*next = temp;
+	else
+		*next = ++temp;
+
+	return(1);
+}
+
+/*
+ * build_pcibus_name
+ *	This routine parses the ioconfig contents read into
+ *	memory by ioconfig command in EFI and builds the
+ *	persistent pci bus naming table.
+ */
+void
+build_pcibus_name(char *file_contents, struct pcipath_to_busnum *table)
+{
+	/*
+	 * Read the whole file into memory.
+	 */
+	int busnum;
+	int rc;
+	char *name;
+	char *temp;
+	char *next;
+	char *current;
+	char *line;
+	struct pcipath_to_busnum *pcibus;
+
+	line = kmalloc(256, GFP_KERNEL);
+	memset(line, 0,256);
+	name = kmalloc(125, GFP_KERNEL);
+	memset(name, 0, 125);
+	pcibus = table;
+	current = file_contents;
+	while (nextline(current, &next, line)){
+printk("current 0x%lx next 0x%lx\n", current, next);
+		temp = line;
+		/*
+		 * Skip all leading Blank lines ..
+		 */
+		while (isspace(*temp))
+			if (*temp != '\n')
+				temp++;
+			else
+				break;
+
+		if (*temp == '\n') {
+			current = next;
+			memset(line, 0, 256);
+			continue;
+		}
+ 
+		/*
+		 * Skip comment lines
+		 */
+		if (*temp == '#') {
+			current = next;
+			memset(line, 0, 256);
+			continue;
+		}
+
+		/*
+		 * Get the next free entry in the table.
+		 */
+		rc = sscanf(temp, "%d %s", &busnum, name);
+		pcibus->num = busnum;
+		pcibus->len = strlen(name);
+		strcpy(&pcibus->path[0], name);
+		DBG("pci number = %d pci path = %s\n", pcibus->num, pcibus->path);
+		if (busnum > highest_pcibus_num)
+			highest_pcibus_num = busnum;
+		else 
+			highest_pcibus_num = busnum; 
+ 
+		pcibus_names_index++;
+		pcibus++;
+		current = next;
+		memset(line, 0, 256);
+	}
+
+	DBG("highest_pcibus_num %d pcibus_names_index %d\n", highest_pcibus_num, pcibus_names_index);
+
+	current_index = pcibus_names_index;
+	kfree(line);
+	kfree(name);
+
+	return;
+}
+
+void
+ioconfig_bus_init(void)
+{
+
+	struct ia64_sal_retval ret_stuff;
+
+	DBG("ioconfig_bus_init called.\n");
+
+	/*
+	 * Make SAL call to get the address of the bus configuration table.
+	 */
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, get_nasid(), 0, 0, 0, 0, 0);
+	if (ret_stuff.status != 0) {
+		DBG("ifconfig_bus_init: No Address given\n");
+	}
+
+	ioconfig_file = ret_stuff.v0;
+	ioconfig_file_size = ret_stuff.v1;
+	DBG("ioconfig_bus_init: ioconfig_file %p %d\n", 
+		(void *)ioconfig_file, (int)ioconfig_file_size);
+
+	/*
+	 * Convert the address to a Cache Address.
+	 */
+	ioconfig_file = (CACHEABLE_MEM_SPACE | 
+		(ioconfig_file & TO_PHYS_MASK));
+
+	ioconfig_bus_table = kmalloc( 512*sizeof(struct pcipath_to_busnum), 
+				GFP_KERNEL );
+
+	DBG("ioconfig_bus_init: Kernel virtual ioconfig_file %p ioconfig_bus_table %p\n", 
+		(void *)ioconfig_file, (void *)ioconfig_bus_table);
+
+	(void) build_pcibus_name((char *)ioconfig_file, ioconfig_bus_table);
+
+	(void) dump_ioconfig_table(ioconfig_bus_table);
+
+}
+
+/*
+ * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_open(struct inode * inode, struct file * filp)
+{
+	if (ioconfig_bus_debug) {
+        	printk("ioconfig_bus_open called.\n");
+	}
+
+        return(0);
+
+}
+
+/*
+ * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_close(struct inode * inode, struct file * filp)
+{
+
+	if (ioconfig_bus_debug) {
+        	printk("ioconfig_bus_close called.\n");
+	}
+
+        return(0);
+}
+
+struct file_operations ioconfig_bus_fops = {
+	/* ioctl:ioconfig_bus_ioctl, ioctl */
+	open:ioconfig_bus_open,		/* open */
+	release:ioconfig_bus_close	/* release */
+};
+
+
+/*
+ * init_ifconfig_net() - Boot time initialization.  Ensure that it is called 
+ *	after devfs has been initialized.
+ *
+ */
+int init_ioconfig_bus(void)
+{
+	ioconfig_bus_handle = NULL;
+	ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus",
+			0, DEVFS_FL_AUTO_DEVNUM,
+			0, 0,
+			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+			&ioconfig_bus_fops, NULL);
+
+	if (ioconfig_bus_handle == NULL) {
+		panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n");
+	}
+
+	return(0);
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/invent.c linux-2.4.21-rc3/arch/ia64/sn/io/invent.c
--- linux-2.4.20/arch/ia64/sn/io/invent.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/invent.c	2003-05-22 22:06:47.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/io.c linux-2.4.21-rc3/arch/ia64/sn/io/io.c
--- linux-2.4.20/arch/ia64/sn/io/io.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/io.c	2003-05-22 22:06:42.000000000 +0000
@@ -7,6 +7,7 @@
  * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <asm/sn/types.h>
@@ -31,21 +32,6 @@
 extern void hub_intr_init(devfs_handle_t hubv);
 
 
-/*      
- * hub_device_desc_update               
- *      Update the passed in device descriptor with the actual the
- *      target cpu number and interrupt priority level.
- *      NOTE : These might be the same as the ones passed in thru
- *      the descriptor.
- */     
-void
-hub_device_desc_update(device_desc_t    dev_desc,
-                       ilvl_t           intr_swlevel, 
-                       cpuid_t          cpu)
-{       
-}
-
-
 /*
  * Perform any initializations needed to support hub-based I/O.
  * Called once during startup.
@@ -53,11 +39,6 @@
 void
 hubio_init(void)
 {
-#ifdef	LATER
-	/* This isn't needed unless we port the entire sio driver ... */
-        extern void early_brl1_port_init( void );
-	early_brl1_port_init();
-#endif
 }
 
 /* 
@@ -149,6 +130,10 @@
 	nasid_t nasid;
 	volatile hubreg_t junk;
 	unsigned long s;
+	caddr_t kvaddr;
+#ifdef PIOMAP_UNC_ACC_SPACE
+	uint64_t addr;
+#endif
 
 	/* sanity check */
 	if (byte_count_max > byte_count)
@@ -159,8 +144,19 @@
 	/* If xtalk_addr range is mapped by a small window, we don't have 
 	 * to do much 
 	 */
-	if (xtalk_addr + byte_count <= SWIN_SIZE)
-		return(hubinfo_swin_piomap_get(hubinfo, (int)widget));
+	if (xtalk_addr + byte_count <= SWIN_SIZE) {
+		hub_piomap_t piomap;
+
+		piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
+#ifdef PIOMAP_UNC_ACC_SPACE
+		if (flags & PIOMAP_UNC_ACC) {
+			addr = (uint64_t)piomap->hpio_xtalk_info.xp_kvaddr;
+			addr |= PIOMAP_UNC_ACC_SPACE;
+			piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)addr;
+		}
+#endif
+		return piomap;
+	}
 
 	/* We need to use a big window mapping.  */
 
@@ -257,7 +253,15 @@
 	bw_piomap->hpio_xtalk_info.xp_dev = dev;
 	bw_piomap->hpio_xtalk_info.xp_target = widget;
 	bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr;
-	bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
+	kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
+#ifdef PIOMAP_UNC_ACC_SPACE
+	if (flags & PIOMAP_UNC_ACC) {
+		addr = (uint64_t)kvaddr;
+		addr |= PIOMAP_UNC_ACC_SPACE;
+		kvaddr = (caddr_t)addr;
+	}
+#endif
+	bw_piomap->hpio_xtalk_info.xp_kvaddr = kvaddr;
 	bw_piomap->hpio_holdcnt++;
 	bw_piomap->hpio_bigwin_num = free_bw_index;
 
@@ -378,12 +382,22 @@
 	devfs_handle_t hubv = xwidget_info_master_get(widget_info);
 	hub_piomap_t hub_piomap;
 	hubinfo_t hubinfo;
+	caddr_t addr;
 
 	hubinfo_get(hubv, &hubinfo);
 
 	if (xtalk_addr + byte_count <= SWIN_SIZE) {
 		hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
-		return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count));
+		addr = hub_piomap_addr(hub_piomap, xtalk_addr, byte_count);
+#ifdef PIOMAP_UNC_ACC_SPACE
+		if (flags & PIOMAP_UNC_ACC) {
+			uint64_t iaddr;
+			iaddr = (uint64_t)addr;
+			iaddr |= PIOMAP_UNC_ACC_SPACE;
+			addr = (caddr_t)iaddr;
+		}
+#endif
+		return(addr);
 	} else
 		return(0);
 }
@@ -392,19 +406,6 @@
 /* DMA MANAGEMENT */
 /* Mapping from crosstalk space to system physical space */
 
-/* 
- * There's not really very much to do here, since crosstalk maps
- * directly to system physical space.  It's quite possible that this
- * DMA layer will be bypassed in performance kernels.
- */
-
-
-/* ARGSUSED */
-void
-hub_dma_init(devfs_handle_t hubv)
-{
-}
-
 
 /*
  * Allocate resources needed to set up DMA mappings up to a specified size
@@ -478,7 +479,12 @@
 	}
 
 	/* There isn't actually any DMA mapping hardware on the hub. */
-	return(paddr);
+#ifdef CONFIG_IA64_SGI_SN2
+        return( (PHYS_TO_DMA(paddr)) );
+#else
+        /* no translation needed */
+        return(paddr);
+#endif
 }
 
 /*
@@ -549,8 +555,12 @@
 			size_t byte_count,	/* length */
 			unsigned flags)		/* defined in dma.h */
 {
+#ifdef CONFIG_IA64_SGI_SN2
+	return( (PHYS_TO_DMA(paddr)) );
+#else
 	/* no translation needed */
 	return(paddr);
+#endif
 }
 
 /*
@@ -565,6 +575,7 @@
 			alenlist_t palenlist,	/* system address/length list */
 			unsigned flags)		/* defined in dma.h */
 {
+	BUG();
 	/* no translation needed */
 	return(palenlist);
 }
@@ -603,11 +614,9 @@
 void
 hub_provider_startup(devfs_handle_t hubv)
 {
-	extern void hub_dma_init(devfs_handle_t hubv);
 	extern void hub_pio_init(devfs_handle_t hubv);
 
 	hub_pio_init(hubv);
-	hub_dma_init(hubv);
 	hub_intr_init(hubv);
 }
 
@@ -707,14 +716,12 @@
 {
 	iprb_t prb;
 	int prb_offset;
-#ifdef LATER
 	extern int force_fire_and_forget;
 	extern volatile int ignore_conveyor_override;
 
 	if (force_fire_and_forget && !ignore_conveyor_override)
 	    if (conveyor == HUB_PIO_CONVEYOR)
 		conveyor = HUB_PIO_FIRE_N_FORGET;
-#endif
 
 	/*
 	 * Get the current register value.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/klgraph_hack.c linux-2.4.21-rc3/arch/ia64/sn/io/klgraph_hack.c
--- linux-2.4.20/arch/ia64/sn/io/klgraph_hack.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/klgraph_hack.c	2003-05-22 22:06:25.000000000 +0000
@@ -13,13 +13,16 @@
  * initial klgraph information that is normally provided by prom.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
 #include <asm/sn/klconfig.h>
+#include <asm/sn/simulator.h>
 
+extern u64 klgraph_addr[];
 void * real_port;
 void * real_io_base;
 void * real_addr;
@@ -45,10 +48,15 @@
 #define HUBREG                  ((char *)0xc0000a0001e00000)
 #define WIDGET0                 ((char *)0xc0000a0000000000)
 
+#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c
+
 void
 klgraph_hack_init(void)
 {
 
+	u64     *temp;
+
+#ifdef CONFIG_IA64_SGI_SN1
 	/*
 	 * We need to know whether we are booting from PROM or 
 	 * boot from disk.
@@ -60,6 +68,139 @@
 		panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n");
 	}
 
+	convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000);
+
+#else
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		printk("Creating FAKE Klconfig Structure for Embeded Kernel\n");
+		klgraph_addr[0] = 0xe000003000030000;
+
+        /*
+         * klconfig entries initialization - mankato
+         */
+        convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000);
+        convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178);
+        convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000);
+        convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000);
+        convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070);
+        convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70);
+        convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330);
+        convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101);
+        convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67);
+        convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40);
+        convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0);
+        convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000);
+        convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000);
+        convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000);
+        convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101);
+        convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50);
+        convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070);
+        convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000);
+        convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000);
+        convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101);
+        convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0);
+        convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140);
+        convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000);
+        convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000);
+        convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101);
+        convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190);
+        convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000);
+        convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140);
+        convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000);
+        convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000);
+        convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000);
+        convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000);
+        /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */
+        convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000);
+        convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000);
+        convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000);
+        convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000);
+        convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000);
+        convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000);
+        convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001);
+        convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000);
+        convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff);
+        convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200);
+        convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000);
+        convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000);
+        convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000);
+        convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff);
+        convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000);
+        convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000);
+        convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000);
+        convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000);
+        convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a);
+        convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000);
+        convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000);
+        convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e);
+        convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000);
+        convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000);
+        convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e);
+        convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000);
+        convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff);
+        convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077);
+        convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8);
+        convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000);
+        convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002);
+        convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000);
+        convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000);
+        convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000);
+        convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f);
+        convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff);
+        convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9);
+        convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c);
+        convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0);
+        convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000);
+        convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003);
+        convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000);
+        convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000);
+        convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004);
+        convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004);
+        convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000);
+        convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000);
+        convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000);
+        convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000);
+        convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005);
+        convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000);
+        convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000);
+        convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000);
+        convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006);
+        convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000);
+        convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000);
+        convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff);
+        convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000);
+        convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001);
+        convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff);
+        convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000);
+        convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002);
+        convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff);
+        convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000);
+        convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003);
+        convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff);
+        convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000);
+}
+
+#endif
+
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/labelcl.c linux-2.4.21-rc3/arch/ia64/sn/io/labelcl.c
--- linux-2.4.20/arch/ia64/sn/io/labelcl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/labelcl.c	2003-05-22 22:06:41.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
 */
 
 #include <linux/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pci.c linux-2.4.21-rc3/arch/ia64/sn/io/pci.c
--- linux-2.4.20/arch/ia64/sn/io/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/pci.c	2003-05-22 22:06:39.000000000 +0000
@@ -230,7 +230,7 @@
 void __init
 sn_pci_find_bios(void)
 {
-	extern struct pci_ops pci_conf;
+	extern struct pci_ops *pci_root_ops;
 	/*
 	 * Go initialize our IO Infrastructure ..
 	 */
@@ -239,7 +239,7 @@
 	sgi_master_io_infr_init();
 
 	/* sn_io_infrastructure_init(); */
-	pci_conf = snia64_pci_ops;
+	pci_root_ops = &snia64_pci_ops;
 }
 
 void
@@ -276,15 +276,9 @@
                 d->resource[i].flags = 0UL;
         }
 
-	/*
-	 * Hardcode Device 4 register(IOC3 is in Slot 4) to set the 
-	 * DEV_DIRECT bit.  This will not work if IOC3 is not on Slot 
-	 * 4.
-	 */
-	DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220);
-
- 	*(volatile u32 *)0xc0000a000f000220 |= 0x90000; 
-
+#ifdef CONFIG_IA64_SGI_SN1
+	*(volatile u32 *)0xc0000a000f000220 |= 0x90000;
+#endif
         d->subsystem_vendor = 0;
         d->subsystem_device = 0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pci_dma.c linux-2.4.21-rc3/arch/ia64/sn/io/pci_dma.c
--- linux-2.4.20/arch/ia64/sn/io/pci_dma.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/pci_dma.c	2003-05-22 22:06:39.000000000 +0000
@@ -9,6 +9,7 @@
  * a description of how these routines should be used.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/string.h>
@@ -31,18 +32,6 @@
 #include <asm/sn/pci/pci_bus_cvlink.h>
 #include <asm/sn/nag.h>
 
-/* DMA, PIO, and memory allocation flags */
-#ifdef CONFIG_IA64_SGI_SN1
-#define DMA_DATA_FLAGS		( PCIIO_BYTE_STREAM | PCIIO_DMA_DATA )
-#define DMA_CONTROL_FLAGS	( PCIIO_BYTE_STREAM | PCIBR_BARRIER | \
-				  PCIIO_DMA_CMD )
-#elif defined(CONFIG_IA64_SGI_SN2)
-#define DMA_DATA_FLAGS		( PCIIO_DMA_DATA )
-#define DMA_CONTROL_FLAGS	( PCIBR_BARRIER | PCIIO_DMA_CMD )
-#else
-#error need to define DMA mapping flags for this platform
-#endif
-
 /*
  * For ATE allocations
  */
@@ -129,9 +118,6 @@
 		}
 	}
 
-	printk(KERN_WARNING "find_sn_dma_map: Unable find the corresponding "
-	       "dma map\n");
-
 	return NULL;
 }
 
@@ -151,12 +137,15 @@
 sn_dma_sync(struct pci_dev *hwdev)
 {
 
+#ifdef SN_DMA_SYNC
+
 	struct sn_device_sysdata *device_sysdata;
 	volatile unsigned long dummy;
 
 	/*
-	 * It is expected that on an IA64 platform, a DMA sync ensures that 
-	 * all the DMA from a particular device is complete and coherent.  We
+	 * A DMA sync is supposed to ensure that 
+	 * all the DMA from a particular device
+	 * is complete and coherent.  We
 	 * try to do this by
 	 *	1. flushing the write wuffers from Bridge
 	 *	2. flushing the Xbow port.
@@ -167,12 +156,13 @@
 	dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync;
 
 	/*
-	 * For the Xbow port flush, we maybe denied the request because 
+	 * For the Xbow port flush, we may be denied the request because 
 	 * someone else may be flushing the port .. try again.
 	 */
 	while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) {
 		udelay(2);
 	}
+#endif
 }
 
 /**
@@ -183,13 +173,12 @@
  *
  * pci_alloc_consistent() returns a pointer to a memory region suitable for
  * coherent DMA traffic to/from a PCI device.  On SN platforms, this means
- * that @dma_handle will have the PCIBR_BARRIER and PCIIO_DMA_CMD flags
- * set.
+ * that @dma_handle will have the %PCIIO_DMA_CMD flag set.
  *
  * This interface is usually used for "command" streams (e.g. the command
  * queue for a SCSI controller).  See Documentation/DMA-mapping.txt for
- * more information.  Note that this routine should always put a 32 bit
- * DMA address into @dma_handle.  This is because most other platforms
+ * more information.  Note that this routine will always put a 32 bit
+ * DMA address into @dma_handle.  This is because most devices
  * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_
  * DMAs, and unfortunately this interface has to cater to the LCD.  Oh well.
  *
@@ -232,15 +221,40 @@
 	/* physical addr. of the memory we just got */
 	phys_addr = __pa(cpuaddr);
 
+	/*
+	 * This will try to use a Direct Map register to do the
+	 * 32 bit DMA mapping, but it may not succeed if another
+	 * device on the same bus is already mapped with different
+	 * attributes or to a different memory region.
+	 */
+#ifdef CONFIG_IA64_SGI_SN1
 	*dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					  DMA_CONTROL_FLAGS);
+					  PCIIO_BYTE_STREAM |
+					  PCIIO_DMA_CMD);
+#elif defined(CONFIG_IA64_SGI_SN2)
+	*dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					  PCIIO_DMA_CMD);
+#else
+#error unsupported platform
+#endif
+
 	/*
 	 * It is a 32 bit card and we cannot do direct mapping,
-	 * so we use an ATE.
+	 * so we try to use an ATE.
 	 */
 	if (!(*dma_handle)) {
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
-					     DMA_CONTROL_FLAGS | PCIIO_FIXED);
+					     PCIIO_BYTE_STREAM |
+					     PCIIO_DMA_CMD);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
+				((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					     PCIIO_DMA_CMD);
+#else
+#error unsupported platform
+#endif
 		if (!dma_map) {
 			printk(KERN_ERR "sn_pci_alloc_consistent: Unable to "
 			       "allocate anymore 32 bit page map entries.\n");
@@ -250,13 +264,7 @@
 							     size);
 		sn_dma_map = (struct sn_dma_maps_s *)dma_map;
 		sn_dma_map->dma_addr = *dma_handle;
-		printk(KERN_INFO "%s: PMU mapping: %p\n", __FUNCTION__,
-		       (void *)*dma_handle);
 	}
-	else
-		printk(KERN_INFO "%s: direct mapping: %p\n", __FUNCTION__,
-		       (void *)*dma_handle);
-	
 
         return cpuaddr;
 }
@@ -359,7 +367,9 @@
 		if (IS_PCIA64(hwdev)) {
 			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
-						       DMA_DATA_FLAGS | PCIIO_DMA_A64 );
+			       ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+						       PCIIO_DMA_DATA |
+						       PCIIO_DMA_A64);
 			sg->address = (char *)dma_addr;
 			continue;
 		}
@@ -368,9 +378,19 @@
 		 * Handle 32-63 bit cards via direct mapping
 		 */
 		if (IS_PCI32G(hwdev)) {
+#ifdef CONFIG_IA64_SGI_SN1
 			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
-						       DMA_DATA_FLAGS);
+						       PCIIO_BYTE_STREAM |
+						       PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+						       sg->length,
+					((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+						       PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 			/*
 			 * See if we got a direct map entry
 			 */
@@ -386,8 +406,17 @@
 		 * so we use an ATE.
 		 */
 		dma_map = 0;
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
-					     DMA_DATA_FLAGS);
+					     PCIIO_BYTE_STREAM |
+					     PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
+				((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					     PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 		if (!dma_map) {
 			printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
 			       "anymore 32 bit page map entries.\n");
@@ -395,7 +424,7 @@
 		}
 		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
 		sg->address = (char *)dma_addr;
-		sg->page = (char *)dma_map;
+		sg->page = (struct page *)dma_map;
 		
 	}
 
@@ -474,7 +503,8 @@
 		BUG();
 
 	/* SN cannot support DMA addresses smaller than 32 bits. */
-	if (IS_PCI32L(hwdev)) return 0;
+	if (IS_PCI32L(hwdev))
+		return 0;
 
 	/*
 	 * find vertex for the device
@@ -489,23 +519,32 @@
 	phys_addr = __pa(ptr);
 
 	if (IS_PCIA64(hwdev)) {
-		/*
-		 * This device supports 64 bit DMA addresses.
-		 */
+		/* This device supports 64 bit DMA addresses. */
 		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					       DMA_DATA_FLAGS | PCIIO_DMA_A64);
+		       ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					       PCIIO_DMA_DATA |
+					       PCIIO_DMA_A64);
 		return dma_addr;
 	}
 
 	/*
-	 * Devices that supports 32 bit to 63 bit DMA addresses get
+	 * Devices that support 32 bit to 63 bit DMA addresses get
 	 * 32 bit DMA addresses.
 	 *
 	 * First try to get a 32 bit direct map register.
 	 */
 	if (IS_PCI32G(hwdev)) {
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					       DMA_DATA_FLAGS);
+					       PCIIO_BYTE_STREAM |
+					       PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					       PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 		if (dma_addr)
 			return dma_addr;
 	}
@@ -515,11 +554,20 @@
 	 * let's use the PMU instead.
 	 */
 	dma_map = NULL;
-	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, DMA_DATA_FLAGS);
+#ifdef CONFIG_IA64_SGI_SN1
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM |
+				     PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, 
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+			PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 
 	if (!dma_map) {
 		printk(KERN_ERR "pci_map_single: Unable to allocate anymore "
-		       "32 bits page map entries.\n");
+		       "32 bit page map entries.\n");
 		BUG();
 	}
 
@@ -628,7 +676,9 @@
  * properly.  For example, if your device can only drive the low 24-bits
  * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
  * this function.  Of course, SN only supports devices that have 32 or more
- * address bits.
+ * address bits when using the PMU.  We could theoretically support <32 bit
+ * cards using direct mapping, but we'll worry about that later--on the off
+ * chance that someone actually wants to use such a card.
  */
 int
 sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pciba.c linux-2.4.21-rc3/arch/ia64/sn/io/pciba.c
--- linux-2.4.20/arch/ia64/sn/io/pciba.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/pciba.c	2003-05-22 22:06:25.000000000 +0000
@@ -285,45 +285,6 @@
 static devfs_handle_t pciba_devfs_handle;
 
 
-#if !defined(CONFIG_IA64_SGI_SN1)
-
-static status __init
-register_with_devfs(void)
-{
-	struct pci_dev * dev;
-	devfs_handle_t device_dir_handle;
-	char devfs_path[40];
-
-	TRACE();
-
-	pciba_devfs_handle = devfs_mk_dir(NULL, "pci", NULL);
-	if (pciba_devfs_handle == NULL)
-		return failure;
-
-	/* FIXME: don't forget /dev/pci/mem & /dev/pci/io */
-
-	pci_for_each_dev(dev) {
-		sprintf(devfs_path, "%02x/%02x.%x",
-			dev->bus->number,
-			PCI_SLOT(dev->devfn),
-			PCI_FUNC(dev->devfn));
-    
-		device_dir_handle =
-			devfs_mk_dir(pciba_devfs_handle, devfs_path, NULL);
-		if (device_dir_handle == NULL)
-			return failure;
-
-		if (register_pci_device(device_dir_handle, dev) == failure) {
-			devfs_unregister(pciba_devfs_handle);
-			return failure;
-		}
-	}
-
-	return success;
-}
-
-#else
-
 extern devfs_handle_t
 devfn_to_vertex(unsigned char busnum, unsigned int devfn);
 
@@ -352,9 +313,6 @@
 	return success;
 }
 
-#endif /* CONFIG_IA64_SGI_SN1 */
-
-
 static void __exit
 unregister_with_devfs(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sgi_if.c linux-2.4.21-rc3/arch/ia64/sn/io/sgi_if.c
--- linux-2.4.20/arch/ia64/sn/io/sgi_if.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sgi_if.c	2003-05-22 22:06:46.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -20,14 +20,50 @@
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/slotnum.h>
 
+unsigned char Is_pic_on_this_nasid[512];	/* non-0 when this is a pic shub */
+
 void *
 snia_kmem_zalloc(size_t size, int flag)
 {
         void *ptr = kmalloc(size, GFP_KERNEL);
-        BZERO(ptr, size);
-        return ptr;
+	if ( ptr )
+        	BZERO(ptr, size);
+        return(ptr);
+}
+
+void
+snia_kmem_free(void *ptr, size_t size)
+{
+        kfree(ptr);
+}
+
+int
+nic_vertex_info_match(devfs_handle_t v, char *s)
+{
+	/* we don't support this */
+	return(0);
 }
 
+/*
+ * the alloc/free_node routines do a simple kmalloc for now ..
+ */
+void *
+snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node)
+{
+	/* someday will Allocate on node 'node' */
+	return(kmalloc(size, GFP_KERNEL));
+}
+
+void *
+snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node)
+{
+	void *ptr = kmalloc(size, GFP_KERNEL);
+	if ( ptr )
+		BZERO(ptr, size);
+        return(ptr);
+}
+
+
 #define xtod(c)         ((c) <= '9' ? '0' - (c) : 'a' - (c) - 10)
 long
 atoi(register char *p)
@@ -67,3 +103,111 @@
         }
         return (neg ? n : -n);
 }
+
+char *
+strtok_r(char *string, const char *sepset, char **lasts)
+{
+        register char   *q, *r;
+
+        /*first or subsequent call*/
+        if (string == NULL)
+                string = *lasts;
+
+        if(string == 0)         /* return if no tokens remaining */
+                return(NULL);
+
+        q = string + strspn(string, sepset);    /* skip leading separators */
+
+        if(*q == '\0') {                /* return if no tokens remaining */
+                *lasts = 0;     /* indicate this is last token */
+                return(NULL);
+        }
+
+        if((r = strpbrk(q, sepset)) == NULL)    /* move past token */
+                *lasts = 0;     /* indicate this is last token */
+        else {
+                *r = '\0';
+                *lasts = r+1;
+        }
+        return(q);
+}
+
+/*
+ * print_register() allows formatted printing of bit fields.  individual
+ * bit fields are described by a struct reg_desc, multiple bit fields within
+ * a single word can be described by multiple reg_desc structures.
+ * %r outputs a string of the format "<bit field descriptions>"
+ * %R outputs a string of the format "0x%x<bit field descriptions>"
+ *
+ * The fields in a reg_desc are:
+ *	unsigned long long rd_mask; An appropriate mask to isolate the bit field
+ *				within a word, and'ed with val
+ *
+ *	int rd_shift;		A shift amount to be done to the isolated
+ *				bit field.  done before printing the isolate
+ *				bit field with rd_format and before searching
+ *				for symbolic value names in rd_values
+ *
+ *	char *rd_name;		If non-null, a bit field name to label any
+ *				out from rd_format or searching rd_values.
+ *				if neither rd_format or rd_values is non-null
+ *				rd_name is printed only if the isolated
+ *				bit field is non-null.
+ *
+ *	char *rd_format;	If non-null, the shifted bit field value
+ *				is printed using this format.
+ *
+ *	struct reg_values *rd_values;	If non-null, a pointer to a table
+ *				matching numeric values with symbolic names.
+ *				rd_values are searched and the symbolic
+ *				value is printed if a match is found, if no
+ *				match is found "???" is printed.
+ *				
+ */
+
+void
+print_register(unsigned long long reg, struct reg_desc *addr)
+{
+	register struct reg_desc *rd;
+	register struct reg_values *rv;
+	unsigned long long field;
+	int any;
+
+	printk("<");
+	any = 0;
+	for (rd = addr; rd->rd_mask; rd++) {
+		field = reg & rd->rd_mask;
+		field = (rd->rd_shift > 0) ? field << rd->rd_shift : field >> -rd->rd_shift;
+		if (any && (rd->rd_format || rd->rd_values || (rd->rd_name && field)))
+			printk(",");
+		if (rd->rd_name) {
+			if (rd->rd_format || rd->rd_values || field) {
+				printk("%s", rd->rd_name);
+				any = 1;
+			}
+			if (rd->rd_format || rd->rd_values) {
+				printk("=");
+				any = 1;
+			}
+		}
+		/* You can have any format so long as it is %x */
+		if (rd->rd_format) {
+			printk("%llx", field);
+			any = 1;
+			if (rd->rd_values)
+				printk(":");
+		}
+		if (rd->rd_values) {
+			any = 1;
+			for (rv = rd->rd_values; rv->rv_name; rv++) {
+				if (field == rv->rv_value) {
+					printk("%s", rv->rv_name);
+					break;
+				}
+			}
+			if (rv->rv_name == NULL)
+				printk("???");
+		}
+	}
+	printk(">\n");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sgi_io_sim.c linux-2.4.21-rc3/arch/ia64/sn/io/sgi_io_sim.c
--- linux-2.4.20/arch/ia64/sn/io/sgi_io_sim.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sgi_io_sim.c	2003-05-22 22:06:40.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
@@ -71,6 +71,9 @@
  */
 static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL;
 nasid_t console_nasid = (nasid_t)-1;
+#if !defined(CONFIG_IA64_SGI_SN1)
+char master_baseio_wid;
+#endif
 static char console_wid;
 static char console_pcislot;
 
@@ -92,6 +95,7 @@
                 return 0;
 }
 
+#if defined(CONFIG_IA64_SGI_SN1)
 int
 is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid)
 {
@@ -111,6 +115,29 @@
                 return 0;
         }
 }
+#else
+int
+is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid)
+{
+	extern nasid_t master_baseio_nasid;
+
+        /*
+         * If the widget numbers are different, we're not the master.
+         */
+        if (test_wid != (xwidgetnum_t)master_baseio_wid) {
+                return 0;
+	}
+
+        /*
+         * If the NASIDs are the same or equivalent, we're the master.
+         */
+        if (check_nasid_equiv(test_nasid, master_baseio_nasid)) {
+                return 1;
+        } else {
+                return 0;
+        }
+}
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 /*
  * Routines provided by ml/SN/nvram.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/Makefile linux-2.4.21-rc3/arch/ia64/sn/io/sn1/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn1/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/Makefile	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,25 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn1 io routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+O_TARGET := snio.o
+
+export-objs := pciio.o
+
+obj-$(CONFIG_IA64_SGI_SN1)	+= ml_SN_intr.o mem_refcnt.o hubcounters.o \
+				   ip37.o huberror.o hub_intr.o pcibr.o \
+				   eeprom.o l1.o l1_command.o pciio.o \
+				   klconflib.o klgraph.o \
+				   efi-rtc.o xbow.o xtalk.o \
+				   ml_SN_init.o ml_iograph.o module.o \
+				   pci_bus_cvlink.o sgi_io_init.o
+
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/eeprom.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/eeprom.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/eeprom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/eeprom.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,1421 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * WARNING:     There is more than one copy of this file in different isms.
+ *              All copies must be kept exactly in sync.
+ *              Do not modify this file without also updating the following:
+ *
+ *              irix/kern/io/eeprom.c
+ *              stand/arcs/lib/libsk/ml/eeprom.c
+ *		stand/arcs/lib/libkl/io/eeprom.c
+ *
+ *      (from time to time they might not be in sync but that's due to bringup
+ *       activity - this comment is to remind us that they eventually have to
+ *       get back together)
+ *
+ * eeprom.c
+ *
+ * access to board-mounted EEPROMs via the L1 system controllers
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/simulator.h>
+
+#if defined(EEPROM_DEBUG)
+#define db_printf(x) printk x
+#else
+#define db_printf(x) printk x
+#endif
+
+#define BCOPY(x,y,z)	memcpy(y,x,z)
+
+#define UNDERSCORE	0	/* don't convert underscores to hyphens */
+#define HYPHEN		1	/* convert underscores to hyphens */
+
+void		copy_ascii_field( char *to, char *from, int length,
+			          int change_underscore );
+uint64_t	generate_unique_id( char *sn, int sn_len );
+uchar_t		char_to_base36( char c );
+int		nicify( char *dst, eeprom_brd_record_t *src );
+static void	int64_to_hex_string( char *out, uint64_t val );
+
+// extern int router_lock( net_vec_t, int, int );
+// extern int router_unlock( net_vec_t );
+#define ROUTER_LOCK(p) 	// router_lock(p, 10000, 3000000)
+#define ROUTER_UNLOCK(p) 	// router_unlock(p)
+
+#define IP27LOG_OVNIC           "OverrideNIC"
+
+
+/* the following function converts an EEPROM record to a close facsimile
+ * of the string returned by reading a Dallas Semiconductor NIC (see
+ * one of the many incarnations of nic.c for details on that driver)
+ */
+int nicify( char *dst, eeprom_brd_record_t *src )
+{
+    int field_len;
+    uint64_t unique_id;
+    char *cur_dst = dst;
+    eeprom_board_ia_t   *board;
+
+    board   = src->board_ia;
+    ASSERT( board );  /* there should always be a board info area */
+
+    /* copy part number */
+    strcpy( cur_dst, "Part:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->part_num_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN );
+    cur_dst += field_len;
+
+    /* copy product name */
+    strcpy( cur_dst, ";Name:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII );
+    field_len = board->product_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE );
+    cur_dst += field_len;
+
+    /* copy serial number */
+    strcpy( cur_dst, ";Serial:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->serial_num_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->serial_num, field_len,
+		      HYPHEN);
+
+    cur_dst += field_len;
+
+    /* copy revision */
+    strcpy( cur_dst, ";Revision:");
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->board_rev_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN );
+    cur_dst += field_len;
+
+    /* EEPROMs don't have equivalents for the Group, Capability and
+     * Variety fields, so we pad these with 0's
+     */
+    strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" );
+    cur_dst += strlen( cur_dst );
+
+    /* use the board serial number to "fake" a laser id */
+    strcpy( cur_dst, ";Laser:" );
+    cur_dst += strlen( cur_dst );
+    unique_id = generate_unique_id( board->serial_num,
+				    board->serial_num_tl & FIELD_LENGTH_MASK );
+    int64_to_hex_string( cur_dst, unique_id );
+    strcat( dst, ";" );
+
+    return 1;
+}
+
+
+/* These functions borrow heavily from chars2* in nic.c
+ */
+void copy_ascii_field( char *to, char *from, int length,
+		       int change_underscore )
+{
+    int i;
+    for( i = 0; i < length; i++ ) {
+
+	/* change underscores to hyphens if requested */
+	if( from[i] == '_' && change_underscore == HYPHEN )
+	    to[i] = '-';
+
+	/* ; and ; are separators, so mustn't appear within
+	 * a field */
+	else if( from[i] == ':' || from[i] == ';' )
+	    to[i] = '?';
+
+	/* I'm not sure why or if ASCII character 0xff would
+	 * show up in an EEPROM field, but the NIC parsing
+	 * routines wouldn't like it if it did... so we
+	 * get rid of it, just in case. */
+	else if( (unsigned char)from[i] == (unsigned char)0xff )
+	    to[i] = ' ';
+	
+	/* unprintable characters are replaced with . */
+	else if( from[i] < ' ' || from[i] >= 0x7f )
+	    to[i] = '.';
+
+	/* otherwise, just copy the character */
+	else
+	    to[i] = from[i];
+    }
+
+    if( i == 0 ) {
+	to[i] = ' '; /* return at least a space... */
+	i++;
+    }
+    to[i] = 0;	     /* terminating null */
+}
+
+/* Note that int64_to_hex_string currently only has a big-endian
+ * implementation.
+ */
+#ifdef _MIPSEB
+static void int64_to_hex_string( char *out, uint64_t val )
+{
+    int i;
+    uchar_t table[] = "0123456789abcdef";
+    uchar_t *byte_ptr = (uchar_t *)&val;
+    for( i = 0; i < sizeof(uint64_t); i++ ) {
+	out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ];
+	out[i*2+1] = table[ (*byte_ptr) & 0x0f ];
+	byte_ptr++;
+    }
+    out[i*2] = '\0';
+}
+
+#else /* little endian */
+
+static void int64_to_hex_string( char *out, uint64_t val )
+{
+
+
+	printk("int64_to_hex_string needs a little-endian implementation.\n");
+}
+#endif /* _MIPSEB */
+
+/* Convert a standard ASCII serial number to a unique integer
+ * id number by treating the serial number string as though
+ * it were a base 36 number
+ */
+uint64_t generate_unique_id( char *sn, int sn_len )
+{
+    int uid = 0;
+    int i;
+
+    #define VALID_BASE36(c)	((c >= '0' && c <='9') \
+			    ||   (c >= 'A' && c <='Z') \
+			    ||   (c >= 'a' && c <='z'))
+
+    for( i = 0; i < sn_len; i++ ) {
+	if( !VALID_BASE36(sn[i]) )
+	    continue;
+	uid *= 36;
+	uid += char_to_base36( sn[i] );
+    }
+
+    if( uid == 0 )
+	return rtc_time();
+
+    return uid;
+}
+
+uchar_t char_to_base36( char c )
+{
+    uchar_t val;
+
+    if( c >= '0' && c <= '9' )
+	val = (c - '0');
+
+    else if( c >= 'A' && c <= 'Z' )
+	val = (c - 'A' + 10);
+
+    else if( c >= 'a' && c <= 'z' )
+	val = (c - 'a' + 10);
+
+    else val = 0;
+
+    return val;
+}
+
+
+/* given a pointer to the three-byte little-endian EEPROM representation
+ * of date-of-manufacture, this function translates to a big-endian
+ * integer format
+ */
+int eeprom_xlate_board_mfr_date( uchar_t *src )
+{
+    int rval = 0;
+    rval += *src; src++;
+    rval += ((int)(*src) << 8); src ++;
+    rval += ((int)(*src) << 16);
+    return rval;
+}
+
+
+int eeprom_str( char *nic_str, nasid_t nasid, int component )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    if( (component & C_DIMM) == C_DIMM ) {
+	/* this function isn't applicable to DIMMs */
+	return EEP_PARAM;
+    }
+    else {
+	eep.board_ia = &board;
+	eep.spd = NULL;
+	if( !(component & SUBORD_MASK) )
+	    eep.chassis_ia = &chassis;  /* only main boards have a chassis
+					 * info area */
+	else
+	    eep.chassis_ia = NULL;
+    }
+    
+    switch( component & BRICK_MASK ) {
+      case C_BRICK:
+	r = cbrick_eeprom_read( &eep, nasid, component );
+	break;
+      case IO_BRICK:
+	r = iobrick_eeprom_read( &eep, nasid, component );
+	break;
+      default:
+	return EEP_PARAM;  /* must be an invalid component */
+    }
+    if( r )
+	return r;
+    if( !nicify( nic_str, &eep ) )
+	return EEP_NICIFY;
+
+    return EEP_OK;
+}
+
+int vector_eeprom_str( char *nic_str, nasid_t nasid,
+		       int component, net_vec_t path )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    eep.board_ia = &board;
+    if( !(component & SUBORD_MASK) )
+        eep.chassis_ia = &chassis;  /* only main boards have a chassis
+                                     * info area */
+    else
+        eep.chassis_ia = NULL;
+
+    if( !(component & VECTOR) )
+	return EEP_PARAM;
+
+    if( (r = vector_eeprom_read( &eep, nasid, path, component )) )
+	return r;
+
+    if( !nicify( nic_str, &eep ) )
+        return EEP_NICIFY;
+
+    return EEP_OK;
+}
+
+
+int is_iobrick( int nasid, int widget_num )
+{
+    uint32_t wid_reg;
+    int part_num, mfg_num;
+
+    /* Read the widget's WIDGET_ID register to get
+     * its part number and mfg number
+     */
+    wid_reg = *(volatile int32_t *)
+        (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID);
+
+    part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+    mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT;
+
+    /* Is this the "xbow part" of an XBridge?  If so, this
+     * widget is definitely part of an I/O brick.
+     */
+    if( part_num == XXBOW_WIDGET_PART_NUM &&
+	mfg_num == XXBOW_WIDGET_MFGR_NUM )
+
+	return 1;
+
+    /* Is this a "bridge part" of an XBridge?  If so, once
+     * again, we know this widget is part of an I/O brick.
+     */
+    if( part_num == XBRIDGE_WIDGET_PART_NUM &&
+	mfg_num == XBRIDGE_WIDGET_MFGR_NUM )
+
+	return 1;
+
+    return 0;
+}
+
+
+int cbrick_uid_get( nasid_t nasid, uint64_t *uid )
+{
+    char uid_str[32];
+    char msg[BRL1_QSIZE];
+    int subch, len;
+    l1sc_t sc;
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
+     * use that value for the cbrick UID rather than the EEPROM
+     * serial number.
+     */
+#ifdef LOG_GETENV
+    if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 )
+    {
+	/* We successfully read IP27LOG_OVNIC, so return it as the UID. */
+	db_printf(( "cbrick_uid_get:"
+		    "Overriding UID with environment variable %s\n", 
+		    IP27LOG_OVNIC ));
+	*uid = strtoull( uid_str, NULL, 0 );
+	return EEP_OK;
+    }
+#endif
+
+    /* If this brick is retrieving its own uid, use the local l1sc_t to
+     * arbitrate access to the l1; otherwise, set up a new one.
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &sc;
+	sc_init( &sc, nasid, BRL1_LOCALHUB_UART );
+    }
+
+    /* fill in msg with the opcode & params */
+    BZERO( msg, BRL1_QSIZE );
+    if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
+	return EEP_L1;
+
+    if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SER_NUM, 0 )) < 0 )
+    {
+	sc_close( scp, subch );
+	return( EEP_L1 );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( scp, subch, msg, msg, &len ) ) {
+	sc_close( scp, subch );
+	return( EEP_L1 );
+    }
+
+    /* free up subchannel */
+    sc_close(scp, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
+    {
+	return( EEP_L1 );
+    }
+
+    *uid = generate_unique_id( uid_str, strlen( uid_str ) );
+
+    return EEP_OK;
+}
+
+
+int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid )
+{
+    char uid_str[32];
+    char msg[BRL1_QSIZE];
+    int subch, len;
+    l1sc_t sc;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+#define FAIL								\
+    {									\
+	*uid = rtc_time();						\
+	printk( "rbrick_uid_get failed; using current time as uid\n" );	\
+	return EEP_OK;							\
+    }
+
+    ROUTER_LOCK(path);
+    sc_init( &sc, nasid, path );
+
+    /* fill in msg with the opcode & params */
+    BZERO( msg, BRL1_QSIZE );
+    if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) {
+	ROUTER_UNLOCK(path);
+	FAIL;
+    }
+
+    if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SER_NUM, 0 )) < 0 )
+    {
+	ROUTER_UNLOCK(path);
+	sc_close( &sc, subch );
+	FAIL;
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( &sc, subch, msg, msg, &len ) ) {
+	ROUTER_UNLOCK(path);
+	sc_close( &sc, subch );
+	FAIL;
+    }
+
+    /* free up subchannel */
+    ROUTER_UNLOCK(path);
+    sc_close(&sc, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
+    {
+	FAIL;
+    }
+
+    *uid = generate_unique_id( uid_str, strlen( uid_str ) );
+
+    return EEP_OK;
+}
+
+int iobrick_uid_get( nasid_t nasid, uint64_t *uid )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    eep.board_ia = &board;
+    eep.chassis_ia = &chassis;
+    eep.spd = NULL;
+
+    r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
+    if( r != EEP_OK ) {
+        *uid = rtc_time();
+        return r;
+    }
+
+    *uid = generate_unique_id( board.serial_num,
+                               board.serial_num_tl & FIELD_LENGTH_MASK );
+
+    return EEP_OK;
+}
+
+
+int ibrick_mac_addr_get( nasid_t nasid, char *eaddr )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+    char *tmp;
+
+    eep.board_ia = &board;
+    eep.chassis_ia = &chassis;
+    eep.spd = NULL;
+
+    r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
+    if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) {
+	db_printf(( "ibrick_mac_addr_get: "
+		    "Couldn't read MAC address from EEPROM\n" ));
+	return EEP_L1;
+    }
+    else {
+	/* successfully read info area */
+	int ix;
+	tmp = board.mac_addr;
+	for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ )
+	{
+	    *eaddr++ = *tmp++;
+	}
+	*eaddr = '\0';
+    }
+
+    return EEP_OK;
+}
+
+
+/* 
+ * eeprom_vertex_info_set
+ *
+ * Given a vertex handle, a component designation, a starting nasid
+ * and (in the case of a router) a vector path to the component, this
+ * function will read the EEPROM and attach the resulting information
+ * to the vertex in the same string format as that provided by the
+ * Dallas Semiconductor NIC drivers.  If the vertex already has the
+ * string, this function just returns the string.
+ */
+
+extern char *nic_vertex_info_get( devfs_handle_t );
+extern void nic_vmc_check( devfs_handle_t, char * );
+/* the following were lifted from nic.c - change later? */
+#define MAX_INFO 2048
+#define NEWSZ(ptr,sz)   ((ptr) = kern_malloc((sz)))
+#define DEL(ptr) (kern_free((ptr)))
+
+char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v,
+                              net_vec_t path )
+{
+        char *info_tmp;
+        int info_len;
+        char *info;
+
+        /* see if this vertex is already marked */
+        info_tmp = nic_vertex_info_get(v);
+        if (info_tmp) return info_tmp;
+
+        /* get a temporary place for the data */
+        NEWSZ(info_tmp, MAX_INFO);
+        if (!info_tmp) return NULL;
+
+        /* read the EEPROM */
+	if( component & R_BRICK ) {
+	    if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK )
+		return NULL;
+	}
+	else {
+            if( eeprom_str( info_tmp, nasid, component ) != EEP_OK )
+	        return NULL;
+	}
+
+        /* allocate a smaller final place */
+        info_len = strlen(info_tmp)+1;
+        NEWSZ(info, info_len);
+        if (info) {
+                strcpy(info, info_tmp);
+                DEL(info_tmp);
+        } else {
+                info = info_tmp;
+        }
+
+        /* add info to the vertex */
+        hwgraph_info_add_LBL(v, INFO_LBL_NIC,
+                             (arbitrary_info_t) info);
+
+        /* see if someone else got there first */
+        info_tmp = nic_vertex_info_get(v);
+        if (info != info_tmp) {
+            DEL(info);
+            return info_tmp;
+        }
+
+        /* export the data */
+        hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len);
+
+        /* trigger all matching callbacks */
+        nic_vmc_check(v, info);
+
+        return info;
+}
+
+
+/*********************************************************************
+ *
+ * stubs for use until the Bedrock/L1 link is available
+ *
+ */
+
+#include <asm/sn/nic.h>
+
+/* #define EEPROM_TEST */
+
+/* fake eeprom reading functions (replace when the BR/L1 communication
+ * channel is in working order)
+ */
+
+
+/* generate a charater in [0-9A-Z]; if an "extra" character is
+ * specified (such as '_'), include it as one of the possibilities.
+ */
+char random_eeprom_ch( char extra ) 
+{
+    char ch;
+    int modval = 36;
+    if( extra )
+	modval++;
+    
+    ch = rtc_time() % modval;
+
+    if( ch < 10 )
+        ch += '0';
+    else if( ch >= 10 && ch < 36 )
+	ch += ('A' - 10);
+    else
+	ch = extra;
+
+    return ch;
+}
+
+/* create a part number of the form xxx-xxxx-xxx.
+ * It may be important later to generate different
+ * part numbers depending on the component we're
+ * supposed to be "reading" from, so the component
+ * paramter is provided.
+ */
+void fake_a_part_number( char *buf, int component )
+{
+    int i;
+    switch( component ) {
+
+    /* insert component-specific routines here */
+
+    case C_BRICK:
+	strcpy( buf, "030-1266-001" );
+	break;
+    default:
+        for( i = 0; i < 12; i++ ) {
+	    if( i == 3 || i == 8 )
+	        buf[i] = '-';
+	    else
+	        buf[i] = random_eeprom_ch(0);
+        }
+    }
+}
+
+
+/* create a six-character serial number */
+void fake_a_serial_number( char *buf, uint64_t ser )
+{
+    int i;
+    static const char hexchars[] = "0123456789ABCDEF";
+
+    if (ser) {
+	for( i = 5; i >=0; i-- ) {
+	    buf[i] = hexchars[ser & 0xf];
+	    ser >>= 4;
+	}
+    }
+    else {
+	for( i = 0; i < 6; i++ )
+	    buf[i] = random_eeprom_ch(0);
+    }
+}
+
+
+void fake_a_product_name( uchar_t *format, char* buf, int component )
+{
+    switch( component & BRICK_MASK ) {
+
+    case C_BRICK:
+	if( component & SUBORD_MASK ) {
+	    strcpy( buf, "C_BRICK_SUB" );
+	    *format = 0xCB;
+	}
+	else {
+	    strcpy( buf, "IP35" );
+	    *format = 0xC4;
+	}
+	break;
+
+    case R_BRICK:
+        if( component & SUBORD_MASK ) {
+            strcpy( buf, "R_BRICK_SUB" );
+            *format = 0xCB;
+        }
+        else {
+            strcpy( buf, "R_BRICK" );
+            *format = 0xC7;
+        }
+        break;
+
+    case IO_BRICK:
+        if( component & SUBORD_MASK ) {
+            strcpy( buf, "IO_BRICK_SUB" );
+            *format = 0xCC;
+        }
+        else {
+            strcpy( buf, "IO_BRICK" );
+            *format = 0xC8;
+        }
+        break;
+
+    default:
+	strcpy( buf, "UNK_DEVICE" );
+	*format = 0xCA;
+    }
+}
+
+
+
+int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, 
+			   uint64_t ser )
+{
+    eeprom_board_ia_t *board;
+    eeprom_chassis_ia_t *chassis;
+    int i, cs;
+
+    board = buf->board_ia;
+    chassis = buf->chassis_ia;
+
+    if( !(component & SUBORD_MASK) ) {
+	if( !chassis )
+	    return EEP_PARAM;
+	chassis->format = 0;
+	chassis->length = 5;
+	chassis->type = 0x17;
+
+	chassis->part_num_tl = 0xCC;
+	fake_a_part_number( chassis->part_num, component );
+	chassis->serial_num_tl = 0xC6;
+	fake_a_serial_number( chassis->serial_num, ser );
+
+	cs = chassis->format + chassis->length + chassis->type
+	    + chassis->part_num_tl + chassis->serial_num_tl;
+	for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ )
+	    cs += chassis->part_num[i];
+	for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ )
+	    cs += chassis->serial_num[i];
+	chassis->checksum = 256 - (cs % 256);
+    }
+
+    if( !board )
+	return EEP_PARAM;
+    board->format = 0;
+    board->length = 10;
+    board->language = 0;
+    board->mfg_date = 1789200; /* noon, 5/26/99 */
+    board->manuf_tl = 0xC3;
+    strcpy( board->manuf, "SGI" );
+
+    fake_a_product_name( &(board->product_tl), board->product, component );
+
+    board->serial_num_tl = 0xC6;
+    fake_a_serial_number( board->serial_num, ser );
+
+    board->part_num_tl = 0xCC;
+    fake_a_part_number( board->part_num, component );
+
+    board->board_rev_tl = 0xC2;
+    board->board_rev[0] = '0';
+    board->board_rev[1] = '1';
+
+    board->eeprom_size_tl = 0x01;
+    board->eeprom_size = 1;
+
+    board->temp_waiver_tl = 0xC2;
+    board->temp_waiver[0] = '0';
+    board->temp_waiver[1] = '1';
+
+    cs = board->format + board->length + board->language
+	+ (board->mfg_date & 0xFF)
+	+ (board->mfg_date & 0xFF00)
+	+ (board->mfg_date & 0xFF0000)
+	+ board->manuf_tl + board->product_tl + board->serial_num_tl
+	+ board->part_num_tl + board->board_rev_tl
+	+ board->board_rev[0] + board->board_rev[1]
+	+ board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl
+	+ board->temp_waiver[0] + board->temp_waiver[1];
+    for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->manuf[i];
+    for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->product[i];
+    for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->serial_num[i];
+    for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->part_num[i];
+    
+    board->checksum = 256 - (cs % 256);
+
+    return EEP_OK;
+}
+
+#define EEPROM_CHUNKSIZE	64
+
+#if defined(EEPROM_DEBUG)
+#define RETURN_ERROR							\
+{									\
+    printk( "read_ia error return, component 0x%x, line %d"		\
+	    ", address 0x%x, ia code 0x%x\n",				\
+	    l1_compt, __LINE__, sc->subch[subch].target, ia_code );	\
+    return EEP_L1;							\
+}
+
+#else
+#define RETURN_ERROR	return(EEP_L1)
+#endif
+
+int read_ia( l1sc_t *sc, int subch, int l1_compt, 
+	     int ia_code, char *eep_record )
+{
+    char msg[BRL1_QSIZE]; 	   /* message buffer */
+    int len;              	   /* number of bytes used in message buffer */
+    int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */
+    int offset = 0;                /* current offset into info area */
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    BZERO( msg, BRL1_QSIZE );
+
+    /* retrieve EEPROM data in 64-byte chunks
+     */
+
+    while( ia_len )
+    {
+	/* fill in msg with opcode & params */
+	if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				     L1_ADDR_TASK_GENERAL,
+				     L1_REQ_EEPROM, 8,
+				     L1_ARG_INT, l1_compt,
+				     L1_ARG_INT, ia_code,
+				     L1_ARG_INT, offset,
+				     L1_ARG_INT, ia_len )) < 0 )
+	{
+	    RETURN_ERROR;
+	}
+
+	/* send the request to the L1 */
+
+	if( sc_command( sc, subch, msg, msg, &len ) ) {
+	    RETURN_ERROR;
+	}
+
+	/* check response */
+	if( sc_interpret_resp( msg, 5, 
+			       L1_ARG_INT, &ia_len,
+			       L1_ARG_UNKNOWN, &len, eep_record ) < 0 )
+	{
+	    RETURN_ERROR;
+	}
+
+	if( ia_len > EEPROM_CHUNKSIZE )
+	    ia_len = EEPROM_CHUNKSIZE;
+
+	eep_record += EEPROM_CHUNKSIZE;
+	offset += EEPROM_CHUNKSIZE;
+    }
+
+    return EEP_OK;
+}
+
+
+int read_spd( l1sc_t *sc, int subch, int l1_compt,
+	      eeprom_spd_u *spd )
+{
+    char msg[BRL1_QSIZE]; 	    /* message buffer */
+    int len;              	    /* number of bytes used in message buffer */
+    int resp;                       /* l1 response code */
+    int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */
+    int offset = 0;		    /* current offset into spd record */
+    char *spd_p = spd->bytes;	    /* "thumb" for writing to spd */
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    BZERO( msg, BRL1_QSIZE );
+
+    /* retrieve EEPROM data in 64-byte chunks
+     */
+
+    while( spd_len )
+    {
+	/* fill in msg with opcode & params */
+	if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				     L1_ADDR_TASK_GENERAL,
+				     L1_REQ_EEPROM, 8,
+				     L1_ARG_INT, l1_compt,
+				     L1_ARG_INT, L1_EEP_SPD,
+				     L1_ARG_INT, offset,
+				     L1_ARG_INT, spd_len )) < 0 )
+	{
+	    return( EEP_L1 );
+	}
+
+	/* send the request to the L1 */
+	if( sc_command( sc, subch, msg, msg, &len ) ) {
+	    return( EEP_L1 );
+	}
+
+	/* check response */
+	if( (resp = sc_interpret_resp( msg, 5, 
+			       L1_ARG_INT, &spd_len,
+			       L1_ARG_UNKNOWN, &len, spd_p )) < 0 )
+	{
+            /*
+             * translate l1 response code to eeprom.c error codes:
+             * The L1 response will be L1_RESP_NAVAIL if the spd
+             * can't be read (i.e. the spd isn't physically there). It will
+             * return L1_RESP_INVAL if the spd exists, but fails the checksum
+             * test because the eeprom wasn't programmed, programmed incorrectly,
+             * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present,
+             * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is
+             * invalid.
+             */
+            if(resp == L1_RESP_INVAL) {
+                resp = EEP_BAD_CHECKSUM;
+            } else {
+                resp = EEP_L1;
+            }
+            return( resp );
+	}
+
+	if( spd_len > EEPROM_CHUNKSIZE )
+	    spd_len = EEPROM_CHUNKSIZE;
+
+	spd_p += EEPROM_CHUNKSIZE;
+	offset += EEPROM_CHUNKSIZE;
+    }
+    return EEP_OK;
+}
+
+
+int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt,
+		     eeprom_chassis_ia_t *ia )
+{
+    char eep_record[512];          /* scratch area for building up info area */
+    char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
+    int checksum = 0;              /* use to verify eeprom record checksum */
+    int i;
+
+    /* Read in info area record from the L1.
+     */
+    if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record )
+	!= EEP_OK )
+    {
+	return EEP_L1;
+    }
+
+    /* Now we've got the whole info area.  Transfer it to the data structure.
+     */
+
+    eep_rec_p = eep_record;
+    ia->format = *eep_rec_p++;
+    ia->length = *eep_rec_p++;
+    if( ia->length == 0 ) {
+	/* since we're using 8*ia->length-1 as an array index later, make
+	 * sure it's sane.
+	 */
+	db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" ));
+	return EEP_L1;
+    }
+    ia->type = *eep_rec_p++;
+   
+    ia->part_num_tl = *eep_rec_p++;
+
+    (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
+
+    ia->serial_num_tl = *eep_rec_p++;
+
+    BCOPY( eep_rec_p, ia->serial_num, 
+	   (ia->serial_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
+
+    ia->checksum = eep_record[(8 * ia->length) - 1];
+
+    /* verify checksum */
+    eep_rec_p = eep_record;
+    checksum = 0;
+    for( i = 0; i < (8 * ia->length); i++ ) {
+	checksum += *eep_rec_p++;
+    }
+
+    if( (checksum & 0xff) != 0 )
+    {
+	db_printf(( "read_chassis_ia: bad checksum\n" ));
+	db_printf(( "read_chassis_ia: target 0x%x  uart 0x%lx\n",
+			   sc->subch[subch].target, sc->uart ));
+	return EEP_BAD_CHECKSUM;
+    }
+
+    return EEP_OK;
+}
+
+
+int read_board_ia( l1sc_t *sc, int subch, int l1_compt,
+		   eeprom_board_ia_t *ia )
+{
+    char eep_record[512];          /* scratch area for building up info area */
+    char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
+    int checksum = 0;              /* running checksum total */
+    int i;
+
+    BZERO( ia, sizeof( eeprom_board_ia_t ) );
+
+    /* Read in info area record from the L1.
+     */
+    if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record )
+	!= EEP_OK )
+    {
+	db_printf(( "read_board_ia: error reading info area from L1\n" ));
+	return EEP_L1;
+    }
+
+     /* Now we've got the whole info area.  Transfer it to the data structure.
+      */
+
+    eep_rec_p = eep_record;
+    ia->format = *eep_rec_p++;
+    ia->length = *eep_rec_p++;
+    if( ia->length == 0 ) {
+	/* since we're using 8*ia->length-1 as an array index later, make
+	 * sure it's sane.
+	 */
+	db_printf(( "read_board_ia: eeprom length byte of ZERO\n" ));
+	return EEP_L1;
+    }
+    ia->language = *eep_rec_p++;
+    
+    ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p );
+    eep_rec_p += 3;
+
+    ia->manuf_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK);
+
+    ia->product_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK);
+
+    ia->serial_num_tl = *eep_rec_p++;
+    
+    BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK));
+    eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
+
+    ia->part_num_tl = *eep_rec_p++;
+
+    BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
+
+    eep_rec_p++; /* we do not use the FRU file id */
+    
+    ia->board_rev_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK);
+
+    ia->eeprom_size_tl = *eep_rec_p++;
+    ia->eeprom_size = *eep_rec_p++;
+
+    ia->temp_waiver_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->temp_waiver, 
+	   (ia->temp_waiver_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK);
+
+    /* if there's more, we must be reading a main board; get
+     * additional fields
+     */
+    if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
+
+	ia->ekey_G_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_G, 
+	       ia->ekey_G_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK);
+	
+	ia->ekey_P_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_P, 
+	       ia->ekey_P_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK);
+	
+	ia->ekey_Y_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_Y, 
+	       ia->ekey_Y_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK);
+	
+	/* 
+	 * need to get a couple more fields if this is an I brick 
+	 */
+	if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
+
+	    ia->mac_addr_tl = *eep_rec_p++;
+	    BCOPY( eep_rec_p, ia->mac_addr, 
+		   ia->mac_addr_tl & FIELD_LENGTH_MASK );
+	    eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK);
+	    
+	    ia->ieee1394_cfg_tl = *eep_rec_p++;
+	    BCOPY( eep_rec_p, ia->ieee1394_cfg,
+		   ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK );
+	    
+	}
+    }
+
+    ia->checksum = eep_record[(ia->length * 8) - 1];
+
+    /* verify checksum */
+    eep_rec_p = eep_record;
+    checksum = 0;
+    for( i = 0; i < (8 * ia->length); i++ ) {
+	checksum += *eep_rec_p++;
+    }
+
+    if( (checksum & 0xff) != 0 )
+    {
+	db_printf(( "read_board_ia: bad checksum\n" ));
+	db_printf(( "read_board_ia: target 0x%x  uart 0x%lx\n",
+		    sc->subch[subch].target, sc->uart ));
+	return EEP_BAD_CHECKSUM;
+    }
+
+    return EEP_OK;
+}
+
+
+int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp,
+			 int component )
+{
+    int r;
+    uint64_t uid = 0;
+#ifdef LOG_GETENV
+    char uid_str[32];
+#endif
+    int l1_compt, subch;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're targeting a cbrick */
+    if( !(component & C_BRICK) )
+	return EEP_PARAM;
+
+    /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
+     * use that value for the cbrick UID rather than the EEPROM
+     * serial number.
+     */
+#ifdef LOG_GETENV
+    if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 )
+    {
+	db_printf(( "_cbrick_eeprom_read: "
+		    "Overriding UID with environment variable %s\n", 
+		    IP27LOG_OVNIC ));
+	uid = strtoull( uid_str, NULL, 0 );
+    }
+#endif
+
+    if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
+	return EEP_L1;
+
+    if((component & C_DIMM) == C_DIMM) {
+        l1_compt = L1_EEP_DIMM(component & COMPT_MASK);
+        r = read_spd(scp,subch,l1_compt, buf->spd);
+        sc_close(scp,subch);
+        return(r);
+    }
+
+    switch( component )
+    {
+      case C_BRICK:
+	/* c-brick motherboard */
+	l1_compt = L1_EEP_NODE;
+	r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
+	if( r != EEP_OK ) {
+	    sc_close( scp, subch );
+	    db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
+	    return fake_an_eeprom_record( buf, component, uid );
+	}
+	if( uid ) {
+	    /* If IP27LOG_OVNIC is set, we want to put that value
+	     * in as our UID. */
+	    fake_a_serial_number( buf->chassis_ia->serial_num, uid );
+	    buf->chassis_ia->serial_num_tl = 6;
+	}
+	break;
+
+      case C_PIMM:
+	/* one of the PIMM boards */
+	l1_compt = L1_EEP_PIMM( component & COMPT_MASK );
+	break;
+
+      default:
+	/* unsupported board type */
+	sc_close( scp, subch );
+	return EEP_PARAM;
+    }
+	      
+    r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
+    sc_close( scp, subch );
+    if( r != EEP_OK ) 
+    {
+	db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
+	return fake_an_eeprom_record( buf, component, uid );
+    }
+    return EEP_OK;
+}
+
+
+int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+    		        int component )
+{
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* If this brick is retrieving its own uid, use the local l1sc_t to
+     * arbitrate access to the l1; otherwise, set up a new one (prom) or
+     * use an existing remote l1sc_t (kernel)
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
+    }
+
+    return _cbrick_eeprom_read( buf, scp, component );
+}
+
+
+int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+			 int component )
+{
+    int r;
+    int l1_compt, subch;
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're talking to an applicable brick */
+    if( !(component & IO_BRICK) ) {
+	return EEP_PARAM;
+    }
+
+    /* If we're talking to this c-brick's attached io brick, use
+     * the local l1sc_t; otherwise, set up a new one (prom) or
+     * use an existing remote l1sc_t (kernel)
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
+    }
+
+    if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 )
+	return EEP_L1;
+
+
+    switch( component )
+    {
+      case IO_BRICK:
+	/* IO brick motherboard */
+	l1_compt = L1_EEP_LOGIC;
+	r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
+
+	if( r != EEP_OK ) {
+	    sc_close( scp, subch );
+	/*
+	 * Whenever we no longer need to test on hardware
+	 * that does not have EEPROMS, then this can be removed.
+	 */
+	    r = fake_an_eeprom_record( buf, component, rtc_time() );
+	    return r;
+	}
+	break;
+
+      case IO_POWER:
+	/* IO brick power board */
+	l1_compt = L1_EEP_POWER;
+	break;
+
+      default:
+	/* unsupported board type */
+	sc_close( scp, subch );
+	return EEP_PARAM;
+    }
+
+    r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
+    sc_close( scp, subch );
+    if( r != EEP_OK ) {
+	return r;
+    }
+    return EEP_OK;
+}
+
+
+int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+			net_vec_t path, int component )
+{
+    int r;
+    uint64_t uid = 0;
+    int l1_compt, subch;
+    l1sc_t sc;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're targeting an applicable brick */
+    if( !(component & VECTOR) )
+	return EEP_PARAM;
+
+    switch( component & BRICK_MASK )
+    {
+      case R_BRICK:
+	ROUTER_LOCK( path );
+	sc_init( &sc, nasid, path );
+
+	if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 )
+	{
+	    db_printf(( "vector_eeprom_read: couldn't open subch\n" ));
+	    ROUTER_UNLOCK(path);
+	    return EEP_L1;
+	}
+	switch( component )
+	{
+	  case R_BRICK:
+	    /* r-brick motherboard */
+	    l1_compt = L1_EEP_LOGIC;
+    	    r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia );
+	    if( r != EEP_OK ) {
+		sc_close( &sc, subch );
+		ROUTER_UNLOCK( path );
+		printk( "vector_eeprom_read: couldn't get rbrick eeprom info;"
+			" using current time as uid\n" );
+		uid = rtc_time();
+		db_printf(("vector_eeprom_read: using a fake eeprom record\n"));
+		return fake_an_eeprom_record( buf, component, uid );
+	    }
+	    break;
+
+	  case R_POWER:
+	    /* r-brick power board */
+	    l1_compt = L1_EEP_POWER;
+	    break;
+
+	  default:
+	    /* unsupported board type */
+	    sc_close( &sc, subch );
+	    ROUTER_UNLOCK( path );
+	    return EEP_PARAM;
+	}
+	r = read_board_ia( &sc, subch, l1_compt, buf->board_ia );
+	sc_close( &sc, subch );
+	ROUTER_UNLOCK( path );
+	if( r != EEP_OK ) {
+	    db_printf(( "vector_eeprom_read: using a fake eeprom record\n" ));
+	    return fake_an_eeprom_record( buf, component, uid );
+	}
+	return EEP_OK;
+
+      case C_BRICK:
+	sc_init( &sc, nasid, path );
+	return _cbrick_eeprom_read( buf, &sc, component );
+
+      default:
+	/* unsupported brick type */
+	return EEP_PARAM;
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/efi-rtc.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/efi-rtc.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/efi-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/efi-rtc.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,202 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2001 by Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/efi.h>
+#include <asm/sn/klclock.h>
+
+/*
+ * No locking necessary when this is called from efirtc which protects us
+ * from racing by efi_rtc_lock.
+ */
+#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3))
+#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr))
+#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data))
+
+#define TOD_SGS_M48T35		1
+#define TOD_DALLAS_DS1386	2
+
+#define TYPE_IOC3		1
+#define TYPE_IOC4		2
+
+static unsigned long nvram_base = 0;
+static int tod_chip_type;
+static int ioc_type;
+
+static int
+get_tod_chip_type(void)
+{
+	unsigned char testval;
+
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+	write_io_port(RTC_DAL_DAY_ADDR, 0xff);
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+
+	testval = read_io_port(RTC_DAL_DAY_ADDR);
+	if (testval == 0xff)
+		return TOD_SGS_M48T35;
+
+	return TOD_DALLAS_DS1386;
+}
+
+efi_status_t
+ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	memset(time, 0, sizeof(*time));
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
+
+		time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF;
+		time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR));
+		time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR));
+		time->nanosecond = 0;
+
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+
+		time->nanosecond = 0;
+		time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR));
+		time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR));
+		time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF;
+
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	if (caps) {
+		caps->resolution = 50000000;	/*  50PPM */
+		caps->accuracy = 1000;		/*  1ms */
+		caps->sets_to_zero = 0;
+	}
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t ioc3_set_time (efi_time_t *t)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE);
+        	write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_SGS_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_SGS_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+		write_io_port(RTC_DAL_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_DAL_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	return EFI_SUCCESS;
+}
+
+/* The following two are not supported atm.  */
+static efi_status_t
+ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static __init int efi_ioc_time_init(void)
+{
+	struct pci_dev *dev = NULL;
+	static void *ioc_base;
+
+        while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID, dev))) {
+		if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+			ioc_type = TYPE_IOC3;
+			break;
+		}
+		else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) {
+			ioc_type = TYPE_IOC4;
+			break;
+		}
+		else
+			;; // keep looking
+	}
+
+	if ( !dev ) {
+		printk(KERN_CRIT "Couldn't find master IOC\n");
+		return -ENODEV;
+	}
+
+	ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+	if ( ioc_type == TYPE_IOC3 )
+		nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0;
+	if ( ioc_type == TYPE_IOC4 )
+		nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0;
+
+	tod_chip_type = get_tod_chip_type();
+	if (tod_chip_type == 1)
+		printk(KERN_NOTICE "TOD type is SGS M48T35\n");
+	else if (tod_chip_type == 2)
+		printk(KERN_NOTICE "TOD type is Dallas DS1386\n");
+	else
+		printk(KERN_CRIT "No or unknown TOD\n");
+
+	efi.get_time = ioc3_get_time;
+	efi.set_time = ioc3_set_time;
+	efi.get_wakeup_time = ioc3_get_wakeup_time;
+	efi.set_wakeup_time = ioc3_set_wakeup_time;
+
+	return 0;
+}
+
+module_init(efi_ioc_time_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/hubcounters.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/hubcounters.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/hubcounters.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/hubcounters.c	2003-05-22 22:06:28.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc.
- * All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/klconflib.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/klconflib.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/klconflib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/klconflib.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,979 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/module.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+
+#define printf printk
+int hasmetarouter;
+
+#define LDEBUG 0
+#define NIC_UNKNOWN ((nic_t) -1)
+
+#undef DEBUG_KLGRAPH
+#ifdef DEBUG_KLGRAPH
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_KLGRAPH */
+
+static void sort_nic_names(lboard_t *) ;
+
+u64 klgraph_addr[MAX_COMPACT_NODES];
+int module_number = 0;
+
+lboard_t *
+find_lboard(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (start->brd_type == brd_type)
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_class(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+klinfo_t *
+find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
+{
+	int index, j;
+
+	if (kli == (klinfo_t *)NULL) {
+		index = 0;
+	} else {
+		for (j = 0; j < KLCF_NUM_COMPS(brd); j++) {
+			if (kli == KLCF_COMP(brd, j))
+				break;
+		}
+		index = j;
+		if (index == KLCF_NUM_COMPS(brd)) {
+			DBG("find_component: Bad pointer: 0x%p\n", kli);
+			return (klinfo_t *)NULL;
+		}
+		index++;	/* next component */
+	}
+	
+	for (; index < KLCF_NUM_COMPS(brd); index++) {		
+		kli = KLCF_COMP(brd, index);
+		DBG("find_component: brd %p kli %p  request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli));
+		if (KLCF_COMP_TYPE(kli) == struct_type)
+			return kli;
+	}
+
+	/* Didn't find it. */
+	return (klinfo_t *)NULL;
+}
+
+klinfo_t *
+find_first_component(lboard_t *brd, unsigned char struct_type)
+{
+	return find_component(brd, (klinfo_t *)NULL, struct_type);
+}
+
+lboard_t *
+find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (MODULE_MATCH(start->brd_module, mod) &&
+		    (start->brd_slot == slot))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module(lboard_t *start, moduleid_t mod)
+{
+        /* Search all boards stored on this node. */
+        while (start) {
+                if (MODULE_MATCH(start->brd_module, mod))
+                        return start;
+                start = KLCF_NEXT(start);
+        }
+
+        /* Didn't find it. */
+        return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module_class(lboard_t *start, moduleid_t mod,
+                                                unsigned char brd_type)
+{
+	while (start) {
+		DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type);
+
+		if (MODULE_MATCH(start->brd_module, mod) &&
+			(KLCLASS(start->brd_type) == KLCLASS(brd_type)))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+
+/*
+ * Convert a NIC name to a name for use in the hardware graph.
+ */
+void
+nic_name_convert(char *old_name, char *new_name)
+{
+        int i;
+        char c;
+        char *compare_ptr;
+
+	if ((old_name[0] == '\0') || (old_name[1] == '\0')) {
+                strcpy(new_name, EDGE_LBL_XWIDGET);
+        } else {
+                for (i = 0; i < strlen(old_name); i++) {
+                        c = old_name[i];
+
+                        if (isalpha(c))
+                                new_name[i] = tolower(c);
+                        else if (isdigit(c))
+                                new_name[i] = c;
+                        else
+                                new_name[i] = '_';
+                }
+                new_name[i] = '\0';
+        }
+
+        /* XXX -
+         * Since a bunch of boards made it out with weird names like
+         * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and
+         * replace it with "baseio" to avoid confusion in the field.
+	 * We also have to make sure we don't report media_io instead of
+	 * baseio.
+         */
+
+        /* Skip underscores at the beginning of the name */
+        for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++)
+                ;
+
+	/*
+	 * Check for some names we need to replace.  Early boards
+	 * had junk following the name so check only the first
+	 * characters.
+	 */
+        if (!strncmp(new_name, "io6", 3) || 
+            !strncmp(new_name, "mio", 3) || 
+	    !strncmp(new_name, "media_io", 8))
+		strcpy(new_name, "baseio");
+	else if (!strncmp(new_name, "divo", 4))
+		strcpy(new_name, "divo") ;
+
+}
+
+/* Check if the given board corresponds to the global 
+ * master io6
+ */
+int
+is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot)
+{
+	lboard_t	*board;
+
+/* If this works then look for callers of is_master_baseio()
+ * (e.g. iograph.c) and let them pass in a slot if they want
+ */
+	board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			board = find_lboard_module((lboard_t *)
+				    KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				    module);
+	}
+#endif
+	if (!board)
+		return(0);
+	return(board->brd_flags & GLOBAL_MASTER_IO6);
+}
+/*
+ * Find the lboard structure and get the board name.
+ * If we can't find the structure or it's too low a revision,
+ * use default name.
+ */
+lboard_t *
+get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name)
+{
+	lboard_t *brd;
+
+	brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
+				  mod, slot);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			brd = find_lboard_modslot((lboard_t *)
+				KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				mod, slot);
+	}
+#endif
+
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, name);
+	}
+
+	/*
+ 	 * PV # 540860
+	 * If the name is not 'baseio' 
+	 * get the lowest of all the names in the nic string.
+	 * This is needed for boards like divo, which can have
+	 * a bunch of daughter cards, but would like to be called
+	 * divo. We could do this for baseio 
+ 	 * but it has some special case names that we would not
+ 	 * like to disturb at this point.
+	 */
+
+	/* gfx boards don't need any of this name scrambling */
+	if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) {
+		return(brd);
+	}
+
+	if (!(!strcmp(name, "baseio") )) {
+		if (brd) {
+			sort_nic_names(brd) ;
+			/* Convert to small case, '-' to '_' etc */
+			nic_name_convert(brd->brd_name, name) ;
+		}
+	}
+
+	return(brd);
+}
+
+/*
+ * get_actual_nasid
+ *
+ *	Completely disabled brds have their klconfig on 
+ *	some other nasid as they have no memory. But their
+ *	actual nasid is hidden in the klconfig. Use this
+ *	routine to get it. Works for normal boards too.
+ */
+nasid_t
+get_actual_nasid(lboard_t *brd)
+{
+	klhub_t	*hub ;
+
+	if (!brd)
+		return INVALID_NASID ;
+
+	/* find out if we are a completely disabled brd. */
+
+        hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+	if (!hub)
+                return INVALID_NASID ;
+	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
+		return hub->hub_info.physid ;
+	else
+		return brd->brd_nasid ;
+}
+
+int
+xbow_port_io_enabled(nasid_t nasid, int link)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+
+	/*
+	 * look for boards that might contain an xbow or xbridge
+	 */
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
+	if (brd == NULL) return 0;
+		
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return 0;
+
+	if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
+	    return 0;
+
+	return 1;
+}
+
+void
+board_to_path(lboard_t *brd, char *path)
+{
+	moduleid_t modnum;
+	char *board_name;
+
+	ASSERT(brd);
+
+	switch (KLCLASS(brd->brd_type)) {
+
+		case KLCLASS_NODE:
+			board_name = EDGE_LBL_NODE;
+			break;
+		case KLCLASS_ROUTER:
+			if (brd->brd_type == KLTYPE_META_ROUTER) {
+				board_name = EDGE_LBL_META_ROUTER;
+				hasmetarouter++;
+			} else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
+				board_name = EDGE_LBL_REPEATER_ROUTER;
+				hasmetarouter++;
+			} else
+				board_name = EDGE_LBL_ROUTER;
+			break;
+		case KLCLASS_MIDPLANE:
+			board_name = EDGE_LBL_MIDPLANE;
+			break;
+		case KLCLASS_IO:
+			board_name = EDGE_LBL_IO;
+			break;
+		case KLCLASS_IOBRICK:
+			if (brd->brd_type == KLTYPE_PBRICK)
+				board_name = EDGE_LBL_PBRICK;
+			else if (brd->brd_type == KLTYPE_IBRICK)
+				board_name = EDGE_LBL_IBRICK;
+			else if (brd->brd_type == KLTYPE_XBRICK)
+				board_name = EDGE_LBL_XBRICK;
+			else
+				board_name = EDGE_LBL_IOBRICK;
+			break;
+		default:
+			board_name = EDGE_LBL_UNKNOWN;
+	}
+			
+	modnum = brd->brd_module;
+
+	/* ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); */
+if ((modnum == MODULE_UNKNOWN) || (modnum == INVALID_MODULE)) {
+	modnum = ++module_number;
+}
+#ifdef __ia64
+	{
+		char	buffer[16];
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
+		sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name);
+	}
+#else
+	sprintf(path, "%H/%s", modnum, board_name);
+#endif
+}
+
+/*
+ * Get the module number for a NASID.
+ */
+moduleid_t
+get_module_id(nasid_t nasid)
+{
+	lboard_t *brd;
+
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+	if (!brd)
+		return INVALID_MODULE;
+	else
+		return brd->brd_module;
+}
+
+
+#define MHZ	1000000
+
+
+/* Get the canonical hardware graph name for the given pci component
+ * on the given io board.
+ */
+void
+device_component_canonical_name_get(lboard_t 	*brd,
+				    klinfo_t 	*component,
+				    char 	*name)
+{
+	moduleid_t 	modnum;
+	slotid_t 	slot;
+	char 		board_name[20];
+
+	ASSERT(brd);
+
+	/* Get the module number of this board */
+	modnum = brd->brd_module;
+
+	/* Convert the [ CLASS | TYPE ] kind of slotid
+	 * into a string 
+	 */
+	slot = brd->brd_slot;
+	ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
+
+	/* Get the io board name  */
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, board_name);
+	}
+
+	/* Give out the canonical  name of the pci device*/
+	sprintf(name, 
+		"/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/"
+		EDGE_LBL_PCI"/%d", 
+		modnum, board_name,KLCF_BRIDGE_W_ID(component));
+}
+
+/*
+ * Get the serial number of the main  component of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ * Assumptions: Nic manufacturing string  has the following format
+ *			*Serial:<serial_number>;*
+ */
+static int
+component_serial_number_get(lboard_t 		*board,
+			    klconf_off_t 	mfg_nic_offset,
+			    char		*serial_number,
+			    char		*key_pattern)
+{
+
+	char	*mfg_nic_string;
+	char	*serial_string,*str;
+	int	i;
+	char	*serial_pattern = "Serial:";
+
+	/* We have an error on a null mfg nic offset */
+	if (!mfg_nic_offset)
+		return(1);
+	/* Get the hub's manufacturing nic information
+	 * which is in the form of a pre-formatted string
+	 */
+	mfg_nic_string = 
+		(char *)NODE_OFFSET_TO_K0(NASID_GET(board),
+					  mfg_nic_offset);
+	/* There is no manufacturing nic info */
+	if (!mfg_nic_string)
+		return(1);
+
+	str = mfg_nic_string;
+	/* Look for the key pattern first (if it is  specified)
+	 * and then print the serial number corresponding to that.
+	 */
+	if (strcmp(key_pattern,"") && 
+	    !(str = strstr(mfg_nic_string,key_pattern)))
+		return(1);
+
+	/* There is no serial number info in the manufacturing
+	 * nic info
+	 */
+	if (!(serial_string = strstr(str,serial_pattern)))
+		return(1);
+
+	serial_string = serial_string + strlen(serial_pattern);
+	/*  Copy the serial number information from the klconfig */
+	i = 0;
+	while (serial_string[i] != ';') {
+		serial_number[i] = serial_string[i];
+		i++;
+	}
+	serial_number[i] = 0;
+	
+	return(0);
+}
+/*
+ * Get the serial number of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ */
+
+int
+board_serial_number_get(lboard_t *board,char *serial_number)
+{
+	ASSERT(board && serial_number);
+	if (!board || !serial_number)
+		return(1);
+
+	strcpy(serial_number,"");
+	switch(KLCLASS(board->brd_type)) {
+	case KLCLASS_CPU: {	/* Node board */
+		klhub_t	*hub;
+		
+		/* Get the hub component information */
+		hub = (klhub_t *)find_first_component(board,
+						      KLSTRUCT_HUB);
+		/* If we don't have a hub component on an IP27
+		 * then we have a weird klconfig.
+		 */
+		if (!hub)
+			return(1);
+		/* Get the serial number information from
+		 * the hub's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						hub->hub_mfg_nic,
+						serial_number,
+						"IP37"))
+				return(1);
+		break;
+	}
+	case KLCLASS_IO: {	/* IO board */
+		if (KLTYPE(board->brd_type) == KLTYPE_TPU) {
+		/* Special case for TPU boards */
+			kltpu_t *tpu;	
+		
+			/* Get the tpu component information */
+			tpu = (kltpu_t *)find_first_component(board,
+						      KLSTRUCT_TPU);
+			/* If we don't have a tpu component on a tpu board
+			 * then we have a weird klconfig.
+			 */
+			if (!tpu)
+				return(1);
+			/* Get the serial number information from
+			 * the tpu's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						tpu->tpu_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else  if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ||
+		            (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) {
+		/* Special case for GSN boards */
+			klgsn_t *gsn;	
+		
+			/* Get the gsn component information */
+			gsn = (klgsn_t *)find_first_component(board,
+			      ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ?
+					KLSTRUCT_GSN_A : KLSTRUCT_GSN_B));
+			/* If we don't have a gsn component on a gsn board
+			 * then we have a weird klconfig.
+			 */
+			if (!gsn)
+				return(1);
+			/* Get the serial number information from
+			 * the gsn's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						gsn->gsn_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else {
+		     	klbri_t	*bridge;
+		
+			/* Get the bridge component information */
+			bridge = (klbri_t *)find_first_component(board,
+							 KLSTRUCT_BRI);
+			/* If we don't have a bridge component on an IO board
+			 * then we have a weird klconfig.
+			 */
+			if (!bridge)
+				return(1);
+			/* Get the serial number information from
+		 	 * the bridge's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						bridge->bri_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		}
+	}
+	case KLCLASS_ROUTER: {	/* Router board */
+		klrou_t *router;	
+		
+		/* Get the router component information */
+		router = (klrou_t *)find_first_component(board,
+							 KLSTRUCT_ROU);
+		/* If we don't have a router component on a router board
+		 * then we have a weird klconfig.
+		 */
+		if (!router)
+			return(1);
+		/* Get the serial number information from
+		 * the router's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						router->rou_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	case KLCLASS_GFX: {	/* Gfx board */
+		klgfx_t *graphics;
+		
+		/* Get the graphics component information */
+		graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX);
+		/* If we don't have a gfx component on a gfx board
+		 * then we have a weird klconfig.
+		 */
+		if (!graphics)
+			return(1);
+		/* Get the serial number information from
+		 * the graphics's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						graphics->gfx_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	default:
+		strcpy(serial_number,"");
+		break;
+	}
+	return(0);
+}
+
+#include "asm/sn/sn_private.h"
+
+xwidgetnum_t
+nodevertex_widgetnum_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, 
+			     (arbitrary_info_t *) &hubinfo_p);
+	return(hubinfo_p->h_widgetid);
+}
+
+devfs_handle_t
+nodevertex_xbow_peer_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+	nasid_t xbow_peer_nasid;
+	cnodeid_t xbow_peer;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
+				     (arbitrary_info_t *) &hubinfo_p);
+	xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer;
+	if(xbow_peer_nasid == INVALID_NASID) 
+			return ( (devfs_handle_t)-1);
+	xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid);
+	return(NODEPDA(xbow_peer)->node_vertex);
+}
+
+/* NIC Sorting Support */
+
+#define MAX_NICS_PER_STRING 	32
+#define MAX_NIC_NAME_LEN	32
+
+static char *
+get_nic_string(lboard_t *lb)
+{
+        int         	i;
+        klinfo_t    	*k = NULL ;
+    	klconf_off_t    mfg_off = 0 ;
+    	char            *mfg_nic = NULL ;
+
+        for (i = 0; i < KLCF_NUM_COMPS(lb); i++) {
+                k = KLCF_COMP(lb, i) ;
+                switch(k->struct_type) {
+                        case KLSTRUCT_BRI:
+            			mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_HUB:
+            			mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_ROU:
+            			mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GFX:
+            			mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_TPU:
+            			mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GSN_A:
+                        case KLSTRUCT_GSN_B:
+            			mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_XTHD:
+                                mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
+                                break;
+
+			default:
+				mfg_off = 0 ;
+                                break ;
+                }
+		if (mfg_off)
+			break ;
+        }
+
+	if ((mfg_off) && (k))
+		mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ;
+
+        return mfg_nic ;
+}
+
+char *
+get_first_string(char **ptrs, int n)
+{
+        int     i ;
+        char    *tmpptr ;
+
+        if ((ptrs == NULL) || (n == 0))
+                return NULL ;
+
+        tmpptr = ptrs[0] ;
+
+        if (n == 1)
+                return tmpptr ;
+
+        for (i = 0 ; i < n ; i++) {
+                if (strcmp(tmpptr, ptrs[i]) > 0)
+                        tmpptr = ptrs[i] ;
+        }
+
+        return tmpptr ;
+}
+
+int
+get_ptrs(char *idata, char **ptrs, int n, char *label)
+{
+        int     i = 0 ;
+        char    *tmp = idata ;
+
+        if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0))
+                return 0 ;
+
+        while  ( (tmp = strstr(tmp, label)) ){
+                tmp += strlen(label) ;
+                /* check for empty name field, and last NULL ptr */
+                if ((i < (n-1)) && (*tmp != ';')) {
+                        ptrs[i++] = tmp ;
+                }
+        }
+
+        ptrs[i] = NULL ;
+
+        return i ;
+}
+
+/*
+ * sort_nic_names
+ *
+ * 	Does not really do sorting. Find the alphabetically lowest
+ *	name among all the nic names found in a nic string.
+ *
+ * Return:
+ *	Nothing
+ *
+ * Side Effects:
+ *
+ *	lb->brd_name gets the new name found
+ */
+
+static void
+sort_nic_names(lboard_t *lb)
+{
+	char 	*nic_str ;
+        char    *ptrs[MAX_NICS_PER_STRING] ;
+        char    name[MAX_NIC_NAME_LEN] ;
+        char    *tmp, *tmp1 ;
+
+	*name = 0 ;
+
+	/* Get the nic pointer from the lb */
+
+	if ((nic_str = get_nic_string(lb)) == NULL)
+		return ;
+
+        tmp = get_first_string(ptrs,
+                        get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ;
+
+        if (tmp == NULL)
+		return ;
+
+        if  ( (tmp1 = strchr(tmp, ';')) ){
+                strncpy(name, tmp, tmp1-tmp) ;
+                name[tmp1-tmp] = 0 ;
+        } else {
+                strncpy(name, tmp, (sizeof(name) -1)) ;
+                name[sizeof(name)-1] = 0 ;
+        }
+
+	strcpy(lb->brd_name, name) ;
+}
+
+
+
+char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345";
+
+
+/*
+ * Format a module id for printing.
+ */
+void
+format_module_id(char *buffer, moduleid_t m, int fmt)
+{
+	int rack, position;
+	char brickchar;
+
+	rack = MODULE_GET_RACK(m);
+	ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES);
+	brickchar = MODULE_GET_BTCHAR(m);
+	position = MODULE_GET_BPOS(m);
+
+	if (fmt == MODULE_FORMAT_BRIEF) {
+	    /* Brief module number format, eg. 002c15 */
+
+	    /* Decompress the rack number */
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    /* Add the brick type */
+	    *buffer++ = brickchar;
+	}
+	else if (fmt == MODULE_FORMAT_LONG) {
+	    /* Fuller hwgraph format, eg. rack/002/bay/15 */
+
+	    strcpy(buffer, EDGE_LBL_RACK "/");  buffer += strlen(buffer);
+
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    strcpy(buffer, "/" EDGE_LBL_RPOS "/");  buffer += strlen(buffer);
+	}
+
+	/* Add the bay position, using at least two digits */
+	if (position < 10)
+	    *buffer++ = '0';
+	sprintf(buffer, "%d", position);
+
+}
+
+/*
+ * Parse a module id, in either brief or long form.
+ * Returns < 0 on error.
+ * The long form does not include a brick type, so it defaults to 0 (CBrick)
+ */
+int
+parse_module_id(char *buffer)
+{
+	unsigned int	v, rack, bay, type, form;
+	moduleid_t	m;
+	char 		c;
+
+	if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) {
+		form = MODULE_FORMAT_LONG;
+		buffer += strlen(EDGE_LBL_RACK "/");
+
+		/* A long module ID must be exactly 5 non-template chars. */
+		if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5)
+			return -1;
+	}
+	else {
+		form = MODULE_FORMAT_BRIEF;
+
+		/* A brief module id must be exactly 6 characters */
+		if (strlen(buffer) != 6)
+			return -2;
+	}
+
+	/* The rack number must be exactly 3 digits */
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2])))
+		return -3;
+
+	rack = 0;
+	v = *buffer++ - '0';
+	if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+		return -4;
+	RACK_ADD_CLASS(rack, v);
+
+	v = *buffer++ - '0';
+	if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+		return -5;
+	RACK_ADD_GROUP(rack, v);
+
+	v = *buffer++ - '0';
+	/* rack numbers are 1-based */
+	if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+		return -6;
+	RACK_ADD_NUM(rack, v);
+
+	if (form == MODULE_FORMAT_BRIEF) {
+		/* Next should be a module type character.  Accept ucase or lcase. */
+		c = *buffer++;
+		if (!isalpha(c))
+			return -7;
+
+		/* strchr() returns a pointer into brick_types[], or NULL */
+		type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types);
+		if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT)
+			return -8;
+	}
+	else {
+		/* Hardcode the module type, and skip over the boilerplate */
+		type = MODULE_CBRICK;
+
+		if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer)
+			return -9;
+
+		buffer += strlen("/" EDGE_LBL_RPOS "/");
+	}
+		
+	/* The bay number is last.  Make sure it's exactly two digits */
+
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2]))
+		return -10;
+
+	bay = 10 * (buffer[0] - '0') + (buffer[1] - '0');
+
+	if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+		return -11;
+
+	m = RBT_TO_MODULE(rack, bay, type);
+
+	/* avoid sign extending the moduleid_t */
+	return (int)(unsigned short)m;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/klgraph.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/klgraph.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/klgraph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/klgraph.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,940 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * klgraph.c-
+ *      This file specifies the interface between the kernel and the PROM's
+ *      configuration data structures.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/kldir.h>
+#include <asm/sn/gda.h> 
+#include <asm/sn/klconfig.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/hcl_util.h>
+
+/* #define KLGRAPH_DEBUG 1 */
+#ifdef KLGRAPH_DEBUG
+#define GRPRINTF(x)	printk x
+#define CE_GRPANIC	CE_PANIC
+#else
+#define GRPRINTF(x)
+#define CE_GRPANIC	CE_PANIC
+#endif
+
+#include <asm/sn/sn_private.h>
+
+extern char arg_maxnodes[];
+extern u64 klgraph_addr[];
+
+/*
+ * Support for verbose inventory via hardware graph. 
+ * klhwg_invent_alloc allocates the necessary size of inventory information
+ * and fills in the generic information.
+ */
+invent_generic_t *
+klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
+{
+	invent_generic_t *invent;
+
+	invent = kern_malloc(size);
+	if (!invent) return NULL;
+	
+	invent->ig_module = NODE_MODULEID(cnode);
+	invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
+	invent->ig_invclass = class;
+
+	return invent;
+}
+
+/*
+ * Add detailed disabled cpu inventory info to the hardware graph.
+ */
+void
+klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv,
+                               cnodeid_t cnode,
+                               klcpu_t *cpu, slotid_t slot)
+{
+	invent_cpuinfo_t *cpu_invent;
+	diag_inv_t       *diag_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+	klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	/* Diag information on this processor */
+	diag_invent = (diag_inv_t *)
+	klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t));
+
+	if (!diag_invent)
+		return;
+
+
+	/* Disabled CPU */
+	cpu_invent->ic_gen.ig_flag = 0x0;
+	cpu_invent->ic_gen.ig_slot = slot;
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu->cpu_info.physid;
+
+	/* Disabled CPU label */
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+
+	/* Diagval label - stores reason for disable +{virt,phys}id +diagval*/
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL,
+			(arbitrary_info_t) diag_invent);
+
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL,
+			sizeof(diag_inv_t));
+}
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_cpu_invent_info(devfs_handle_t cpuv,
+			cnodeid_t cnode,
+			klcpu_t *cpu)
+{
+	invent_cpuinfo_t *cpu_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+		klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu))
+		cpu_invent->ic_gen.ig_flag = INVENT_ENABLED;
+	else
+		cpu_invent->ic_gen.ig_flag = 0x0;
+
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid);
+
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+}
+
+/* 
+ * Add information about the baseio prom version number
+ * as a part of detailed inventory info in the hwgraph.
+ */
+void
+klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
+{
+	invent_miscinfo_t	*baseio_inventory;
+	unsigned char		version = 0,revision = 0;
+
+	/* Allocate memory for the "detailed inventory" info
+	 * for the baseio
+	 */
+	baseio_inventory = (invent_miscinfo_t *) 
+		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
+	baseio_inventory->im_type = INV_IO6PROM;
+	/* Store the revision info  in the inventory */
+	baseio_inventory->im_version = version;
+	baseio_inventory->im_rev = revision;
+	/* Put the inventory info in the hardware graph */
+	hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) baseio_inventory);
+	/* Make the information available to the user programs
+	 * thru hwgfs.
+	 */
+        hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+char	*hub_rev[] = {
+	"0.0",
+	"1.0",
+	"2.0",
+	"2.1",
+	"2.2",
+	"2.3"
+};
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_hub_invent_info(devfs_handle_t hubv,
+		      cnodeid_t cnode, 
+		      klhub_t *hub)
+{
+	invent_miscinfo_t *hub_invent;
+
+	hub_invent = (invent_miscinfo_t *) 
+	    klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
+	if (!hub_invent)
+	    return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
+	    hub_invent->im_gen.ig_flag = INVENT_ENABLED;
+
+	hub_invent->im_type = INV_HUB;
+	hub_invent->im_rev = hub->hub_info.revision;
+	hub_invent->im_speed = hub->hub_speed;
+	hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) hub_invent);
+        hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
+{
+	devfs_handle_t myhubv;
+	devfs_handle_t hub_mon;
+	devfs_handle_t synergy;
+	devfs_handle_t fsb0;
+	devfs_handle_t fsb1;
+	int rc;
+	extern struct file_operations hub_mon_fops;
+
+	GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
+
+	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
+	rc = device_master_set(myhubv, node_vertex);
+
+	/*
+	 * hub perf stats.
+	 */
+	rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO,
+                        (arbitrary_info_t)(&NODEPDA(cnode)->hubstats));
+
+	if (rc != GRAPH_SUCCESS) {
+		printk(KERN_WARNING  "klhwg_add_hub: Can't add hub info label 0x%p, code %d",
+			(void *)myhubv, rc);
+	}
+
+	klhwg_hub_invent_info(myhubv, cnode, hub);
+
+	hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &hub_mon_fops,
+	    (void *)(long)cnode);
+
+	init_hub_stats(cnode, NODEPDA(cnode));
+
+	/*
+	 * synergy perf
+	 */
+	(void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy);
+	(void) hwgraph_path_add(synergy, "0", &fsb0);
+	(void) hwgraph_path_add(synergy, "1", &fsb1);
+
+	fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0));
+
+	fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
+{
+        devfs_handle_t my_cpu;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+        if(cpu_id != -1){
+		sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid);
+		(void) hwgraph_path_add(node_vertex, name, &my_cpu);
+
+		mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+		device_master_set(my_cpu, node_vertex);
+
+		klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot);
+		return;
+        }
+}
+
+/* ARGSUSED */
+void
+klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
+{
+        devfs_handle_t my_cpu, cpu_dir;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+
+        sprintf(name, "%s/%d/%c",
+                EDGE_LBL_CPUBUS,
+                0,
+                'a' + cpu->cpu_info.physid);
+
+        GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%x\n", name, node_vertex));
+        (void) hwgraph_path_add(node_vertex, name, &my_cpu);
+        mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+        device_master_set(my_cpu, node_vertex);
+
+        /* Add an alias under the node's CPU directory */
+        if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) {
+                sprintf(name, "%c", 'a' + cpu->cpu_info.physid);
+                (void) hwgraph_edge_add(cpu_dir, my_cpu, name);
+        }
+
+        klhwg_cpu_invent_info(my_cpu, cnode, cpu);
+}
+
+
+void
+klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+	nasid_t hub_nasid;
+	cnodeid_t hub_cnode;
+	int widgetnum;
+	devfs_handle_t xbow_v, hubv;
+	/*REFERENCED*/
+	graph_error_t err;
+
+	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL)
+			return;
+
+	if (KL_CONFIG_DUPLICATE_BOARD(brd))
+	    return;
+
+	GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
+			cnode, nasid));
+
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return;
+
+#ifdef	LATER
+	/*
+	 * We cannot support this function in devfs .. see below where 
+	 * we use hwgraph_path_add() to create this vertex with a known 
+	 * name.
+	 */
+	err = hwgraph_vertex_create(&xbow_v);
+	ASSERT(err == GRAPH_SUCCESS);
+
+	xswitch_vertex_init(xbow_v);
+#endif /* LATER */
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
+		    continue;
+
+		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
+		if (hub_nasid == INVALID_NASID) {
+			printk(KERN_WARNING  "hub widget %d, skipping xbow graph\n", widgetnum);
+			continue;
+		}
+
+		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
+
+		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
+			continue;
+		}
+			
+		hubv = cnodeid_to_vertex(hub_cnode);
+
+		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
+                if (err != GRAPH_SUCCESS) {
+                        if (err == GRAPH_DUP)
+                                printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+                                        "working routers and router links!");
+
+                        PRINT_PANIC("klhwg_add_xbow: Failed to add "
+                                "edge: vertex 0x%p to vertex 0x%p,"
+                                "error %d\n",
+                                (void *)hubv, (void *)xbow_v, err);
+                }
+		xswitch_vertex_init(xbow_v); 
+
+		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
+
+		/*
+		 * XXX - This won't work is we ever hook up two hubs
+		 * by crosstown through a crossbow.
+		 */
+		if (hub_nasid != nasid) {
+			NODEPDA(hub_cnode)->xbow_peer = nasid;
+			NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
+				hub_nasid;
+		}
+
+		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
+			hub_nasid, EDGE_LBL_XTALK, hubv));
+
+#ifdef	LATER
+		err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK);
+		if (err != GRAPH_SUCCESS) {
+			if (err == GRAPH_DUP)
+				printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+					"working routers and router links!");
+
+			PRINT_PANIC("klhwg_add_xbow: Failed to add "
+				"edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), "
+				"error %d\n",
+				hubv, hubv, xbow_v, xbow_v, err);
+		}
+#endif
+	}
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
+{
+	nasid_t nasid;
+	lboard_t *brd;
+	klhub_t *hub;
+	devfs_handle_t node_vertex = NULL;
+	char path_buffer[100];
+	int rv;
+	char *s;
+	int board_disabled = 0;
+	klcpu_t *cpu;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
+                cnode, nasid, brd));
+	ASSERT(brd);
+
+	do {
+		devfs_handle_t cpu_dir;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
+			path_buffer, hwgraph_root));
+		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+		if (rv != GRAPH_SUCCESS)
+			PRINT_PANIC("Node vertex creation failed.  "
+					  "Path == %s",
+				path_buffer);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+		if(hub->hub_info.flags & KLINFO_ENABLE)
+			board_disabled = 0;
+		else
+			board_disabled = 1;
+		
+		if(!board_disabled) {
+			mark_nodevertex_as_node(node_vertex,
+					    cnode + board_disabled * numnodes);
+
+			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
+			NODEPDA(cnode)->hwg_node_name =
+						kmalloc(strlen(s) + 1,
+						GFP_KERNEL);
+			ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
+			strcpy(NODEPDA(cnode)->hwg_node_name, s);
+
+			hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
+
+			/* Set up node board's slot */
+			NODEPDA(cnode)->slotdesc = brd->brd_slot;
+
+			/* Set up the module we're in */
+			NODEPDA(cnode)->module_id = brd->brd_module;
+			NODEPDA(cnode)->module = module_lookup(brd->brd_module);
+		}
+
+
+		/* Get the first CPU structure */
+		cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
+
+		/*
+		* If there's at least 1 CPU, add a "cpu" directory to represent
+		* the collection of all CPUs attached to this node.
+		*/
+		if (cpu) {
+			graph_error_t rv;
+
+			rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir);
+			if (rv != GRAPH_SUCCESS)
+				panic("klhwg_add_node: Cannot create CPU directory\n");
+		}
+
+		/* Add each CPU */
+		while (cpu) {
+			cpuid_t cpu_id;
+			cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid);
+			if (cpu_enabled(cpu_id))
+				klhwg_add_cpu(node_vertex, cnode, cpu);
+			else
+				klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
+
+			cpu = (klcpu_t *)
+				find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
+		} /* while */
+
+		if(!board_disabled)
+		klhwg_add_hub(node_vertex, hub, cnode);
+		
+		brd = KLCF_NEXT(brd);
+		if (brd)
+			brd = find_lboard(brd, KLTYPE_SNIA);
+		else
+			break;
+	} while(brd);
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_all_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	devfs_handle_t node_vertex;
+	char path_buffer[100];
+	int rv;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			/* No routers stored in this node's memory */
+			continue;
+
+		do {
+			ASSERT(brd);
+			GRPRINTF(("Router board struct is %p\n", brd));
+
+			/* Don't add duplicate boards. */
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+
+			GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module));
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("Router path is %s\n", path_buffer));
+
+			/* Add the router */
+			GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
+				path_buffer, hwgraph_root));
+			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+			if (rv != GRAPH_SUCCESS)
+				PRINT_PANIC("Router vertex creation "
+						  "failed.  Path == %s",
+					path_buffer);
+
+			GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
+					brd));
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd),
+			 KLTYPE_ROUTER)) );
+
+		GRPRINTF(("klhwg_add_all_routers: Done.\n"));
+	}
+
+}
+
+/* ARGSUSED */
+void
+klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
+			 cnodeid_t cnode, nasid_t nasid)
+{
+	klrou_t *router;
+	char path_buffer[50];
+	char dest_path[50];
+	devfs_handle_t router_hndl;
+	devfs_handle_t dest_hndl;
+	int rc;
+	int port;
+	lboard_t *dest_brd;
+
+	GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
+			cnode));
+
+	/* Don't add duplicate boards. */
+	if (brd->brd_flags & DUPLICATE_BOARD) {
+		GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
+			brd, cnode));
+		return;
+	}
+
+	/* Generate a hardware graph path for this board. */
+	board_to_path(brd, path_buffer);
+
+	rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
+
+	if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
+			return;
+
+	if (rc != GRAPH_SUCCESS)
+		printk(KERN_WARNING  "Can't find router: %s", path_buffer);
+
+	/* We don't know what to do with multiple router components */
+	if (brd->brd_numcompts != 1) {
+		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
+			brd->brd_numcompts);
+		return;
+	}
+
+
+	/* Convert component 0 to klrou_t ptr */
+	router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
+					      brd->brd_compts[0]);
+
+	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+		/* See if the port's active */
+		if (router->rou_port[port].port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
+				 port));
+			continue;
+		}
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) 
+		    == INVALID_CNODEID) {
+			continue;
+		}
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				router->rou_port[port].port_nasid,
+				router->rou_port[port].port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find router: %s", dest_path);
+		}
+		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
+			  path_buffer, port, dest_path));
+
+		sprintf(dest_path, "%d", port);
+
+		rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
+
+		if (rc == GRAPH_DUP) {
+			GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
+				  port, router->rou_port[port].port_nasid,
+				  path_buffer, dest_path));
+			continue;
+		}
+
+		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
+			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+		
+	}
+}
+
+
+void
+klhwg_connect_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+
+			nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+			klhwg_connect_one_router(hwgraph_root, brd,
+						 cnode, nasid);
+
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+}
+
+
+
+void
+klhwg_connect_hubs(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	klhub_t *hub;
+	lboard_t *dest_brd;
+	devfs_handle_t hub_hndl;
+	devfs_handle_t dest_hndl;
+	char path_buffer[50];
+	char dest_path[50];
+	graph_error_t rc;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
+			cnode));
+
+		brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+		ASSERT(brd);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+
+		/* See if the port's active */
+		if (hub->hub_port.port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
+			continue;
+		}
+
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID)
+			continue;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
+		rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
+
+		if (rc != GRAPH_SUCCESS)
+			printk(KERN_WARNING  "Can't find hub: %s", path_buffer);
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				hub->hub_port.port_nasid,
+				hub->hub_port.port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find board: %s", dest_path);
+		} else {
+		
+
+			GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
+			  path_buffer, dest_path));
+
+			rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT);
+
+			if (rc != GRAPH_SUCCESS)
+				PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+
+		}
+	}
+}
+
+/* Store the pci/vme disabled board information as extended administrative
+ * hints which can later be used by the drivers using the device/driver
+ * admin interface. 
+ */
+void
+klhwg_device_disable_hints_add(void)
+{
+	cnodeid_t	cnode; 		/* node we are looking at */
+	nasid_t		nasid;		/* nasid of the node */
+	lboard_t	*board;		/* board we are looking at */
+	int		comp_index;	/* component index */
+	klinfo_t	*component;	/* component in the board we are
+					 * looking at 
+					 */
+	char		device_name[MAXDEVNAME];
+	
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		/* Check out all the board info stored  on a node */
+		while(board) {
+			/* No need to look at duplicate boards or non-io 
+			 * boards
+			 */
+			if (KL_CONFIG_DUPLICATE_BOARD(board) ||
+			    KLCLASS(board->brd_type) != KLCLASS_IO) {
+				board = KLCF_NEXT(board);
+				continue;
+			}
+			/* Check out all the components of a board */
+			for (comp_index = 0; 
+			     comp_index < KLCF_NUM_COMPS(board);
+			     comp_index++) {
+				component = KLCF_COMP(board,comp_index);
+				/* If the component is enabled move on to
+				 * the next component
+				 */
+				if (KLCONFIG_INFO_ENABLED(component))
+					continue;
+				/* NOTE : Since the prom only supports
+				 * the disabling of pci devices the following
+				 * piece of code makes sense. 
+				 * Make sure that this assumption is valid
+				 */
+				/* This component is disabled. Store this
+				 * hint in the extended device admin table
+				 */
+				/* Get the canonical name of the pci device */
+				device_component_canonical_name_get(board,
+							    component,
+							    device_name);
+#ifdef DEBUG
+				printf("%s DISABLED\n",device_name);
+#endif				
+			}
+			/* go to the next board info stored on this 
+			 * node 
+			 */
+			board = KLCF_NEXT(board);
+		}
+	}
+}
+
+void
+klhwg_add_all_modules(devfs_handle_t hwgraph_root)
+{
+	cmoduleid_t	cm;
+	char		name[128];
+	devfs_handle_t	vhdl;
+	int		rc;
+	char		buffer[16];
+
+	/* Add devices under each module */
+
+	for (cm = 0; cm < nummodules; cm++) {
+		/* Use module as module vertex fastinfo */
+
+#ifdef __ia64
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
+		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
+#else
+		sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id);
+#endif
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT(rc == GRAPH_SUCCESS);
+		rc = rc;
+
+		hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]);
+
+		/* Add system controller */
+
+#ifdef __ia64
+		sprintf(name,
+			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
+			buffer);
+#else
+		sprintf(name,
+			EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1,
+			modules[cm]->id);
+#endif
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
+		rc = rc;
+
+		hwgraph_info_add_LBL(vhdl,
+				     INFO_LBL_ELSC,
+				     (arbitrary_info_t) (__psint_t) 1);
+
+#ifdef	LATER
+		sndrv_attach(vhdl);
+		/*
+		 * We need to call the drivers attach routine ..
+		 */
+		FIXME("klhwg_add_all_modules: Need code to call driver attach.\n");
+#endif
+	}
+}
+
+void
+klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
+{
+	cnodeid_t	cnode;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_node(hwgraph_root, cnode, NULL);
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
+	}
+
+	/*
+	 * As for router hardware inventory information, we set this
+	 * up in router.c. 
+	 */
+	
+	klhwg_add_all_routers(hwgraph_root);
+	klhwg_connect_routers(hwgraph_root);
+	klhwg_connect_hubs(hwgraph_root);
+
+	/* Go through the entire system's klconfig
+	 * to figure out which pci components have been disabled
+	 */
+	klhwg_device_disable_hints_add();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/l1.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/l1.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/l1.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/l1.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,3124 @@
+/* $Id: l1.c,v 1.2 2002/11/16 02:23:19 steiner Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/* In general, this file is organized in a hierarchy from lower-level
+ * to higher-level layers, as follows:
+ *
+ *	UART routines
+ *	Bedrock/L1 "PPP-like" protocol implementation
+ *	System controller "message" interface (allows multiplexing
+ *		of various kinds of requests and responses with
+ *		console I/O)
+ *	Console interface:
+ *	  "l1_cons", the glue that allows the L1 to act
+ *		as the system console for the stdio libraries
+ *
+ * Routines making use of the system controller "message"-style interface
+ * can be found in l1_command.c.
+ */
+
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/uart16550.h>
+#include <asm/sn/simulator.h>
+
+
+/* Make all console writes atomic */
+#define SYNC_CONSOLE_WRITE	1
+
+
+/*********************************************************************
+ * Hardware-level (UART) driver routines.
+ */
+
+/* macros for reading/writing registers */
+
+/* USLD and USSD are needed for SN2 - but since we moving this code out soon ... */
+#define LD(x)			(*(volatile uint64_t *)(x))
+#define USLD(x)			LD(x)			// (*(volatile ushort *)(x))
+#define SD(x, v)        	(LD(x) = (uint64_t) (v))
+#define USSD(x, v)        	SD(x,v)			// (USLD(x) = (ushort) (v))
+
+/* location of uart receive/xmit data register */
+#define L1_UART_BASE(n)		((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080))
+#define LOCK_HUB		REMOTE_HUB_ADDR
+
+#define ADDR_L1_REG(n, r)	( L1_UART_BASE(n) | ( (r) << 3 ) )
+#define READ_L1_UART_REG(n, r)  ( LD(ADDR_L1_REG((n), (r))) )
+
+#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) )
+
+/* upper layer interface calling methods */
+#define SERIAL_INTERRUPT_MODE	0
+#define SERIAL_POLLED_MODE	1
+
+
+/* UART-related #defines */
+
+#define UART_BAUD_RATE		57600
+#define UART_FIFO_DEPTH		16
+#define UART_DELAY_SPAN		10
+#define UART_PUTC_TIMEOUT	50000
+#define UART_INIT_TIMEOUT	100000
+
+/* error codes */
+#define UART_SUCCESS		  0
+#define UART_TIMEOUT		(-1)
+#define UART_LINK		(-2)
+#define UART_NO_CHAR		(-3)
+#define UART_VECTOR		(-4)
+
+#define UART_DELAY(x)		udelay(x)
+
+/* Some debug counters */
+#define L1C_INTERRUPTS		0
+#define L1C_OUR_R_INTERRUPTS	1
+#define L1C_OUR_X_INTERRUPTS	2
+#define L1C_SEND_CALLUPS	3
+#define L1C_RECEIVE_CALLUPS	4
+#define L1C_SET_BAUD		5
+#define L1C_ALREADY_LOCKED	L1C_SET_BAUD
+#define L1C_R_IRQ		6
+#define L1C_R_IRQ_RET		7
+#define L1C_LOCK_TIMEOUTS	8
+#define L1C_LOCK_COUNTER	9
+#define L1C_UNLOCK_COUNTER	10
+#define L1C_REC_STALLS		11
+#define L1C_CONNECT_CALLS	12
+#define L1C_SIZE		L1C_CONNECT_CALLS	/* Set to the last one */
+
+uint64_t L1_collectibles[L1C_SIZE + 1];
+
+
+/*
+ *	Some macros for handling Endian-ness
+ */
+
+#define COPY_INT_TO_BUFFER(_b, _i, _n)		\
+	{					\
+		_b[_i++] = (_n >> 24) & 0xff;	\
+		_b[_i++] = (_n >> 16) & 0xff;	\
+		_b[_i++] = (_n >>  8) & 0xff;	\
+		_b[_i++] =  _n        & 0xff;	\
+	}
+
+#define COPY_BUFFER_TO_INT(_b, _i, _n)		\
+	{					\
+		_n  = (_b[_i++] << 24) & 0xff;	\
+		_n |= (_b[_i++] << 16) & 0xff;	\
+		_n |= (_b[_i++] <<  8) & 0xff;	\
+		_n |=  _b[_i++]        & 0xff;	\
+	}
+
+#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn)	\
+	{					\
+	    char *_xyz = (char *)_bn;		\
+	    _xyz[3] = _b[_i++];			\
+	    _xyz[2] = _b[_i++];			\
+	    _xyz[1] = _b[_i++];			\
+	    _xyz[0] = _b[_i++];			\
+	}
+
+void snia_kmem_free(void *where, int size);
+
+#define ALREADY_LOCKED		1
+#define NOT_LOCKED		0
+static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ );
+
+#define BCOPY(x,y,z)	memcpy(y,x,z)
+
+uint8_t L1_interrupts_connected;		/* Non-zero when we are in interrupt mode */
+
+
+/*
+ * Console locking defines and functions.
+ *
+ */
+
+uint8_t L1_cons_is_inited = 0;			/* non-zero when console is init'd */
+nasid_t Master_console_nasid = (nasid_t)-1;
+extern nasid_t console_nasid;
+
+u64 ia64_sn_get_console_nasid(void);
+
+inline nasid_t
+get_master_nasid(void)
+{
+	nasid_t nasid = Master_console_nasid;
+
+	master_nasid = Master_console_nasid = nasid = 0;
+	if ( nasid == (nasid_t)-1 ) {
+		nasid = (nasid_t)ia64_sn_get_console_nasid();
+		if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) {
+			/* Out of bounds, use local */
+			console_nasid = nasid = get_nasid();
+		}
+		else {
+			/* Got a valid nasid, set the console_nasid */
+			char xx[100];
+/* zzzzzz - force nasid to 0 for now */
+			sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid);
+nasid = 0;
+/* end zzzzzz */
+			xx[99] = (char)0;
+			early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED);
+			Master_console_nasid = console_nasid = nasid;
+		}
+	}
+	return(nasid);
+}
+
+
+
+#define HUB_LOCK		16
+
+#define PRIMARY_LOCK_TIMEOUT    10000000
+#define HUB_LOCK_REG(n)         LOCK_HUB(n, MD_PERF_CNT0)
+
+#define SET_BITS(reg, bits)     SD(reg, LD(reg) |  (bits))
+#define CLR_BITS(reg, bits)     SD(reg, LD(reg) & ~(bits))
+#define TST_BITS(reg, bits)     ((LD(reg) & (bits)) != 0)
+
+#define HUB_TEST_AND_SET(n)	LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ))
+#define HUB_CLEAR(n)		SD(LOCK_HUB(n,LB_SCRATCH_REG3),0)
+
+#define RTC_TIME_MAX		((rtc_time_t) ~0ULL)
+
+/*
+ * primary_lock
+ *
+ *   Allows CPU's 0-3  to mutually exclude the hub from one another by
+ *   obtaining a blocking lock.  Does nothing if only one CPU is active.
+ *
+ *   This lock should be held just long enough to set or clear a global
+ *   lock bit.  After a relatively short timeout period, this routine
+ *   figures something is wrong, and steals the lock. It does not set
+ *   any other CPU to "dead".
+ */
+inline void
+primary_lock(nasid_t nasid)
+{
+	rtc_time_t          expire;
+
+	expire = rtc_time() + PRIMARY_LOCK_TIMEOUT;
+
+	while (HUB_TEST_AND_SET(nasid)) {
+		if (rtc_time() > expire) {
+			HUB_CLEAR(nasid);
+		}
+	}
+}
+
+/*
+ * primary_unlock (internal)
+ *
+ *   Counterpart to primary_lock
+ */
+
+inline void
+primary_unlock(nasid_t nasid)
+{
+	HUB_CLEAR(nasid);
+}
+
+/*
+ * hub_unlock
+ *
+ *   Counterpart to hub_lock_timeout and hub_lock
+ */
+
+inline void
+hub_unlock(nasid_t nasid, int level)
+{
+	uint64_t mask = 1ULL << level;
+
+	primary_lock(nasid);
+	CLR_BITS(HUB_LOCK_REG(nasid), mask);
+	primary_unlock(nasid);
+}
+
+/*
+ * hub_lock_timeout
+ *
+ *   Uses primary_lock to implement multiple lock levels.
+ *
+ *   There are 20 lock levels from 0 to 19 (limited by the number of bits
+ *   in HUB_LOCK_REG).  To prevent deadlock, multiple locks should be
+ *   obtained in order of increasingly higher level, and released in the
+ *   reverse order.
+ *
+ *   A timeout value of 0 may be used for no timeout.
+ *
+ *   Returns 0 if successful, -1 if lock times out.
+ */
+
+inline int
+hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout)
+{
+	uint64_t mask = 1ULL << level;
+	rtc_time_t expire = (timeout ?  rtc_time() + timeout : RTC_TIME_MAX);
+	int done    = 0;
+
+	while (! done) {
+		while (TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			if (rtc_time() > expire)
+				return -1;
+		}
+
+		primary_lock(nasid);
+
+		if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			SET_BITS(HUB_LOCK_REG(nasid), mask);
+			done = 1;
+		}
+		primary_unlock(nasid);
+	}
+	return 0;
+}
+
+
+#define LOCK_TIMEOUT	(0x1500000 * 1) /* 0x1500000 is ~30 sec */
+
+void
+lock_console(nasid_t nasid)
+{
+	int ret;
+
+	/* If we already have it locked, just return */
+	L1_collectibles[L1C_LOCK_COUNTER]++;
+
+	ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+	if ( ret != 0 ) {
+		L1_collectibles[L1C_LOCK_TIMEOUTS]++;
+		/* timeout */
+		hub_unlock(nasid, HUB_LOCK);
+		/* If the 2nd lock fails, just pile ahead.... */
+		hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+		L1_collectibles[L1C_LOCK_TIMEOUTS]++;
+	}
+}
+
+inline void
+unlock_console(nasid_t nasid)
+{
+	L1_collectibles[L1C_UNLOCK_COUNTER]++;
+	hub_unlock(nasid, HUB_LOCK);
+}
+
+
+int 
+get_L1_baud(void)
+{
+    return UART_BAUD_RATE;
+}
+
+
+/* uart driver functions */
+
+static inline void
+uart_delay( rtc_time_t delay_span )
+{
+    UART_DELAY( delay_span );
+}
+
+#define UART_PUTC_READY(n)      (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE)
+
+static int
+uart_putc( l1sc_t *sc ) 
+{
+    WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] );
+    return UART_SUCCESS;
+}
+
+
+static int
+uart_getc( l1sc_t *sc )
+{
+    u_char lsr_reg = 0;
+    nasid_t nasid = sc->nasid;
+
+    if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & 
+	(LSR_RCA | LSR_PARERR | LSR_FRMERR) ) 
+    {
+	if( lsr_reg & LSR_RCA ) 
+	    return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) );
+	else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) {
+	    return UART_LINK;
+	}
+    }
+    return UART_NO_CHAR;
+}
+
+
+#define PROM_SER_CLK_SPEED	12000000
+#define PROM_SER_DIVISOR(x)	(PROM_SER_CLK_SPEED / ((x) * 16))
+
+static void
+uart_init( l1sc_t *sc, int baud )
+{
+#if !defined(USE_SAL_CONSOLE_IO)
+    rtc_time_t expire;
+    int clkdiv;
+    nasid_t nasid;
+
+    clkdiv = PROM_SER_DIVISOR(baud);
+    expire = rtc_time() + UART_INIT_TIMEOUT;
+    nasid = sc->nasid;
+    
+    /* make sure the transmit FIFO is empty */
+    while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) {
+	uart_delay( UART_DELAY_SPAN );
+	if( rtc_time() > expire ) {
+	    break;
+	}
+    }
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* Setup for the proper baud rate */
+    WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* set operating parameters and set DLAB to 0 */
+
+    /* 8bit, one stop, clear request to send, auto flow control */
+    WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* disable interrupts */
+    WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* enable FIFO mode and reset both FIFOs, trigger on 1 */
+    WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0);
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+#endif	/* !USE_SAL_CONSOLE_IO */
+}
+
+/* This requires the console lock */
+
+
+static void
+uart_intr_enable( l1sc_t *sc, u_char mask )
+{
+    u_char lcr_reg, icr_reg;
+    nasid_t nasid = sc->nasid;
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* make sure that the DLAB bit in the LCR register is 0
+     */
+    lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
+    lcr_reg &= ~(LCR_DLAB);
+    WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg );
+
+    /* enable indicated interrupts
+     */
+    icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
+    icr_reg |= mask;
+    WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+}
+
+/* This requires the console lock */
+static void
+uart_intr_disable( l1sc_t *sc, u_char mask )
+{
+    u_char lcr_reg, icr_reg;
+    nasid_t nasid = sc->nasid;
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* make sure that the DLAB bit in the LCR register is 0
+     */
+    lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
+    lcr_reg &= ~(LCR_DLAB);
+    WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg );
+
+    /* enable indicated interrupts
+     */
+    icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
+    icr_reg &= mask;
+    WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+}
+
+#define uart_enable_xmit_intr(sc) \
+	uart_intr_enable((sc), ICR_TIEN)
+
+#define uart_disable_xmit_intr(sc) \
+        uart_intr_disable((sc), ~(ICR_TIEN))
+
+#define uart_enable_recv_intr(sc) \
+        uart_intr_enable((sc), ICR_RIEN)
+
+#define uart_disable_recv_intr(sc) \
+        uart_intr_disable((sc), ~(ICR_RIEN))
+
+
+/*********************************************************************
+ * Routines for accessing a remote (router) UART
+ */
+
+#define READ_RTR_L1_UART_REG(p, n, r, v)		\
+    {							\
+	if( vector_read_node( (p), (n), 0,		\
+			      RR_JBUS1(r), (v) ) ) {	\
+	    return UART_VECTOR;				\
+	}						\
+    }
+
+#define WRITE_RTR_L1_UART_REG(p, n, r, v)		\
+    {							\
+	if( vector_write_node( (p), (n), 0,		\
+			       RR_JBUS1(r), (v) ) ) {	\
+	    return UART_VECTOR;				\
+	}						\
+    }
+
+#define RTR_UART_PUTC_TIMEOUT	UART_PUTC_TIMEOUT*10
+#define RTR_UART_DELAY_SPAN	UART_DELAY_SPAN
+#define RTR_UART_INIT_TIMEOUT	UART_INIT_TIMEOUT*10
+
+static int
+rtr_uart_putc( l1sc_t *sc )
+{
+    uint64_t regval, c;
+    nasid_t nasid = sc->nasid;
+    net_vec_t path = sc->uart;
+    rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT;
+
+    c = (sc->send[sc->sent] & 0xffULL);
+    
+    while( 1 ) 
+    {
+        /* Check for "tx hold reg empty" bit. */
+	READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+	if( regval & LSR_XHRE )
+	{
+	    WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c );
+	    return UART_SUCCESS;
+	}
+
+	if( rtc_time() >= expire ) 
+	{
+	    return UART_TIMEOUT;
+	}
+	uart_delay( RTR_UART_DELAY_SPAN );
+    }
+}
+
+
+static int
+rtr_uart_getc( l1sc_t *sc )
+{
+    uint64_t regval;
+    nasid_t nasid = sc->nasid;
+    net_vec_t path = sc->uart;
+
+    READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+    if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) )
+    {
+	if( regval & LSR_RCA )
+	{
+	    READ_RTR_L1_UART_REG( path, nasid, REG_DAT, &regval );
+	    return( (int)regval );
+	}
+	else
+	{
+	    return UART_LINK;
+	}
+    }
+
+    return UART_NO_CHAR;
+}
+
+
+static int
+rtr_uart_init( l1sc_t *sc, int baud )
+{
+    rtc_time_t expire;
+    int clkdiv;
+    nasid_t nasid;
+    net_vec_t path;
+    uint64_t regval;
+
+    clkdiv = PROM_SER_DIVISOR(baud);
+    expire = rtc_time() + RTR_UART_INIT_TIMEOUT;
+    nasid = sc->nasid;
+    path = sc->uart;
+
+    /* make sure the transmit FIFO is empty */
+    while(1) {
+	READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+	if( regval & LSR_XSRE ) {
+	    break;
+	}
+	if( rtc_time() > expire ) {
+	    break;
+	}
+	uart_delay( RTR_UART_DELAY_SPAN );
+    }
+
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* set operating parameters and set DLAB to 0 */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* disable interrupts */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* enable FIFO mode and reset both FIFOs */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR,
+	FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO );
+
+    return 0;
+}
+
+/*********************************************************************
+ * locking macros 
+ */
+
+#define L1SC_SEND_LOCK(l,p)   { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); }
+#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); }
+#define L1SC_RECV_LOCK(l,p)   { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } 
+#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); }
+
+
+/*********************************************************************
+ * subchannel manipulation 
+ *
+ * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel
+ * allocation.  SUBCH_DATA_[UN]LOCK control access to data structures
+ * associated with particular subchannels (e.g., receive queues).
+ *
+ */
+#define SUBCH_LOCK(sc, p)		spin_lock_irqsave( &((sc)->subch_lock), p )
+#define SUBCH_UNLOCK(sc, p)		spin_unlock_irqrestore( &((sc)->subch_lock), p )
+#define SUBCH_DATA_LOCK(sbch, p) 	spin_lock_irqsave( &((sbch)->data_lock), p )
+#define SUBCH_DATA_UNLOCK(sbch, p)	spin_unlock_irqrestore( &((sbch)->data_lock), p )
+
+
+/*
+ * set a function to be called for subchannel ch in the event of
+ * a transmission low-water interrupt from the uart
+ */
+void
+subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
+{
+    unsigned long pl = 0;
+
+    L1SC_SEND_LOCK( sc, pl );
+#if	!defined(SYNC_CONSOLE_WRITE)
+    if ( func && !sc->send_in_use )
+	uart_enable_xmit_intr( sc );
+#endif
+    sc->subch[ch].tx_notify = func;
+    L1SC_SEND_UNLOCK(sc, pl );
+}
+
+/*
+ * set a function to be called for subchannel ch when data is received
+ */
+void
+subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    SUBCH_DATA_LOCK( subch, pl );
+    sc->subch[ch].rx_notify = func;
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+/*********************************************************************
+ * Queue manipulation macros
+ *
+ *
+ */
+#define NEXT(p)         (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */
+
+#define cq_init(q)      bzero((q), sizeof (*(q)))
+#define cq_empty(q)     ((q)->ipos == (q)->opos)
+#define cq_full(q)      (NEXT((q)->ipos) == (q)->opos)
+#define cq_used(q)      ((q)->opos <= (q)->ipos ?                       \
+                         (q)->ipos - (q)->opos :                        \
+                         BRL1_QSIZE + (q)->ipos - (q)->opos)
+#define cq_room(q)      ((q)->opos <= (q)->ipos ?                       \
+                         BRL1_QSIZE - 1 + (q)->opos - (q)->ipos :       \
+                         (q)->opos - (q)->ipos - 1)
+#define cq_add(q, c)    ((q)->buf[(q)->ipos] = (u_char) (c),            \
+                         (q)->ipos = NEXT((q)->ipos))
+#define cq_rem(q, c)    ((c) = (q)->buf[(q)->opos],                     \
+                         (q)->opos = NEXT((q)->opos))
+#define cq_discard(q)	((q)->opos = NEXT((q)->opos))
+
+#define cq_tent_full(q)	(NEXT((q)->tent_next) == (q)->opos)
+#define cq_tent_len(q)	((q)->ipos <= (q)->tent_next ?			\
+			 (q)->tent_next - (q)->ipos :			\
+			 BRL1_QSIZE + (q)->tent_next - (q)->ipos)
+#define cq_tent_add(q, c)						\
+			((q)->buf[(q)->tent_next] = (u_char) (c),	\
+			 (q)->tent_next = NEXT((q)->tent_next))
+#define cq_commit_tent(q)						\
+			((q)->ipos = (q)->tent_next)
+#define cq_discard_tent(q)						\
+			((q)->tent_next = (q)->ipos)
+
+
+
+
+/*********************************************************************
+ * CRC-16 (for checking bedrock/L1 packets).
+ *
+ * These are based on RFC 1662 ("PPP in HDLC-like framing").
+ */
+
+static unsigned short fcstab[256] = {
+      0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+      0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+      0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+      0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+      0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+      0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+      0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+      0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+      0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+      0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+      0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+      0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+      0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+      0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+      0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+      0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+      0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+      0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+      0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+      0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+      0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+      0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+      0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+      0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+      0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+      0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+      0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+      0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+      0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+      0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+      0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+      0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define INIT_CRC	0xFFFF	/* initial CRC value	  */
+#define	GOOD_CRC	0xF0B8	/* "good" final CRC value */
+
+static unsigned short crc16_calc( unsigned short crc, u_char c )
+{
+    return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] );
+}
+
+
+/***********************************************************************
+ * The following functions implement the PPP-like bedrock/L1 protocol
+ * layer.
+ *
+ */
+
+#define BRL1_FLAG_CH	0x7e
+#define BRL1_ESC_CH	0x7d
+#define BRL1_XOR_CH	0x20
+
+/* L1<->Bedrock packet types */
+#define BRL1_REQUEST    0x00
+#define BRL1_RESPONSE   0x20
+#define BRL1_EVENT      0x40
+
+#define BRL1_PKT_TYPE_MASK      0xE0
+#define BRL1_SUBCH_MASK         0x1F
+
+#define PKT_TYPE(tsb)   ((tsb) & BRL1_PKT_TYPE_MASK)
+#define SUBCH(tsb)	((tsb) & BRL1_SUBCH_MASK)
+
+/* timeouts */
+#define BRL1_INIT_TIMEOUT	500000
+
+/*
+ * brl1_discard_packet is a dummy "receive callback" used to get rid
+ * of packets we don't want
+ */
+void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &sc->subch[ch];
+
+    sc_cq_t *q = subch->iqp;
+    SUBCH_DATA_LOCK( subch, pl );
+    q->opos = q->ipos;
+    atomic_set(&(subch->packet_arrived), 0);
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+
+/*
+ * brl1_send_chars sends the send buffer in the l1sc_t structure
+ * out through the uart.  Assumes that the caller has locked the
+ * UART (or send buffer in the kernel).
+ *
+ * This routine doesn't block-- if you want it to, call it in
+ * a loop.
+ */
+static int
+brl1_send_chars( l1sc_t *sc )
+{
+    /* We track the depth of the C brick's UART's
+     * fifo in software, and only check if the UART is accepting
+     * characters when our count indicates that the fifo should
+     * be full.
+     *
+     * For remote (router) UARTs, we check with the UART before sending every
+     * character.
+     */
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) )
+	    sc->fifo_space = UART_FIFO_DEPTH;
+	
+	while( (sc->sent < sc->send_len) && (sc->fifo_space) ) {
+	    uart_putc( sc );
+	    sc->fifo_space--;
+	    sc->sent++;
+	}
+    }
+    else {
+
+	/* remote (router) UARTs */
+
+	int result;
+	int tries = 0;
+
+	while( sc->sent < sc->send_len ) {
+	    result = sc->putc_f( sc );
+	    if( result >= 0 ) {
+		(sc->sent)++;
+		continue;
+	    }
+	    if( result == UART_TIMEOUT ) {
+		tries++;
+		/* send this character in TIMEOUT_RETRIES... */
+		if( tries < 30 /* TIMEOUT_RETRIES */ ) {
+		    continue;
+		}
+		/* ...or else... */
+		else {
+		    /* ...drop the packet. */
+		    sc->sent = sc->send_len;
+		    return sc->send_len;
+		}
+	    }
+	    if( result < 0 ) {
+		return result;
+	    }
+	}
+    }
+    return sc->sent;
+}
+
+
+/* brl1_send formats up a packet and (at least begins to) send it
+ * to the uart.  If the send buffer is in use when this routine obtains
+ * the lock, it will behave differently depending on the "wait" parameter.
+ * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"),
+ * hopefully encouraging the caller to back off (unlock any high-level 
+ * spinlocks) and allow the buffer some time to drain.  For wait==1 (high-
+ * priority I/O along the lines of kernel error messages), we will flush
+ * the current contents of the send buffer and beat on the uart
+ * until our message has been completely transmitted.
+ */
+
+static int
+brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait )
+{
+    unsigned long pl = 0;
+    int index;
+    int pkt_len = 0;
+    unsigned short crc = INIT_CRC;
+    char *send_ptr = sc->send;
+
+
+    if( sc->send_in_use && !(wait) ) {
+	/* We are in the middle of sending, but can wait until done */
+	return 0;
+    }
+    else if( sc->send_in_use ) {
+	/* buffer's in use, but we're synchronous I/O, so we're going
+	 * to send whatever's in there right now and take the buffer
+	 */
+	int counter = 0;
+
+	if ( sc->uart == BRL1_LOCALHUB_UART )
+		lock_console(sc->nasid);
+	L1SC_SEND_LOCK(sc, pl);
+	while( sc->sent < sc->send_len ) {
+		brl1_send_chars( sc );
+		if ( counter++ > 0xfffff ) {
+			char *str = "Looping waiting for uart to clear (1)\n";
+			early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED);
+			break;
+		}
+	}
+    }
+    else {
+	if ( sc->uart == BRL1_LOCALHUB_UART )
+		lock_console(sc->nasid);
+	L1SC_SEND_LOCK(sc, pl);
+	sc->send_in_use = 1;
+    }
+    *send_ptr++ = BRL1_FLAG_CH;
+    *send_ptr++ = type_and_subch;
+    pkt_len += 2;
+    crc = crc16_calc( crc, type_and_subch );
+
+    /* limit number of characters accepted to max payload size */
+    if( len > (BRL1_QSIZE - 1) )
+	len = (BRL1_QSIZE - 1);
+
+    /* copy in the message buffer (inserting PPP 
+     * framing info where necessary)
+     */
+    for( index = 0; index < len; index++ ) {
+
+	switch( *msg ) {
+	    
+	  case BRL1_FLAG_CH:
+	    *send_ptr++ = BRL1_ESC_CH;
+	    *send_ptr++ = (*msg) ^ BRL1_XOR_CH;
+	    pkt_len += 2;
+	    break;
+	    
+	  case BRL1_ESC_CH:
+	    *send_ptr++ = BRL1_ESC_CH;
+	    *send_ptr++ = (*msg) ^ BRL1_XOR_CH;
+	    pkt_len += 2;
+	    break;
+	    
+	  default:
+	    *send_ptr++ = *msg;
+	    pkt_len++;
+	}
+	crc = crc16_calc( crc, *msg );
+	msg++;
+    }
+    crc ^= 0xffff;
+
+    for( index = 0; index < sizeof(crc); index++ ) {
+	char crc_char = (char)(crc & 0x00FF);
+	if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	    *send_ptr++ = BRL1_ESC_CH;
+	    pkt_len++;
+	    crc_char ^= BRL1_XOR_CH;
+	}
+	*send_ptr++ = crc_char;
+	pkt_len++;
+	crc >>= 8;
+    }
+    
+    *send_ptr++ = BRL1_FLAG_CH;
+    pkt_len++;
+
+    sc->send_len = pkt_len;
+    sc->sent = 0;
+
+    {
+	int counter = 0;
+	do {
+		brl1_send_chars( sc );
+		if ( counter++ > 0xfffff ) {
+			char *str = "Looping waiting for uart to clear (2)\n";
+			early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED);
+			break;
+		}
+	} while( (sc->sent < sc->send_len) && wait );
+    }
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(sc->nasid);
+
+    if( sc->sent == sc->send_len ) {
+	/* success! release the send buffer and call the callup */
+#if	!defined(SYNC_CONSOLE_WRITE)
+	brl1_notif_t callup;
+#endif
+
+	sc->send_in_use = 0;
+	/* call any upper layer that's asked for notification */
+#if	defined(XX_SYNC_CONSOLE_WRITE)
+	/*
+	 * This is probably not a good idea - since the l1_ write func can be called multiple
+	 * time within the callup function.
+	 */
+	callup = subch->tx_notify;
+	if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) {
+		L1_collectibles[L1C_SEND_CALLUPS]++;
+		(*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq,
+				sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id,
+				sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch));
+	}
+#endif	/* SYNC_CONSOLE_WRITE */
+    }
+#if	!defined(SYNC_CONSOLE_WRITE)
+    else if ( !wait ) {
+	/* enable low-water interrupts so buffer will be drained */
+	uart_enable_xmit_intr(sc);
+    }
+#endif
+
+    L1SC_SEND_UNLOCK(sc, pl);
+
+    return len;
+}
+
+/* brl1_send_cont is intended to be called as an interrupt service
+ * routine.  It sends until the UART won't accept any more characters,
+ * or until an error is encountered (in which case we surrender the
+ * send buffer and give up trying to send the packet).  Once the
+ * last character in the packet has been sent, this routine releases
+ * the send buffer and calls any previously-registered "low-water"
+ * output routines.
+ */
+
+#if	!defined(SYNC_CONSOLE_WRITE)
+
+int
+brl1_send_cont( l1sc_t *sc )
+{
+    unsigned long pl = 0;
+    int done = 0;
+    brl1_notif_t callups[BRL1_NUM_SUBCHANS];
+    brl1_notif_t *callup;
+    brl1_sch_t *subch;
+    int index;
+
+    /*
+     * I'm not sure how I think this is to be handled - whether the lock is held
+     * over the interrupt - but it seems like it is a bad idea....
+     */
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(sc->nasid);
+    L1SC_SEND_LOCK(sc, pl);
+    brl1_send_chars( sc );
+    done = (sc->sent == sc->send_len);
+    if( done ) {
+	sc->send_in_use = 0;
+#if	!defined(SYNC_CONSOLE_WRITE)
+	uart_disable_xmit_intr(sc);
+#endif
+    }
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(sc->nasid);
+    /* Release the lock */
+    L1SC_SEND_UNLOCK(sc, pl);
+
+    return 0;
+}
+#endif	/* SYNC_CONSOLE_WRITE */
+
+/* internal function -- used by brl1_receive to read a character 
+ * from the uart and check whether errors occurred in the process.
+ */
+static int
+read_uart( l1sc_t *sc, int *c, int *result )
+{
+    *c = sc->getc_f( sc );
+
+    /* no character is available */
+    if( *c == UART_NO_CHAR ) {
+	*result = BRL1_NO_MESSAGE;
+	return 0;
+    }
+
+    /* some error in UART */
+    if( *c < 0 ) {
+	*result = BRL1_LINK;
+	return 0;
+    }
+
+    /* everything's fine */
+    *result = BRL1_VALID;
+    return 1;
+}
+
+
+/*
+ * brl1_receive
+ *
+ * This function reads a Bedrock-L1 protocol packet into the l1sc_t
+ * response buffer.
+ *
+ * The operation of this function can be expressed as a finite state
+ * machine:
+ *
+
+START STATE			INPUT		TRANSITION
+==========================================================
+BRL1_IDLE (reset or error)	flag		BRL1_FLAG
+				other		BRL1_IDLE@
+
+BRL1_FLAG (saw a flag (0x7e))	flag		BRL1_FLAG
+				escape		BRL1_IDLE@
+				header byte	BRL1_HDR
+				other		BRL1_IDLE@
+
+BRL1_HDR (saw a type/subch byte)(see below)	BRL1_BODY
+						BRL1_HDR
+
+BRL1_BODY (reading packet body)	flag		BRL1_FLAG
+				escape		BRL1_ESC
+				other		BRL1_BODY
+
+BRL1_ESC (saw an escape (0x7d))	flag		BRL1_FLAG@
+				escape		BRL1_IDLE@
+				other		BRL1_BODY
+==========================================================
+
+"@" denotes an error transition.
+
+ * The BRL1_HDR state is a transient state which doesn't read input,
+ * but just provides a way in to code which decides to whom an
+ * incoming packet should be directed.
+ *
+ * brl1_receive can be used to poll for input from the L1, or as 
+ * an interrupt service routine.  It reads as much data as is
+ * ready from the junk bus UART and places into the appropriate
+ * input queues according to subchannel.  The header byte is
+ * stripped from console-type data, but is retained for message-
+ * type data (L1 responses).  A length byte will also be
+ * prepended to message-type packets.
+ *
+ * This routine is non-blocking; if the caller needs to block
+ * for input, it must call brl1_receive in a loop.
+ *
+ * brl1_receive returns when there is no more input, the queue
+ * for the current incoming message is full, or there is an
+ * error (parity error, bad header, bad CRC, etc.).
+ */
+
+#define STATE_SET(l,s)		((l)->brl1_state = (s))
+#define STATE_GET(l)		((l)->brl1_state)
+
+#define LAST_HDR_SET(l,h)	((l)->brl1_last_hdr = (h))
+#define LAST_HDR_GET(l)		((l)->brl1_last_hdr)
+
+#define VALID_HDR(c)				\
+    ( SUBCH((c)) <= SC_CONS_SYSTEM		\
+	? PKT_TYPE((c)) == BRL1_REQUEST		\
+	: ( PKT_TYPE((c)) == BRL1_RESPONSE ||	\
+	    PKT_TYPE((c)) == BRL1_EVENT ) )
+
+#define IS_TTY_PKT(l)		( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 )
+
+
+int
+brl1_receive( l1sc_t *sc, int mode )
+{
+    int result;		/* value to be returned by brl1_receive */
+    int c;		/* most-recently-read character	     	*/
+    int done;		/* set done to break out of recv loop	*/
+    unsigned long pl = 0, cpl = 0;
+    sc_cq_t *q;		/* pointer to queue we're working with	*/
+
+    result = BRL1_NO_MESSAGE;
+
+    L1SC_RECV_LOCK(sc, cpl);
+
+    done = 0;
+    while( !done )
+    {
+	switch( STATE_GET(sc) )
+	{
+
+	  case BRL1_IDLE:
+	    /* Initial or error state.  Waiting for a flag character
+             * to resynchronize with the L1.
+             */
+
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* saw a flag character */
+		STATE_SET( sc, BRL1_FLAG );
+		continue;
+	    }
+	    break;
+	    
+	  case BRL1_FLAG:
+	    /* One or more flag characters have been read; look for
+	     * the beginning of a packet (header byte).
+	     */
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR )
+		    STATE_SET( sc, BRL1_IDLE );
+
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* multiple flags are OK */
+		continue;
+	    }
+
+	    if( !VALID_HDR( c ) ) {
+		/* if c isn't a flag it should have been
+		 * a valid header, so we have an error
+		 */
+		result = BRL1_PROTOCOL;
+		STATE_SET( sc, BRL1_IDLE );
+		done = 1;
+		continue;
+	    }
+
+	    /* we have a valid header byte */
+	    LAST_HDR_SET( sc, c );
+	    STATE_SET( sc, BRL1_HDR );
+
+	    break; 
+
+	  case BRL1_HDR:
+	    /* A header byte has been read. Do some bookkeeping. */
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+	    
+	    if( !IS_TTY_PKT(sc) ) {
+		/* if this is an event or command response rather
+		 * than console I/O, we need to reserve a couple
+		 * of extra spaces in the queue for the header
+		 * byte and a length byte; if we can't, stay in
+		 * the BRL1_HDR state.
+		 */
+		if( cq_room( q ) < 2 ) {
+		    result = BRL1_FULL_Q;
+		    done = 1;
+		    continue;
+		}
+		cq_tent_add( q, 0 );			/* reserve length byte */
+		cq_tent_add( q, LAST_HDR_GET( sc ) );	/* record header byte  */
+	    }
+	    STATE_SET( sc, BRL1_BODY );
+
+	    break;
+
+	  case BRL1_BODY:
+	    /* A header byte has been read.  We are now attempting
+	     * to receive the packet body.
+	     */
+
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+
+	    /* if the queue we want to write into is full, don't read from
+	     * the uart (this provides backpressure to the L1 side)
+	     */
+	    if( cq_tent_full( q ) ) {
+		result = BRL1_FULL_Q;
+		done = 1;
+		continue;
+	    }
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR )
+		    STATE_SET( sc, BRL1_IDLE );
+		done = 1;
+		continue;
+	    }
+
+	    if( c == BRL1_ESC_CH ) {
+		/* prepare to unescape the next character */
+		STATE_SET( sc, BRL1_ESC );
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* flag signifies the end of a packet */
+
+		unsigned short crc;	/* holds the crc as we calculate it */
+		int i;			/* index variable */
+		brl1_sch_t *subch;      /* subchannel for received packet */
+		brl1_notif_t callup;	/* "data ready" callup */
+
+		/* whatever else may happen, we've seen a flag and we're
+		 * starting a new packet
+		 */
+		STATE_SET( sc, BRL1_FLAG );
+
+		/* if the packet body has less than 2 characters,
+		 * it can't be a well-formed packet.  Discard it.
+		 */
+		if( cq_tent_len( q ) < /* 2 + possible length byte */
+		    (2 + (IS_TTY_PKT(sc) ? 0 : 1)) )
+		{
+		    result = BRL1_PROTOCOL;
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_FLAG );
+		    done = 1;
+		    continue;
+		}
+		
+		/* check CRC */
+
+		/* accumulate CRC, starting with the header byte and
+		 * ending with the transmitted CRC.  This should
+		 * result in a known good value.
+		 */
+		crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) );
+		for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE;
+		     i != q->tent_next;
+		     i = (i + 1) % BRL1_QSIZE )
+		{
+		    crc = crc16_calc( crc, q->buf[i] );
+		}
+
+		/* verify the caclulated crc against the "good" crc value;
+		 * if we fail, discard the bad packet and return an error.
+		 */
+		if( crc != (unsigned short)GOOD_CRC ) {
+		    result = BRL1_CRC;
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_FLAG );
+		    done = 1;
+		    continue;
+		}
+		
+		/* so the crc check was ok.  Now we discard the CRC
+		 * from the end of the received bytes.
+		 */
+		q->tent_next += (BRL1_QSIZE - 2);
+		q->tent_next %= BRL1_QSIZE;
+
+		/* get the subchannel and lock it */
+		subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]);
+		SUBCH_DATA_LOCK( subch, pl );
+		
+		/* if this isn't a console packet, we need to record
+		 * a length byte
+		 */
+		if( !IS_TTY_PKT(sc) ) {
+		    q->buf[q->ipos] = cq_tent_len( q ) - 1;
+		}
+		
+		/* record packet for posterity */
+		cq_commit_tent( q );
+		result = BRL1_VALID;
+
+		/* notify subchannel owner that there's something
+		 * on the queue for them
+		 */
+		atomic_inc(&(subch->packet_arrived));
+		callup = subch->rx_notify;
+		SUBCH_DATA_UNLOCK( subch, pl );
+
+		if( callup && (mode == SERIAL_INTERRUPT_MODE) ) {
+		    L1SC_RECV_UNLOCK( sc, cpl );
+		    L1_collectibles[L1C_RECEIVE_CALLUPS]++;
+		    (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq,
+				sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id,
+				sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs,
+				sc, SUBCH(LAST_HDR_GET(sc)) );
+		    L1SC_RECV_LOCK( sc, cpl );
+		}
+		continue;	/* go back for more! */
+	    }
+	    
+	    /* none of the special cases applied; we've got a normal
+	     * body character
+	     */
+	    cq_tent_add( q, c );
+
+	    break;
+
+	  case BRL1_ESC:
+	    /* saw an escape character.  The next character will need
+	     * to be unescaped.
+	     */
+
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+
+	    /* if the queue we want to write into is full, don't read from
+	     * the uart (this provides backpressure to the L1 side)
+	     */
+	    if( cq_tent_full( q ) ) {
+		result = BRL1_FULL_Q;
+		done = 1;
+		continue;
+	    }
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR ) {
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_IDLE );
+		}
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* flag after escape is an error */
+		STATE_SET( sc, BRL1_FLAG );
+		cq_discard_tent( q );
+		result = BRL1_PROTOCOL;
+		done = 1;
+		continue;
+	    }
+
+	    if( c == BRL1_ESC_CH ) {
+		/* two consecutive escapes is an error */
+		STATE_SET( sc, BRL1_IDLE );
+		cq_discard_tent( q );
+		result = BRL1_PROTOCOL;
+		done = 1;
+		continue;
+	    }
+	    
+	    /* otherwise, we've got a character that needs
+	     * to be unescaped
+	     */
+	    cq_tent_add( q, (c ^ BRL1_XOR_CH) );
+	    STATE_SET( sc, BRL1_BODY );
+
+	    break;
+
+	} /* end of switch( STATE_GET(sc) ) */
+    } /* end of while(!done) */
+
+    L1SC_RECV_UNLOCK( sc, cpl );
+
+    return result;
+}	    
+
+
+/* brl1_init initializes the Bedrock/L1 protocol layer.  This includes
+ * zeroing out the send and receive state information.
+ */
+
+void
+brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    int i;
+    brl1_sch_t *subch;
+
+    bzero( sc, sizeof( *sc ) );
+    sc->nasid = nasid;
+    sc->uart = uart;
+    sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc);
+    sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc);
+    sc->sol = 1;
+    subch = sc->subch;
+
+    /* initialize L1 subchannels
+     */
+
+    /* assign processor TTY channels */
+    for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_RSVD;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	spin_lock_init( &(subch->data_lock) );
+	sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
+	subch->tx_notify = NULL;
+	/* (for now, drop elscuart packets in the kernel) */
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* assign system TTY channel (first free subchannel after each
+     * processor's individual TTY channel has been assigned)
+     */
+    subch->use = BRL1_SUBCH_RSVD;
+    subch->packet_arrived = ATOMIC_INIT(0);
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
+    subch->tx_notify = NULL;
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) );
+	ASSERT( subch->iqp );
+	cq_init( subch->iqp );
+	subch->rx_notify = NULL;
+    }
+    else {
+	/* we shouldn't be getting console input from remote UARTs */
+	subch->iqp = &sc->garbage_q;
+	subch->rx_notify = brl1_discard_packet;
+    }
+    subch++; i++;
+
+    /* "reserved" subchannels (0x05-0x0F); for now, throw away
+     * incoming packets
+     */
+    for( ; i < 0x10; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* remaining subchannels are free */
+    for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* initialize synchronization structures
+     */
+    spin_lock_init( &(sc->subch_lock) );
+    spin_lock_init( &(sc->send_lock) );
+    spin_lock_init( &(sc->recv_lock) );
+
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	uart_init( sc, UART_BAUD_RATE );
+    }
+    else {
+	rtr_uart_init( sc, UART_BAUD_RATE );
+    }
+
+    /* Set up remaining fields using L1 command functions-- elsc_module_get
+     * to read the module id, elsc_debug_get to see whether or not we're
+     * in verbose mode.
+     */
+    {
+	extern int elsc_module_get(l1sc_t *);
+
+	sc->modid = elsc_module_get( sc );
+	sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid);
+	sc->verbose = 1;
+    }
+}
+
+/*********************************************************************
+ * These are interrupt-related functions used in the kernel to service
+ * the L1.
+ */
+
+/*
+ * brl1_intrd is the function which is called on a console interrupt.
+ */
+
+
+static void
+brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff)
+{
+    u_char isr_reg;
+    l1sc_t *sc = get_elsc();
+    int ret;
+
+    L1_collectibles[L1C_INTERRUPTS]++;
+    isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
+
+    /* Save for callup args in console */
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq;
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id;
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff;
+
+#if	defined(SYNC_CONSOLE_WRITE)
+    while( isr_reg & ISR_RxRDY )
+#else
+    while( isr_reg & (ISR_RxRDY | ISR_TxRDY) )
+#endif
+    {
+	if( isr_reg & ISR_RxRDY ) {
+	    L1_collectibles[L1C_OUR_R_INTERRUPTS]++;
+	    ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE);
+	    if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) )
+		L1_collectibles[L1C_REC_STALLS] = ret;
+	}
+#if	!defined(SYNC_CONSOLE_WRITE)
+	if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) {
+	    L1_collectibles[L1C_OUR_X_INTERRUPTS]++;
+	    brl1_send_cont(sc);
+	}
+#endif	/* SYNC_CONSOLE_WRITE */
+	isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
+    }
+}
+
+
+/*
+ * Install a callback function for the system console subchannel 
+ * to allow an upper layer to be notified when the send buffer 
+ * has been emptied.
+ */
+static inline void
+l1_tx_notif( brl1_notif_t func )
+{
+	subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc,
+			SC_CONS_SYSTEM, func );
+}
+
+
+/*
+ * Install a callback function for the system console subchannel
+ * to allow an upper layer to be notified when a packet has been
+ * received.
+ */
+static inline void
+l1_rx_notif( brl1_notif_t func )
+{
+	subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc,
+				SC_CONS_SYSTEM, func );
+}
+
+
+/* brl1_intr is called directly from the uart interrupt; after it runs, the
+ * interrupt "daemon" xthread is signalled to continue.
+ */
+void
+brl1_intr( void )
+{
+}
+
+#define BRL1_INTERRUPT_LEVEL	65	/* linux request_irq() value */
+
+/* Return the current interrupt level */
+
+//#define CONSOLE_POLLING_ALSO
+
+int
+l1_get_intr_value( void )
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	return(0);
+#else
+#if defined(CONSOLE_POLLING_ALSO)
+	return(0);
+#else
+	return(BRL1_INTERRUPT_LEVEL);
+#endif /* CONSOLE_POLLING_ALSO */
+#endif /* USE_SAL_CONSOLE_IO */
+}
+
+/* Disconnect the callup functions - throw away interrupts */
+
+void
+l1_unconnect_intr(void)
+{
+#if !defined(USE_SAL_CONSOLE_IO)
+	/* UnRegister the upper-level callup functions */
+	l1_rx_notif((brl1_notif_t)NULL);
+	l1_tx_notif((brl1_notif_t)NULL);
+	/* We do NOT unregister the interrupts */
+#endif /* !USE_SAL_CONSOLE_IO */
+}
+
+/* Set up uart interrupt handling for this node's uart */
+
+void
+l1_connect_intr(void *rx_notify, void *tx_notify)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+#if 0
+	// Will need code here for sn2 - something like this
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid());
+	intr_connect_level(console_nodepda->node_first_cpu,
+                                SGI_UART_VECTOR, INTPEND0_MAXMASK,
+                                dummy_intr_func);
+	request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8),
+                                intr_func, SA_INTERRUPT | SA_SHIRQ,
+                                "l1_protocol_driver", (void *)sc);
+#endif
+#else
+	l1sc_t *sc;
+	nasid_t nasid;
+	int tmp;
+	nodepda_t *console_nodepda;
+	int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t);
+
+	if ( L1_interrupts_connected ) {
+		/* Interrupts are connected, so just register the callups */
+		l1_rx_notif((brl1_notif_t)rx_notify);
+		l1_tx_notif((brl1_notif_t)tx_notify);
+
+		L1_collectibles[L1C_CONNECT_CALLS]++;
+		return;
+	}
+	else
+		L1_interrupts_connected = 1;
+
+	nasid = get_master_nasid();
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid));
+	sc = &console_nodepda->module->elsc;
+	sc->intr_cpu = console_nodepda->node_first_cpu;
+
+	if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) {
+		L1_interrupts_connected = 0; /* FAILS !! */
+	}
+	else {
+		void synergy_intr_connect(int, int);
+
+		synergy_intr_connect(UART_INTR, sc->intr_cpu);
+		L1_collectibles[L1C_R_IRQ]++;
+		tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc);
+		L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp;
+		if ( tmp ) {
+			L1_interrupts_connected = 0; /* FAILS !! */
+		}
+		else {
+			/* Register the upper-level callup functions */
+			l1_rx_notif((brl1_notif_t)rx_notify);
+			l1_tx_notif((brl1_notif_t)tx_notify);
+
+			/* Set the uarts the way we like it */
+			uart_enable_recv_intr( sc );
+			uart_disable_xmit_intr( sc );
+		}
+	}
+#endif	/* USE_SAL_CONSOLE_IO */
+}
+
+
+/* These are functions to use from serial_in/out when in protocol
+ * mode to send and receive uart control regs. These are external
+ * interfaces into the protocol driver.
+ */
+
+void
+l1_control_out(int offset, int value)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	/* quietly ignore unless simulator */
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		if ( master_node_bedrock_address != (u64)0 ) {
+			writeb(value, (unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		}
+		return;
+	}
+#else
+	nasid_t nasid = get_master_nasid();
+	WRITE_L1_UART_REG(nasid, offset, value); 
+#endif
+}
+
+/* Console input exported interface. Return a register value.  */
+
+int
+l1_control_in_polled(int offset)
+{
+	static int l1_control_in_local(int, int);
+
+	return(l1_control_in_local(offset, SERIAL_POLLED_MODE));
+}
+
+int
+l1_control_in(int offset)
+{
+	static int l1_control_in_local(int, int);
+
+	return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE));
+}
+
+static int
+l1_control_in_local(int offset, int mode)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if ( offset == REG_LSR ) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if ( !sal_call_status && input ) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+
+	/* If the sal call failed, do it the old-fashioned way */
+	if ( sal_call_status ) {
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+			ret = readb((unsigned long)master_node_bedrock_address +
+					(offset<< 3));
+		}		
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid;
+			int ret, input;
+			static int l1_poll(l1sc_t *, int);
+
+			nasid = get_master_nasid();
+			ret = READ_L1_UART_REG(nasid, offset); 
+
+			if ( offset == REG_LSR ) {
+				ret |= (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+				if ( L1_cons_is_inited ) {
+					if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) {
+						input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode);
+						if ( input ) {
+							ret |= LSR_RCA;
+						}
+					}
+				}
+			}
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+#endif
+	return(ret);
+}
+
+/*
+ * Console input exported interface. Return a character (if one is available)
+ */
+
+int
+l1_serial_in_polled(void)
+{
+	static int l1_serial_in_local(int mode);
+
+	return(l1_serial_in_local(SERIAL_POLLED_MODE));
+}
+
+int
+l1_serial_in(void)
+{
+	static int l1_serial_in_local(int mode);
+
+	return(l1_serial_in_local(SERIAL_INTERRUPT_MODE));
+}
+
+static int
+l1_serial_in_local(int mode)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	int sal_call_status;
+	int ch;
+
+	sal_call_status = ia64_sn_console_getc(&ch);
+	if ( !sal_call_status ) {
+		return(ch);
+	}
+	else {
+		/* If the sal called failed - do it the old-fashioned way */
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+			return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+		}		
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid;
+			l1sc_t *sc;
+			int value;
+			static int l1_getc( l1sc_t *, int );
+			static inline l1sc_t *early_sc_init(nasid_t);
+
+			nasid = get_master_nasid();
+			sc = early_sc_init(nasid);
+			if ( L1_cons_is_inited ) {
+				if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) {
+					sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc;
+				}
+			}
+			value = l1_getc(sc, mode);
+			return(value);
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+#endif
+}
+
+/* Console output exported interface. Write message to the console.  */
+
+int
+l1_serial_out( char *str, int len )
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	void early_sn_setup(void);
+	int sal_call_status = 0;
+	int counter = len;
+
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+	{
+		static int inited;
+		if(!inited) {
+			inited=1;
+			early_sn_setup();
+		}
+	}
+#endif
+
+	/* Attempt to write things out thru the sal */
+	sal_call_status = ia64_sn_console_putb(str, len);
+	if ( sal_call_status ) {
+		/* If the sal called failed - do it the old-fashioned way */
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+                        if (!master_node_bedrock_address)
+                                early_sn_setup();
+			if ( master_node_bedrock_address != (u64)0 ) {
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+				/* This is an easy way to pre-pend the output to know whether the output
+				 * was done via sal or directly */
+				writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+#endif	/* FLAG_DIRECT_CONSOLE_WRITES */
+				while ( counter > 0 ) {
+					writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+					counter--;
+					str++;
+				}
+			}
+		}
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid = get_master_nasid();
+			int l1_write(l1sc_t *, char *, int, int);
+
+			if ( L1_cons_is_inited ) {
+				if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 )
+					return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len,
+#if	defined(SYNC_CONSOLE_WRITE)
+							1
+#else
+							!L1_interrupts_connected
+#endif
+									));
+			}
+			return(early_l1_serial_out(nasid, str, len, NOT_LOCKED));
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+	return((counter <= 0) ? 0 : (len - counter));
+#endif
+}
+
+
+/*
+ * These are the 'early' functions - when we need to do things before we have
+ * all the structs setup.
+ */
+
+
+static l1sc_t Early_console;		/* fake l1sc_t */
+static int Early_console_inited = 0;
+
+static void
+early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    int i;
+    brl1_sch_t *subch;
+
+    bzero( sc, sizeof( *sc ) );
+    sc->nasid = nasid;
+    sc->uart = uart;
+    sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc);
+    sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc);
+    sc->sol = 1;
+    subch = sc->subch;
+
+    /* initialize L1 subchannels
+     */
+
+    /* assign processor TTY channels */
+    for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_RSVD;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* assign system TTY channel (first free subchannel after each
+     * processor's individual TTY channel has been assigned)
+     */
+    subch->use = BRL1_SUBCH_RSVD;
+    subch->packet_arrived = ATOMIC_INIT(0);
+    subch->tx_notify = NULL;
+    subch->rx_notify = NULL;
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	static sc_cq_t x_iqp;
+
+	subch->iqp = &x_iqp;
+	ASSERT( subch->iqp );
+	cq_init( subch->iqp );
+    }
+    else {
+	/* we shouldn't be getting console input from remote UARTs */
+	subch->iqp = &sc->garbage_q;
+    }
+    subch++; i++;
+
+    /* "reserved" subchannels (0x05-0x0F); for now, throw away
+     * incoming packets
+     */
+    for( ; i < 0x10; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* remaining subchannels are free */
+    for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+}
+
+static inline l1sc_t *
+early_sc_init(nasid_t nasid)
+{
+	/* This is for early I/O */
+	if ( Early_console_inited == 0 ) {
+    		early_brl1_init(&Early_console, nasid,  BRL1_LOCALHUB_UART);
+		Early_console_inited = 1;
+	}
+	return(&Early_console);
+}
+
+#define PUTCHAR(ch) \
+    { \
+        while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \
+                (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \
+        WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \
+    }
+
+static int
+early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state )
+{
+	int ret, sent = 0;
+	char *msg = str;
+	static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state );
+
+	while ( sent < len ) {
+		ret = early_l1_send(nasid, msg, len - sent, lock_state);
+		sent += ret;
+		msg += ret;
+	}
+	return(len);
+}
+
+static inline int
+early_l1_send( nasid_t nasid, char *str, int len, int lock_state )
+{
+    int sent;
+    char crc_char;
+    unsigned short crc = INIT_CRC;
+
+    if( len > (BRL1_QSIZE - 1) )
+	len = (BRL1_QSIZE - 1);
+
+    sent = len;
+    if ( lock_state == NOT_LOCKED )
+    	lock_console(nasid);
+
+    PUTCHAR( BRL1_FLAG_CH );
+    PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM );
+    crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) );
+
+    while( len ) {
+
+	if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) {
+	    PUTCHAR( BRL1_ESC_CH );
+	    PUTCHAR( (*str) ^ BRL1_XOR_CH );
+	}
+	else {
+	    PUTCHAR( *str );
+	}
+	
+	crc = crc16_calc( crc, *str );
+
+	str++; len--;
+    }
+    
+    crc ^= 0xffff;
+    crc_char = crc & 0xff;
+    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	crc_char ^= BRL1_XOR_CH;
+	PUTCHAR( BRL1_ESC_CH );
+    }
+    PUTCHAR( crc_char );
+    crc_char = (crc >> 8) & 0xff;
+    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	crc_char ^= BRL1_XOR_CH;
+	PUTCHAR( BRL1_ESC_CH );
+    }
+    PUTCHAR( crc_char );
+    PUTCHAR( BRL1_FLAG_CH );
+
+    if ( lock_state == NOT_LOCKED )
+    	unlock_console(nasid);
+    return sent;
+}
+
+/*********************************************************************
+ * l1_cons functions
+ *
+ * These allow the L1 to act as the system console.  They're intended
+ * to abstract away most of the br/l1 internal details from the
+ * _L1_cons_* functions (in the prom-- see "l1_console.c") and
+ * l1_* functions (in the kernel-- see "sio_l1.c") that they support.
+ *
+ */
+
+static int
+l1_poll( l1sc_t *sc, int mode )
+{
+    int ret;
+
+    /* in case this gets called before the l1sc_t structure for the module_t
+     * struct for this node is initialized (i.e., if we're called with a
+     * zero l1sc_t pointer)...
+     */
+
+
+    if( !sc ) {
+	return 0;
+    }
+
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
+	return 1;
+    }
+
+    ret = brl1_receive( sc, mode );
+    if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) )
+	L1_collectibles[L1C_REC_STALLS] = ret;
+
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
+	return 1;
+    }
+    return 0;
+}
+
+
+/* pull a character off of the system console queue (if one is available)
+ */
+static int
+l1_getc( l1sc_t *sc, int mode )
+{
+    unsigned long pl = 0;
+    int c;
+
+    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
+    sc_cq_t *q = subch->iqp;
+
+    if( !l1_poll( sc, mode ) ) {
+	return 0;
+    }
+
+    SUBCH_DATA_LOCK( subch, pl );
+    if( cq_empty( q ) ) {
+	atomic_set(&subch->packet_arrived, 0);
+	SUBCH_DATA_UNLOCK( subch, pl );
+	return 0;
+    }
+    cq_rem( q, c );
+    if( cq_empty( q ) )
+	atomic_set(&subch->packet_arrived, 0);
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return c;
+}
+
+/*
+ * Write a message to the L1 on the system console subchannel.
+ *
+ * Danger: don't use a non-zero value for the wait parameter unless you're
+ * someone important (like a kernel error message).
+ */
+
+int
+l1_write( l1sc_t *sc, char *msg, int len, int wait )
+{
+	int sent = 0, ret = 0;
+
+	if ( wait ) {
+		while ( sent < len ) {
+			ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait );
+			sent += ret;
+			msg += ret;
+		}
+		ret = len;
+	}
+	else {
+		ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait );
+	}
+	return(ret);
+}
+
+/* initialize the system console subchannel
+ */
+void
+l1_init(void)
+{
+	/* All we do now is remember that we have been called */
+	L1_cons_is_inited = 1;
+}
+
+
+/*********************************************************************
+ * The following functions and definitions implement the "message"-
+ * style interface to the L1 system controller.
+ *
+ * Note that throughout this file, "sc" generally stands for "system
+ * controller", while "subchannels" tend to be represented by
+ * variables with names like subch or ch.
+ *
+ */
+
+#ifdef L1_DEBUG
+#define L1_DBG_PRF(x) printf x
+#else
+#define L1_DBG_PRF(x)
+#endif
+
+/*
+ * sc_data_ready is called to signal threads that are blocked on l1 input.
+ */
+void
+sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+
+    brl1_sch_t *subch = &(sc->subch[ch]);
+    SUBCH_DATA_LOCK( subch, pl );
+    sv_signal( &(subch->arrive_sv) );
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+/* sc_open reserves a subchannel to send a request to the L1 (the
+ * L1's response will arrive on the same channel).  The number
+ * returned by sc_open is the system controller subchannel
+ * acquired.
+ */
+int
+sc_open( l1sc_t *sc, uint target )
+{
+    /* The kernel version implements a locking scheme to arbitrate
+     * subchannel assignment.
+     */
+    int ch;
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    SUBCH_LOCK( sc, pl );
+
+    /* Look for a free subchannel. Subchannels 0-15 are reserved
+     * for other purposes.
+     */
+    for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; 
+			ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) {
+        if( subch->use == BRL1_SUBCH_FREE )
+            break;
+    }
+
+    if( ch == BRL1_NUM_SUBCHANS ) {
+        /* there were no subchannels available! */
+        SUBCH_UNLOCK( sc, pl );
+        return SC_NSUBCH;
+    }
+
+    subch->use = BRL1_SUBCH_RSVD;
+    SUBCH_UNLOCK( sc, pl );
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->target = target;
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
+    subch->tx_notify = NULL;
+    subch->rx_notify = sc_data_ready;
+    subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
+				   NASID_TO_COMPACT_NODEID(sc->nasid) );
+    ASSERT( subch->iqp );
+    cq_init( subch->iqp );
+
+    return ch;
+}
+
+
+/* sc_close frees a Bedrock<->L1 subchannel.
+ */
+int
+sc_close( l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    SUBCH_LOCK( sc, pl );
+    subch = &(sc->subch[ch]);
+    if( subch->use != BRL1_SUBCH_RSVD ) {
+        /* we're trying to close a subchannel that's not open */
+	SUBCH_UNLOCK( sc, pl );
+        return SC_NOPEN;
+    }
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->use = BRL1_SUBCH_FREE;
+
+    sv_broadcast( &(subch->arrive_sv) );
+    sv_destroy( &(subch->arrive_sv) );
+    spin_lock_destroy( &(subch->data_lock) );
+
+    ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) );
+    snia_kmem_free( subch->iqp, sizeof(sc_cq_t) );
+    subch->iqp = &sc->garbage_q;
+    subch->tx_notify = NULL;
+    subch->rx_notify = brl1_discard_packet;
+
+    SUBCH_UNLOCK( sc, pl );
+
+    return SC_SUCCESS;
+}
+
+
+/* sc_construct_msg builds a bedrock-to-L1 request in the supplied
+ * buffer.  Returns the length of the message.  The
+ * safest course when passing a buffer to be filled in is to use
+ * BRL1_QSIZE as the buffer size.
+ *
+ * Command arguments are passed as type/argument pairs, i.e., to
+ * pass the number 5 as an argument to an L1 command, call
+ * sc_construct_msg as follows:
+ *
+ *    char msg[BRL1_QSIZE];
+ *    msg_len = sc_construct_msg( msg,
+ *				  BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                2,
+ *                                L1_ARG_INT, 5 );
+ *
+ * To pass an additional ASCII argument, you'd do the following:
+ *
+ *    char *str;
+ *    ... str points to a null-terminated ascii string ...
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                4,
+ *                                L1_ARG_INT, 5,
+ *                                L1_ARG_ASCII, str );
+ *
+ * Finally, arbitrary data of unknown type is passed using the argtype
+ * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g.
+ *
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                3,
+ *                                L1_ARG_UNKNOWN, 32, bufptr );
+ *
+ * ...passes 32 bytes of data starting at bufptr.  Note that no string or
+ * "unknown"-type argument should be long enough to overflow the message
+ * buffer.
+ *
+ * To construct a message for an L1 command that requires no arguments,
+ * you'd use the following:
+ *
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                0 );
+ *
+ * The final 0 means "no varargs".  Notice that this parameter is used to hold
+ * the number of additional arguments to sc_construct_msg, _not_ the actual
+ * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII]
+ * type argument, and 3 per L1_ARG_UNKOWN type argument).  A call to construct
+ * an L1 command which required three integer arguments and two arguments of
+ * some arbitrary (unknown) type would pass 12 as the value for this parameter.
+ *
+ * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth
+ * between byte arrays and four-byte big-endian integers.  Depending on the
+ * system controller connection and endianness of future architectures, some
+ * rewriting might be necessary.
+ */
+int
+sc_construct_msg( l1sc_t  *sc,		/* system controller struct */
+		  int	   ch,           /* subchannel for this message */
+		  char    *msg,          /* message buffer */
+		  int      msg_len,      /* size of message buffer */
+                  l1addr_t addr_task,    /* target system controller task */
+                  short    req_code,     /* 16-bit request code */
+                  int      req_nargs,    /* # of arguments (varargs) passed */
+                  ... )                 /* any additional parameters */
+{
+    uint32_t buf32;   /* 32-bit buffer used to bounce things around */
+    void *bufptr;       /* used to hold command argument addresses */
+    va_list al;         /* variable argument list */
+    int index;          /* current index into msg buffer */
+    int argno;          /* current position in varargs list */
+    int l1_argno;       /* running total of arguments to l1 */
+    int l1_arg_t;       /* argument type/length */
+    int l1_argno_byte;  /* offset of argument count byte */
+
+    index = argno = 0;
+
+    /* set up destination address */
+    if( (msg_len -= sizeof( buf32 )) < 0 )
+	return -1;
+    L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task );
+    COPY_INT_TO_BUFFER(msg, index, buf32);
+
+    /* copy request code */
+    if( (msg_len -= 2) < 0 )
+	return( -1 );
+    msg[index++] = ((req_code >> 8) & 0xff);
+    msg[index++] = (req_code & 0xff);
+
+    if( !req_nargs ) {
+        return index;
+    }
+
+    /* reserve a byte for the argument count */
+    if( (msg_len -= 1) < 0 )
+	return( -1 );
+    l1_argno_byte = index++;
+    l1_argno = 0;
+
+    /* copy additional arguments */
+    va_start( al, req_nargs );
+    while( argno < req_nargs ) {
+        l1_argno++;
+        l1_arg_t = va_arg( al, int ); argno++;
+        switch( l1_arg_t )
+        {
+          case L1_ARG_INT:
+	    if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 )
+		return( -1 );
+            msg[index++] = L1_ARG_INT;
+            buf32 = (unsigned)va_arg( al, int ); argno++;
+	    COPY_INT_TO_BUFFER(msg, index, buf32);
+            break;
+
+          case L1_ARG_ASCII:
+            bufptr = va_arg( al, char* ); argno++;
+	    if( (msg_len -= (strlen( bufptr ) + 2)) < 0 )
+		return( -1 );
+            msg[index++] = L1_ARG_ASCII;
+            strcpy( (char *)&(msg[index]), (char *)bufptr );
+            index += (strlen( bufptr ) + 1); /* include terminating null */
+            break;
+
+	  case L1_ARG_UNKNOWN:
+              {
+                  int arglen;
+		  
+                  arglen = va_arg( al, int ); argno++;
+                  bufptr = va_arg( al, void* ); argno++;
+		  if( (msg_len -= (arglen + 1)) < 0 )
+		      return( -1 );
+                  msg[index++] = L1_ARG_UNKNOWN | arglen;
+                  BCOPY( bufptr, &(msg[index]), arglen  );
+                  index += arglen;
+		  break;
+              }
+	  
+	  default: /* unhandled argument type */
+	    return -1;
+        }
+    }
+
+    va_end( al );
+    msg[l1_argno_byte] = l1_argno;
+
+    return index;
+}
+
+
+
+/* sc_interpret_resp verifies an L1 response to a bedrock request, and
+ * breaks the response data up into the constituent parts.  If the
+ * response message indicates error, or if a mismatch is found in the
+ * expected number and type of arguments, an error is returned.  The
+ * arguments to this function work very much like the arguments to
+ * sc_construct_msg, above, except that L1_ARG_INTs must be followed
+ * by a _pointer_ to an integer that can be filled in by this function.
+ */
+int
+sc_interpret_resp( char *resp,          /* buffer received from L1 */
+                   int   resp_nargs,    /* number of _varargs_ passed in */
+                   ... )
+{
+    uint32_t buf32;   /* 32-bit buffer used to bounce things around */
+    void *bufptr;       /* used to hold response field addresses */
+    va_list al;         /* variable argument list */
+    int index;          /* current index into response buffer */
+    int argno;          /* current position in varargs list */
+    int l1_fldno;       /* number of resp fields received from l1 */
+    int l1_fld_t;       /* field type/length */
+
+    index = argno = 0;
+
+#if defined(L1_DEBUG)
+#define DUMP_RESP							  \
+    {									  \
+	int ix;								  \
+        char outbuf[512];						  \
+        sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \
+	for( ix = 0; ix < 16; ix++ ) {					  \
+	    sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] );	  \
+	}								  \
+	printk( "%s\n", outbuf );					  \
+    }
+#else
+#define DUMP_RESP
+#endif /* L1_DEBUG */
+
+    /* check response code */
+    COPY_BUFFER_TO_INT(resp, index, buf32);
+    if( buf32 != L1_RESP_OK ) {
+	DUMP_RESP;
+        return buf32;
+    }
+
+    /* get number of response fields */
+    l1_fldno = resp[index++];
+
+    va_start( al, resp_nargs );
+
+    /* copy out response fields */
+    while( argno < resp_nargs ) {
+        l1_fldno--;
+        l1_fld_t = va_arg( al, int ); argno++;
+        switch( l1_fld_t )
+        {
+          case L1_ARG_INT:
+            if( resp[index++] != L1_ARG_INT ) {
+                /* type mismatch */
+		va_end( al );
+		DUMP_RESP;
+		return -1;
+            }
+            bufptr = va_arg( al, int* ); argno++;
+	    COPY_BUFFER_TO_BUFFER(resp, index, bufptr);
+            break;
+
+          case L1_ARG_ASCII:
+            if( resp[index++] != L1_ARG_ASCII ) {
+                /* type mismatch */
+		va_end( al );
+		DUMP_RESP;
+                return -1;
+            }
+            bufptr = va_arg( al, char* ); argno++;
+            strcpy( (char *)bufptr, (char *)&(resp[index]) );
+            /* include terminating null */
+            index += (strlen( &(resp[index]) ) + 1);
+            break;
+
+          default:
+	    if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN )
+	    {
+		int *arglen;
+		
+		arglen = va_arg( al, int* ); argno++;
+		bufptr = va_arg( al, void* ); argno++;
+		*arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff);
+		BCOPY( &(resp[index]), bufptr, *arglen  );
+		index += (*arglen);
+	    }
+	    
+	    else {
+		/* unhandled type */
+		va_end( al );
+		DUMP_RESP;
+		return -1;
+	    }
+        }
+    }
+    va_end( al );
+  
+    if( (l1_fldno != 0) || (argno != resp_nargs) ) {
+        /* wrong number of arguments */
+	DUMP_RESP;
+        return -1;
+    }
+    return 0;
+}
+
+/* sc_send takes as arguments a system controller struct, a
+ * buffer which contains a Bedrock<->L1 "request" message,
+ * the message length, and the subchannel (presumably obtained
+ * from an earlier invocation of sc_open) over which the
+ * message is to be sent.  The final argument ("wait") indicates
+ * whether the send is to be performed synchronously or not.
+ *
+ * sc_send returns either zero or an error value.  Synchronous sends 
+ * (wait != 0) will not return until the data has actually been sent
+ * to the UART.  Synchronous sends generally receive privileged
+ * treatment.  The intent is that they be used sparingly, for such
+ * purposes as kernel printf's (the "ducons" routines).  Run-of-the-mill
+ * console output and L1 requests should NOT use a non-zero value
+ * for wait.
+ */
+int
+sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait )
+{
+    char type_and_subch;
+    int result;
+
+    if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) {
+        return SC_BADSUBCH;
+    }
+
+    /* Verify that this is an open subchannel
+     */
+    if( sc->subch[ch].use == BRL1_SUBCH_FREE ) {
+        return SC_NOPEN;
+    }
+
+    type_and_subch = (BRL1_REQUEST | ((u_char)ch));
+    result = brl1_send( sc, msg, len, type_and_subch, wait );
+
+    /* If we sent as much as we asked to, return "ok". */
+    if( result == len )
+	return( SC_SUCCESS );
+
+    /* Or, if we sent less, than either the UART is busy or
+     * we're trying to send too large a packet anyway.
+     */
+    else if( result >= 0 && result < len )
+	return( SC_BUSY );
+
+    /* Or, if something else went wrong (result < 0), then
+     * return that error value.
+     */
+    else
+	return( result );
+}
+
+/* subch_pull_msg pulls a message off the receive queue for subch
+ * and places it the buffer pointed to by msg.  This routine should only
+ * be called when the caller already knows a message is available on the
+ * receive queue (and, in the kernel, only when the subchannel data lock
+ * is held by the caller).
+ */
+static void
+subch_pull_msg( brl1_sch_t *subch, char *msg, int *len )
+{
+    sc_cq_t *q;         /* receive queue */
+    int before_wrap,    /* packet may be split into two different       */
+        after_wrap;     /*   pieces to acommodate queue wraparound      */
+
+    /* pull message off the receive queue */
+    q = subch->iqp;
+
+    cq_rem( q, *len );   /* remove length byte and store */
+    cq_discard( q );     /* remove type/subch byte and discard */
+
+    if ( *len > 0 )
+	(*len)--;        /* don't count type/subch byte in length returned */
+
+    if( (q->opos + (*len)) > BRL1_QSIZE ) {
+        before_wrap = BRL1_QSIZE - q->opos;
+        after_wrap = (*len) - before_wrap;
+    }
+    else {
+        before_wrap = (*len);
+        after_wrap = 0;
+    }
+
+    BCOPY( q->buf + q->opos, msg, before_wrap  );
+    if( after_wrap ) {
+        BCOPY( q->buf, msg + before_wrap, after_wrap  );
+	q->opos = after_wrap;
+    }
+    else {
+	q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1));
+    }
+    atomic_dec(&(subch->packet_arrived));
+}
+
+
+/* sc_recv_poll can be called as a blocking or non-blocking function;
+ * it attempts to pull a message off of the subchannel specified
+ * in the argument list (ch).
+ *
+ * The "block" argument, if non-zero, is interpreted as a timeout
+ * delay (to avoid permanent waiting).
+ */
+
+int
+sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
+{
+    int is_msg = 0;
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    rtc_time_t exp_time = rtc_time() + block;
+
+    /* sanity check-- make sure this is an open subchannel */
+    if( subch->use == BRL1_SUBCH_FREE )
+	return( SC_NOPEN );
+
+    do {
+
+        /* kick the next lower layer and see if it pulls anything in
+         */
+	brl1_receive( sc, SERIAL_POLLED_MODE );
+	is_msg = atomic_read(&subch->packet_arrived);
+
+    } while( block && !is_msg && (rtc_time() < exp_time) );
+
+    if( !is_msg ) {
+	/* no message and we didn't care to wait for one */
+	return( SC_NMSG );
+    }
+
+    SUBCH_DATA_LOCK( subch, pl );
+    subch_pull_msg( subch, msg, len );
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return( SC_SUCCESS );
+}
+    
+
+/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking
+ * or non-blocking mode.  Rather than polling until an appointed timeout,
+ * however, sc_recv_intr sleeps on a syncrhonization variable until a
+ * signal from the lower layer tells us that a packet has arrived.
+ *
+ * sc_recv_intr can't be used with remote (router) L1s.
+ */
+int
+sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
+{
+    int is_msg = 0;
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    do {
+	SUBCH_DATA_LOCK(subch, pl);
+	is_msg = atomic_read(&subch->packet_arrived);
+	if( !is_msg && block ) {
+	    /* wake me when you've got something */
+	    subch->rx_notify = sc_data_ready;
+	    sv_wait( &(subch->arrive_sv), 0, 0);
+	    if( subch->use == BRL1_SUBCH_FREE ) {
+		/* oops-- somebody closed our subchannel while we were
+		 * sleeping!
+		 */
+
+		/* no need to unlock since the channel's closed anyhow */
+		return( SC_NOPEN );
+	    }
+	}
+    } while( !is_msg && block );
+
+    if( !is_msg ) {
+	/* no message and we didn't care to wait for one */
+	SUBCH_DATA_UNLOCK( subch, pl );
+	return( SC_NMSG );
+    }
+
+    subch_pull_msg( subch, msg, len );
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return( SC_SUCCESS );
+}
+
+/* sc_command implements a (blocking) combination of sc_send and sc_recv.
+ * It is intended to be the SN1 equivalent of SN0's "elsc_command", which
+ * issued a system controller command and then waited for a response from
+ * the system controller before returning.
+ *
+ * cmd points to the outgoing command; resp points to the buffer in
+ * which the response is to be stored.  Both buffers are assumed to
+ * be the same length; if there is any doubt as to whether the
+ * response buffer is long enough to hold the L1's response, then
+ * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any
+ * bigger.
+ *
+ * Be careful using the same buffer for both cmd and resp; it could get
+ * hairy if there were ever an L1 command reqeuest that spanned multiple
+ * packets.  (On the other hand, that would require some additional
+ * rewriting of the L1 command interface anyway.)
+ */
+#define __RETRIES	50
+#define __WAIT_SEND	1	// ( sc->uart != BRL1_LOCALHUB_UART )
+#define __WAIT_RECV	10000000
+
+
+int
+sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len )
+{
+    int result;
+    int retries;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+    	return SC_NMSG;
+
+    retries = __RETRIES;
+
+    while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) {
+	if( result == SC_BUSY ) {
+	    retries--;
+	    if( retries <= 0 )
+		return result;
+	    uart_delay(500);
+	}
+	else {
+	    return result;
+	}
+    }
+    
+    /* block on sc_recv_* */
+    if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) {
+	return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) );
+    }
+    else {
+	return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );
+    }
+}
+
+/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command
+ * used in situations where the kernel has a command that shouldn't be
+ * delayed until the send buffer clears.  sc_command should be used instead
+ * under most circumstances.
+ */
+
+int
+sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len )
+{
+    int result;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+    	return SC_NMSG;
+
+    if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) {
+	return result;
+    }
+
+    return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );
+}
+
+
+
+/* sc_poll checks the queue corresponding to the given
+ * subchannel to see if there's anything available.  If
+ * not, it kicks the brl1 layer and then checks again.
+ *
+ * Returns 1 if input is available on the given queue,
+ * 0 otherwise.
+ */
+
+int
+sc_poll( l1sc_t *sc, int ch )
+{
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    if( atomic_read(&subch->packet_arrived) )
+	return 1;
+
+    brl1_receive( sc, SERIAL_POLLED_MODE );
+
+    if( atomic_read(&subch->packet_arrived) )
+	return 1;
+
+    return 0;
+}
+
+/* for now, sc_init just calls brl1_init */
+
+void
+sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    if ( !IS_RUNNING_ON_SIMULATOR() )
+    	brl1_init( sc, nasid, uart );
+}
+
+/* sc_dispatch_env_event handles events sent from the system control
+ * network's environmental monitor tasks.
+ */
+
+#if	defined(LINUX_KERNEL_THREADS)
+
+static void
+sc_dispatch_env_event( uint code, int argc, char *args, int maxlen )
+{
+    int j, i = 0;
+    uint32_t ESPcode;
+
+    switch( code ) {
+	/* for now, all codes do the same thing: grab two arguments
+	 * and print a cmn_err_tag message */
+      default:
+	/* check number of arguments */
+	if( argc != 2 ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected 2 arguments, got %d\n", argc ));
+	    return;
+	}
+	
+	/* get ESP code (integer argument) */
+	if( args[i++] != L1_ARG_INT ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected integer argument\n" ));
+	    return;
+	}
+	/* WARNING: highly endian */
+	COPY_BUFFER_TO_INT(args, i, ESPcode);
+
+	/* verify string argument */
+	if( args[i++] != L1_ARG_ASCII ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected an ASCII string\n" ));
+	    return;
+	}
+	for( j = i; j < maxlen; j++ ) {
+	    if( args[j] == '\0' ) break; /* found string termination */
+	}
+	if( j == maxlen ) {
+	    j--;
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "message too long-- truncating\n" ));
+	}
+
+	/* strip out trailing cr/lf */
+	for( ; 
+	     j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); 
+	     j-- );
+	args[j] = '\0';
+	
+	/* strip out leading cr/lf */
+	for( ;
+	     i < j && ((args[i] == 0xd) || (args[i] == 0xa));
+	     i++ );
+    }
+}
+
+
+/* sc_event waits for events to arrive from the system controller, and
+ * prints appropriate messages to the syslog.
+ */
+
+static void
+sc_event( l1sc_t *sc, int ch )
+{
+    char event[BRL1_QSIZE];
+    int i;
+    int result;
+    int event_len;
+    uint32_t ev_src;
+    uint32_t ev_code;
+    int ev_argc;
+
+    while(1) {
+	
+	bzero( event, BRL1_QSIZE );
+
+	/*
+	 * wait for an event 
+	 */
+	result = sc_recv_intr( sc, ch, event, &event_len, 1 );
+	if( result != SC_SUCCESS ) {
+	    printk(KERN_WARNING  "Error receiving sysctl event on nasid %d\n",
+		     sc->nasid );
+	}
+	else {
+	    /*
+	     * an event arrived; break it down into useful pieces
+	     */
+#if defined(L1_DEBUG) && 0
+	    int ix;
+	    printf( "Event packet received:\n" );
+	    for (ix = 0; ix < 64; ix++) {
+		printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)),
+			(event[ix] & ((uint64_t)0xf)) );
+		if( (ix % 16) == 0xf ) printf( "\n" );
+	    }
+#endif /* L1_DEBUG */
+
+	    i = 0;
+
+	    /* get event source */
+	    COPY_BUFFER_TO_INT(event, i, ev_src);
+	    COPY_BUFFER_TO_INT(event, i, ev_code);
+
+	    /* get arg count */
+	    ev_argc = (event[i++] & 0xffUL);
+	    
+	    /* dispatch events by task */
+	    switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT )
+	    {
+	      case L1_ADDR_TASK_ENV: /* environmental monitor event */
+		sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), 
+				       BRL1_QSIZE - i );
+		break;
+
+	      default: /* unhandled task type */
+		L1_DBG_PRF(( "Unhandled event type received from system "
+			     "controllers: source task %x\n",
+			     (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT
+			   ));
+	    }
+	}
+	
+    }			
+}
+
+/* sc_listen sets up a service thread to listen for incoming events.
+ */
+
+void
+sc_listen( l1sc_t *sc )
+{
+    int result;
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    char        msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         ch;     /* system controller subchannel used */
+
+    extern int msc_shutdown_pri;
+
+    /* grab the designated "event subchannel" */
+    SUBCH_LOCK( sc, pl );
+    subch = &(sc->subch[BRL1_EVENT_SUBCH]);
+    if( subch->use != BRL1_SUBCH_FREE ) {
+	SUBCH_UNLOCK( sc, pl );
+	printk(KERN_WARNING  "sysctl event subchannel in use! "
+		 "Not monitoring sysctl events.\n" );
+	return;
+    }
+    subch->use = BRL1_SUBCH_RSVD;
+    SUBCH_UNLOCK( sc, pl );
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->target = BRL1_LOCALHUB_UART;
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
+    subch->tx_notify = NULL;
+    subch->rx_notify = sc_data_ready;
+    subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
+				   NASID_TO_COMPACT_NODEID(sc->nasid) );
+    ASSERT( subch->iqp );
+    cq_init( subch->iqp );
+
+    /* set up a thread to listen for events */
+    sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri,
+		    KT_PS, (st_func_t *) sc_event,
+		    (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 );
+
+    /* signal the L1 to begin sending events */
+    bzero( msg, BRL1_QSIZE );
+    ch = sc_open( sc, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_EVENT_SUBCH, 2,
+				 L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 )
+    {
+	sc_close( sc, ch );
+	L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len ));
+	goto err_return;
+    }
+
+    result = sc_command_kern( sc, ch, msg, msg, &len );
+    if( result < 0 )
+    {
+	sc_close( sc, ch );
+	L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result ));
+	goto err_return;
+    }
+
+    sc_close( sc, ch );
+
+    result = sc_interpret_resp( msg, 0 );
+    if( result < 0 )
+    {
+	L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result ));
+	goto err_return;
+    }
+
+    /* everything went fine; just return */
+    return;
+	
+err_return:
+    /* there was a problem; complain */
+    printk(KERN_WARNING  "failed to set sysctl event-monitoring subchannel.  "
+	     "Sysctl events will not be monitored.\n" );
+}
+
+#endif	/* LINUX_KERNEL_THREADS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/l1_command.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/l1_command.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/l1_command.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/l1_command.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,1409 @@
+/* $Id: l1_command.c,v 1.2 2002/11/21 17:51:57 jh Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */ 
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+
+#define ELSC_TIMEOUT	1000000		/* ELSC response timeout (usec) */
+#define LOCK_TIMEOUT	5000000		/* Hub lock timeout (usec) */
+
+#define LD(x)		(*(volatile uint64_t *)(x))
+#define SD(x, v)	(LD(x) = (uint64_t) (v))
+
+#define hub_cpu_get()	0
+
+#define LBYTE(caddr)	(*(char *) caddr)
+
+extern char *bcopy(const char * src, char * dest, int count);
+
+#define LDEBUG		0
+
+/*
+ * ELSC data is in NVRAM page 7 at the following offsets.
+ */
+
+#define NVRAM_MAGIC_AD	0x700		/* magic number used for init */
+#define NVRAM_PASS_WD	0x701		/* password (4 bytes in length) */
+#define NVRAM_DBG1	0x705		/* virtual XOR debug switches */
+#define NVRAM_DBG2	0x706		/* physical XOR debug switches */
+#define NVRAM_CFG	0x707		/* ELSC Configuration info */
+#define NVRAM_MODULE	0x708		/* system module number */
+#define NVRAM_BIST_FLG	0x709		/* BIST flags (2 bits per nodeboard) */
+#define NVRAM_PARTITION 0x70a		/* module's partition id */
+#define	NVRAM_DOMAIN	0x70b		/* module's domain id */
+#define	NVRAM_CLUSTER	0x70c		/* module's cluster id */
+#define	NVRAM_CELL	0x70d		/* module's cellid */
+
+#define NVRAM_MAGIC_NO	0x37		/* value of magic number */
+#define NVRAM_SIZE	16		/* 16 bytes in nvram */
+
+/*
+ * Declare a static ELSC NVRAM buffer to hold all data read from
+ * and written to NVRAM.  This nvram "cache" will be used only during the
+ * IP27prom execution.
+ */
+static char elsc_nvram_buffer[NVRAM_SIZE];
+
+#define SC_COMMAND sc_command
+
+/*
+ * elsc_init
+ *
+ *   Initialize ELSC structure
+ */
+
+void elsc_init(elsc_t *e, nasid_t nasid)
+{
+    sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART);
+}
+
+
+/*
+ * elsc_errmsg
+ *
+ *   Given a negative error code,
+ *   returns a corresponding static error string.
+ */
+
+char *elsc_errmsg(int code)
+{
+    switch (code) {
+    case ELSC_ERROR_CMD_SEND:
+	return "Command send error";
+    case ELSC_ERROR_CMD_CHECKSUM:
+	return "Command packet checksum error";
+    case ELSC_ERROR_CMD_UNKNOWN:
+	return "Unknown command";
+    case ELSC_ERROR_CMD_ARGS:
+	return "Invalid command argument(s)";
+    case ELSC_ERROR_CMD_PERM:
+	return "Permission denied";
+    case ELSC_ERROR_RESP_TIMEOUT:
+	return "System controller response timeout";
+    case ELSC_ERROR_RESP_CHECKSUM:
+	return "Response packet checksum error";
+    case ELSC_ERROR_RESP_FORMAT:
+	return "Response format error";
+    case ELSC_ERROR_RESP_DIR:
+	return "Response direction error";
+    case ELSC_ERROR_MSG_LOST:
+	return "Message lost because queue is full";
+    case ELSC_ERROR_LOCK_TIMEOUT:
+	return "Timed out getting ELSC lock";
+    case ELSC_ERROR_DATA_SEND:
+	return "Error sending data";
+    case ELSC_ERROR_NIC:
+	return "NIC protocol error";
+    case ELSC_ERROR_NVMAGIC:
+	return "Bad magic number in NVRAM";
+    case ELSC_ERROR_MODULE:
+	return "Module location protocol error";
+    default:
+	return "Unknown error";
+    }
+}
+
+/*
+ * elsc_nvram_init
+ *
+ *   Initializes reads and writes to NVRAM.  This will perform a single
+ *   read to NVRAM, getting all data at once.  When the PROM tries to
+ *   read NVRAM, it returns the data from the buffer being read.  If the
+ *   PROM tries to write out to NVRAM, the write is done, and the internal
+ *   buffer is updated.
+ */
+
+void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data)
+{
+    /* This might require implementation of multiple-packet request/responses
+     * if it's to provide the same behavior that was available in SN0.
+     */
+    nasid = nasid;
+    elsc_nvram_data = elsc_nvram_data;
+}
+
+/*
+ * elsc_nvram_copy
+ *
+ *   Copies the content of a buffer into the static buffer in this library.
+ */
+
+void elsc_nvram_copy(uchar_t *elsc_nvram_data)
+{
+    memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE);
+}
+
+/*
+ * elsc_nvram_write
+ *
+ *   Copies bytes from 'buf' into NVRAM, starting at NVRAM address
+ *   'addr' which must be between 0 and 2047.
+ *
+ *   If 'len' is non-negative, the routine copies 'len' bytes.
+ *
+ *   If 'len' is negative, the routine treats the data as a string and
+ *   copies bytes up to and including a NUL-terminating zero, but not
+ *   to exceed '-len' bytes.
+ */
+
+int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len)
+{
+    /* Here again, we might need to work out the details of a
+     * multiple-packet protocol.
+     */
+
+    /* For now, pretend it worked. */
+    e = e;
+    addr = addr;
+    buf = buf;
+    return (len < 0 ? -len : len);
+}
+
+/*
+ * elsc_nvram_read
+ *
+ *   Copies bytes from NVRAM into 'buf', starting at NVRAM address
+ *   'addr' which must be between 0 and 2047.
+ *
+ *   If 'len' is non-negative, the routine copies 'len' bytes.
+ *
+ *   If 'len' is negative, the routine treats the data as a string and
+ *   copies bytes up to and including a NUL-terminating zero, but not
+ *   to exceed '-len' bytes.  NOTE:  This method is no longer supported.
+ *   It was never used in the first place.
+ */
+
+int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len)
+{
+    /* multiple packets? */
+    e = e;
+    addr = addr;
+    buf = buf;
+    len = len;
+    return -1;
+}
+
+
+/*
+ * Command Set
+ */
+
+int elsc_version(elsc_t *e, char *result)
+{
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+    int		major,  /* major rev number */
+	        minor,  /* minor rev number */
+                bugfix; /* bugfix rev number */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_FW_REV, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
+			   L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
+	< 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    sprintf( result, "%d.%d.%d", major, minor, bugfix );
+
+    return 0;
+}
+
+int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2)
+{
+    /* shush compiler */
+    e = e;
+    byte1 = byte1;
+    byte2 = byte2;
+
+    /* fill in a buffer with the opcode & params; call sc_command */
+
+    return 0;
+}
+
+int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		dbg_sw; /* holds debug switch settings */
+    int		len;	/* number of msg buffer bytes used */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RDBG, 0 ) ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* copy out debug switch settings (last two bytes of the
+     * integer response)
+     */
+    *byte1 = ((dbg_sw >> 8) & 0xFF);
+    *byte2 = (dbg_sw & 0xFF);
+
+    return 0;
+}
+
+
+/*
+ * elsc_rack_bay_get fills in the two int * arguments with the
+ * rack number and bay number of the L1 being addressed
+ */
+int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay)
+{
+    char msg[BRL1_QSIZE];	/* L1 request/response info */
+    int subch;			/* system controller subchannel used */
+    int len;			/* length of message */
+    uint32_t	buf32;		/* used to copy 32-bit rack/bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRACK, 0 )) < 0 ) 
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+
+    /* send the request to the L1 */
+    if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close(e, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    return 0;
+}
+
+
+/* elsc_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t buf32;	        /* used to copy 32-bit rack & bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRBT, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, 
+			           L1_ARG_INT, brick_type ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    /* convert brick_type to lower case */
+    *brick_type = *brick_type - 'A' + 'a';
+
+    return 0;
+}
+
+
+int elsc_module_get(elsc_t *e)
+{
+    extern char brick_types[];
+    uint rnum, rack, bay, bricktype, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) {
+	return ret;
+    }
+
+    /* report unset location info. with a special, otherwise invalid modid */
+    if (rnum == 0 && bay == 0)
+	return MODULE_NOT_SET;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+	return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;		
+    t = rnum / 100;		/* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;		/* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;		/* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+	if( brick_types[t] == bricktype )
+	    return RBT_TO_MODULE(rack, bay, t);
+    }
+    
+    return ELSC_ERROR_MODULE;
+}
+
+int elsc_partition_set(elsc_t *e, int partition)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PARTITION_SET, 2,
+				 L1_ARG_INT, partition )) < 0 )
+    {
+	
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+    
+    return( 0 );
+}
+
+int elsc_partition_get(elsc_t *e)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t partition_id;    /* used to copy partition id out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PARTITION_GET, 0 )) < 0 )
+
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+    
+    return( partition_id );
+}
+
+
+/*
+ * elsc_cons_subch selects the "active" console subchannel for this node
+ * (i.e., the one that will currently receive input)
+ */
+int elsc_cons_subch(elsc_t *e, uint ch)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( e, L1_ADDR_LOCAL );
+    
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_CONS_SUBCH, 2,
+				 L1_ARG_INT, ch)) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+/*
+ * elsc_cons_node should only be executed by one node.  It declares to
+ * the system controller that the node from which it is called will be
+ * the owner of the system console.
+ */
+int elsc_cons_node(elsc_t *e)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( e, L1_ADDR_LOCAL );
+    
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_CONS_NODE, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+    
+
+/* elsc_display_line writes up to 12 characters to either the top or bottom
+ * line of the L1 display.  line points to a buffer containing the message
+ * to be displayed.  The zero-based line number is specified by lnum (so
+ * lnum == 0 specifies the top line and lnum == 1 specifies the bottom).
+ * Lines longer than 12 characters, or line numbers not less than
+ * L1_DISPLAY_LINES, cause elsc_display_line to return an error.
+ */
+int elsc_display_line(elsc_t *e, char *line, int lnum)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		len;	/* number of msg buffer bytes used */
+
+    /* argument sanity checking */
+    if( !(lnum < L1_DISPLAY_LINES) )
+	return( ELSC_ERROR_CMD_ARGS );
+    if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) )
+	return( ELSC_ERROR_CMD_ARGS );
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 (L1_REQ_DISP1+lnum), 2,
+				 L1_ARG_ASCII, line )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+/* elsc_display_mesg silently drops message characters beyond the 12th.
+ */
+int elsc_display_mesg(elsc_t *e, char *chr)
+{
+
+    char line[L1_DISPLAY_LINE_LENGTH+1];
+    int numlines, i;
+    int result;
+
+    numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) /
+	L1_DISPLAY_LINE_LENGTH;
+
+    if( numlines > L1_DISPLAY_LINES )
+	numlines = L1_DISPLAY_LINES;
+
+    for( i = 0; i < numlines; i++ )
+    {
+	strncpy( line, chr, L1_DISPLAY_LINE_LENGTH );
+	line[L1_DISPLAY_LINE_LENGTH] = '\0';
+
+	/* generally we want to leave the first line of the L1 display
+	 * alone (so the L1 can manipulate it).  If you need to be able
+	 * to display to both lines (for debugging purposes), define
+	 * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES
+	 * to your 'defs file.
+	 */
+#if defined(L1_DISP_2LINES)
+	if( (result = elsc_display_line( e, line, i )) < 0 )
+#else
+	if( (result = elsc_display_line( e, line, i+1 )) < 0 )
+#endif
+
+	    return result;
+
+	chr += L1_DISPLAY_LINE_LENGTH;
+    }
+    
+    return 0;
+}
+
+
+int elsc_password_set(elsc_t *e, char *password)
+{
+    /* shush compiler */
+    e = e;
+    password = password;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+int elsc_password_get(elsc_t *e, char *password)
+{
+    /* shush compiler */
+    e = e;
+    password = password;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+/*
+ * sc_portspeed_get
+ *
+ * retrieve the current portspeed setting for the bedrock II
+ */
+int sc_portspeed_get(l1sc_t *sc)
+{
+    char	msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         subch;  /* system controller subchannel used */
+    int		portspeed_a, portspeed_b;
+			/* ioport clock rates */
+
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+                                 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PORTSPEED,
+				 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+    
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) < 0 )
+    {
+        sc_close( sc, subch );
+        return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, 
+			   L1_ARG_INT, &portspeed_a,
+			   L1_ARG_INT, &portspeed_b ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* for the c-brick, we ignore the portspeed_b value */
+    return (portspeed_a ? 600 : 400);
+}
+
+/*
+ * elsc_power_query
+ *
+ *   To be used after system reset, this command returns 1 if the reset
+ *   was the result of a power-on, 0 otherwise.
+ *
+ *   The power query status is cleared to 0 after it is read.
+ */
+
+int elsc_power_query(elsc_t *e)
+{
+    e = e; /* shush the compiler */
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 1;
+}
+
+int elsc_rpwr_query(elsc_t *e, int is_master)
+{
+    /* shush the compiler */
+    e = e;
+    is_master = is_master;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+} 
+
+/*
+ * elsc_power_down
+ *
+ *   Sets up system to shut down in "sec" seconds (or modifies the
+ *   shutdown time if one is already in effect).  Use 0 to power
+ *   down immediately.
+ */
+
+int elsc_power_down(elsc_t *e, int sec)
+{
+    /* shush compiler */
+    e = e;
+    sec = sec;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+int elsc_system_reset(elsc_t *e)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		len;	/* number of msg buffer bytes used */
+    int		result;
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RESET, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( (result = sc_command( e, subch, msg, msg, &len )) ) {
+	sc_close( e, subch );
+	if( result == SC_NMSG ) {
+	    /* timeout is OK.  We've sent the reset.  Now it's just
+	     * a matter of time...
+	     */
+	    return( 0 );
+	}
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+int elsc_power_cycle(elsc_t *e)
+{
+    /* shush compiler */
+    e = e;
+
+    /* fill in buffer with the opcode & params; call sc_command */
+
+    return 0;
+}
+
+
+int _elsc_hbt(elsc_t *e, int ival, int rdly)
+{
+    e = e;
+    ival = ival;
+    rdly = rdly;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+/* send a command string to an L1 */
+int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay,
+		       char *cmd )
+{
+    char        msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         subch;  /* system controller subchannel used */
+    l1addr_t	target; /* target system controller for command */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+
+    L1_BUILD_ADDR( &target, compt, rack, bay, 0 );
+    subch = sc_open( sc, target );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2,
+				 L1_ARG_ASCII, cmd )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+		   
+    /* send the request to the L1 */
+    if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+    
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+/*
+ * sc_power_down
+ *
+ * Shuts down the c-brick associated with sc, and any attached I/O bricks
+ * or other c-bricks (won't go through r-bricks).
+ */
+
+int sc_power_down(l1sc_t *sc)
+{
+    return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, 
+			      L1_ADDR_BAY_LOCAL, "* pwr d" );
+}
+
+
+/*
+ * sc_power_down_all
+ *
+ * Works similarly to sc_power_down, except that the request is sent to the
+ * closest L2 and EVERYBODY gets turned off.
+ */
+
+int sc_power_down_all(l1sc_t *sc)
+{
+    if( nodepda->num_routers > 0 ) {
+	return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, 
+				  L1_ADDR_BAY_LOCAL, "* pwr d" );
+    }
+    else {
+	return sc_power_down( sc );
+    }
+}
+
+
+/*
+ * iobrick routines
+ */
+
+/* iobrick_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t buf32;	        /* used to copy 32-bit rack & bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRBT, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, 
+			           L1_ARG_INT, brick_type ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    return 0;
+}
+
+
+int iobrick_module_get(l1sc_t *sc)
+{
+    uint rnum, rack, bay, brick_type, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0)
+        return ret;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+        return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;           
+    t = rnum / 100;             /* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;              /* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;              /* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    switch( brick_type ) {
+      case 'I': 
+	brick_type = MODULE_IBRICK; break;
+      case 'P':
+	brick_type = MODULE_PBRICK; break;
+      case 'X':
+	brick_type = MODULE_XBRICK; break;
+    }
+
+    ret = RBT_TO_MODULE(rack, bay, brick_type);
+
+    return ret;
+}
+
+/*
+ * iobrick_module_get_nasid() returns a module_id which has the brick
+ * type encoded in bits 15-12, but this is not the true brick type...
+ * The module_id returned by iobrick_module_get_nasid() is modified
+ * to make a PEBRICKs & PXBRICKs look like a PBRICK.  So this routine
+ * iobrick_type_get_nasid() returns the true unmodified brick type.
+ */
+int
+iobrick_type_get_nasid(nasid_t nasid)
+{
+    l1sc_t *sc = get_elsc();
+    elsc_t tmp_sc;
+    uint rack, bay, type;
+    int t, ret;
+
+#ifdef PIC_LATER
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+        if ((ret = peer_iobrick_type_get(sc, rack, bay, &type)) < 0)
+            return ret;
+    }
+    else
+#endif	/* PIC_LATER */
+    if (nasid != get_nasid()) { /* get the io_moduleid from remote node */
+        elsc_init(&tmp_sc, nasid);
+        if ((ret = iobrick_rack_bay_type_get(&tmp_sc, &rack, &bay, &type)) < 0)
+            return ret;
+    }
+    else {
+        if ((ret = iobrick_rack_bay_type_get(sc, &rack, &bay, &type)) < 0)
+            return ret;
+    }
+
+    /*
+     * Some brick_types need special treatment.  NOTE: This switch is
+     * duplicated in iobrick_module_get(),  so if you change this switch
+     * you must also change it there.
+     */
+    switch (type)
+    {
+    case L1_BRICKTYPE_IP45:
+        /* treat speedo2 like Ibrick for moduleid purposes */
+        type = L1_BRICKTYPE_I;
+        break;
+    case L1_BRICKTYPE_X2:
+        /* give X2 bricks the same moduleid as earlier models */
+        type = L1_BRICKTYPE_X;
+        break;
+    }
+
+    /* convert brick_type to lower case */
+    if ((type >= 'A') && (type <= 'Z'))
+        type = type - 'A' + 'a';
+
+    /* convert to a module.h brick type */
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+        if( brick_types[t] == type )
+            return t;
+    }
+
+    return -1;    /* unknown brick */
+}
+
+int iobrick_module_get_nasid(nasid_t nasid)
+{
+    int io_moduleid;
+    l1sc_t *sc = get_elsc();
+    elsc_t tmp_sc;
+
+#ifdef PIC_LATER
+    uint rack, bay;
+
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+
+        io_moduleid = peer_iobrick_module_get(sc, rack, bay);
+    }
+    else
+#endif	/* PIC_LATER */
+    if (nasid != get_nasid()) { /* get the io_moduleid from remote node */
+        elsc_init(&tmp_sc, nasid);
+
+        io_moduleid = iobrick_module_get(&tmp_sc);
+    }
+    else {
+        io_moduleid = iobrick_module_get(sc);
+    }
+
+    return io_moduleid;
+}
+
+
+/* iobrick_get_sys_snum asks the attached iobrick for the system
+ * serial number.  This function will only be relevant to the master
+ * cbrick (the one attached to the bootmaster ibrick); other nodes
+ * may call the function, but the value returned to the master node
+ * will be the one used as the system serial number by the kernel.
+ */
+
+int
+iobrick_get_sys_snum( l1sc_t *sc, char *snum_str )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SYS_SERIAL, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) );
+}
+
+
+/*
+ * The following functions apply (or cut off) power to the specified
+ * pci bus or slot.
+ */
+
+int
+iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code )
+{
+#if 0 /* The "bedrock request" method of performing this function
+       * seems to be broken in the L1, so for now use the command-
+       * interpreter method
+       */
+
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCALIO );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 req_code, 4,
+				 L1_ARG_INT, bus,
+				 L1_ARG_INT, slot )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+
+#else
+    char cmd[64];
+    char *fxn;
+
+    switch( req_code )
+    {
+    case L1_REQ_PCI_UP:
+	fxn = "u";
+	break;
+    case L1_REQ_PCI_DOWN:
+	fxn = "d";
+	break;
+    case L1_REQ_PCI_RESET:
+	fxn = "rst";
+	break;
+    default:
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    if( slot == -1 ) 
+	sprintf( cmd, "pci %d %s", bus, fxn );
+    else
+        sprintf( cmd, "pci %d %d %s", bus, slot, fxn );
+	
+    return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK,
+	L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd );
+#endif
+}
+				 
+int
+iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up )
+{
+    return iobrick_pci_pwr( sc, bus, slot, up );
+}
+
+int
+iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up )
+{
+    return iobrick_pci_pwr( sc, bus, -1, up );
+}
+
+
+int
+iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot )
+{
+    return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET );
+}
+
+int
+iobrick_pci_bus_rst( l1sc_t *sc, int bus )
+{
+    return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET );
+}
+
+
+/* get the L1 firmware version for an iobrick */
+int
+iobrick_sc_version( l1sc_t *sc, char *result )
+{
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+    int		major,  /* major rev number */
+	        minor,  /* minor rev number */
+                bugfix; /* bugfix rev number */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCALIO );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_FW_REV, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
+			   L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
+	< 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    sprintf( result, "%d.%d.%d", major, minor, bugfix );
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/mem_refcnt.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/mem_refcnt.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/mem_refcnt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/mem_refcnt.c	2003-05-22 22:06:39.000000000 +0000
@@ -7,7 +7,6 @@
  * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/sgi.h>
@@ -43,7 +42,7 @@
 int
 mem_refcnt_attach(devfs_handle_t hub)
 {
-#ifndef CONFIG_IA64_SGI_SN
+#if 0
         devfs_handle_t refcnt_dev;
         
         hwgraph_char_device_add(hub,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/ml_SN_init.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/ml_SN_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/ml_SN_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/ml_SN_init.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,211 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/snconfig.h>
+
+extern int numcpus;
+extern char arg_maxnodes[];
+extern cpuid_t master_procid;
+extern synergy_da_t    *Synergy_da_indr[];
+
+extern int hasmetarouter;
+
+int		maxcpus;
+cpumask_t	boot_cpumask;
+hubreg_t	region_mask = 0;
+
+
+extern xwidgetnum_t hub_widget_id(nasid_t);
+
+extern int valid_icache_reasons;	/* Reasons to flush the icache */
+extern int valid_dcache_reasons;	/* Reasons to flush the dcache */
+extern u_char miniroot;
+extern volatile int	need_utlbmiss_patch;
+extern void iograph_early_init(void);
+
+nasid_t master_nasid = INVALID_NASID;
+
+
+/*
+ * mlreset(int slave)
+ * 	very early machine reset - at this point NO interrupts have been
+ * 	enabled; nor is memory, tlb, p0, etc setup.
+ *
+ * 	slave is zero when mlreset is called for the master processor and
+ *	is nonzero thereafter.
+ */
+
+
+void
+mlreset(int slave)
+{
+	if (!slave) {
+		/*
+		 * We are the master cpu and node.
+		 */ 
+		master_nasid = get_nasid();
+		set_master_bridge_base();
+
+		/* We're the master processor */
+		master_procid = smp_processor_id();
+		master_nasid = cpuid_to_nasid(master_procid);
+
+		/*
+		 * master_nasid we get back better be same as one from
+		 * get_nasid()
+		 */
+		ASSERT_ALWAYS(master_nasid == get_nasid());
+
+		/* early initialization of iograph */
+		iograph_early_init();
+
+		/* Initialize Hub Pseudodriver Management */
+		hubdev_init();
+
+	} else { /* slave != 0 */
+		/*
+		 * This code is performed ONLY by slave processors.
+		 */
+
+	}
+}
+
+
+/* XXX - Move the meat of this to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the nodepda.
+ */
+void init_platform_nodepda(nodepda_t *npda, cnodeid_t node)
+{
+	hubinfo_t hubinfo;
+	int	  sn;
+
+	extern void router_map_init(nodepda_t *);
+	extern void router_queue_init(nodepda_t *,cnodeid_t);
+	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
+
+	/* Allocate per-node platform-dependent data */
+	hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s));
+
+	npda->pdinfo = (void *)hubinfo;
+	hubinfo->h_nodepda = npda;
+	hubinfo->h_cnodeid = node;
+	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
+
+	spin_lock_init(&hubinfo->h_crblock);
+
+	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
+	npda->xbow_peer = INVALID_NASID;
+
+	/* 
+	 * Initialize the linked list of
+	 * router info pointers to the dependent routers
+	 */
+	npda->npda_rip_first = NULL;
+
+	/*
+	 * npda_rip_last always points to the place
+	 * where the next element is to be inserted
+	 * into the list 
+	 */
+	npda->npda_rip_last = &npda->npda_rip_first;
+	npda->module_id = INVALID_MODULE;
+
+	/*
+	* Initialize the interrupts.
+	* On sn2, this is done at pci init time,
+	* because sn2 needs the cpus checked in
+	* when it initializes interrupts.  This is
+	* so we don't see all the nodes as headless.
+	*/
+	for (sn=0; sn<NUM_SUBNODES; sn++) {
+		intr_init_vecblk(npda, node, sn);
+	}
+
+	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
+}
+
+/* XXX - Move the interrupt stuff to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the processor pda.
+ * Must be done _after_ init_platform_nodepda().
+ * If we need a lock here, something else is wrong!
+ */
+void init_platform_pda(cpuid_t cpu)
+{
+	hub_intmasks_t *intmasks;
+	int i, subnode;
+	cnodeid_t	cnode;
+	synergy_da_t	*sda;
+	int	which_synergy;
+
+
+	cnode = cpuid_to_cnodeid(cpu);
+	which_synergy = cpuid_to_synergy(cpu);
+
+	sda = Synergy_da_indr[(cnode * 2) + which_synergy];
+	intmasks = &sda->s_intmasks;
+
+	/* Clear INT_PEND0 masks. */
+	for (i = 0; i < N_INTPEND0_MASKS; i++)
+		intmasks->intpend0_masks[i] = 0;
+
+	/* Set up pointer to the vector block in the nodepda. */
+	/* (Cant use SUBNODEPDA - not working yet) */
+	subnode = cpuid_to_subnode(cpu);
+	intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0;
+	intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1;
+	if (intmasks->dispatch0 !=  &SUBNODEPDA(cnode, subnode)->intr_dispatch0 ||
+	   intmasks->dispatch1 !=  &SUBNODEPDA(cnode, subnode)->intr_dispatch1)
+	   	panic("xxx");
+	intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0;
+	intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1;
+
+	/* Clear INT_PEND1 masks. */
+	for (i = 0; i < N_INTPEND1_MASKS; i++)
+		intmasks->intpend1_masks[i] = 0;
+}
+
+void
+update_node_information(cnodeid_t cnodeid)
+{
+	nodepda_t *npda = NODEPDA(cnodeid);
+	nodepda_router_info_t *npda_rip;
+	
+	/* Go through the list of router info 
+	 * structures and copy some frequently
+	 * accessed info from the info hanging
+	 * off the corresponding router vertices
+	 */
+	npda_rip = npda->npda_rip_first;
+	while(npda_rip) {
+		if (npda_rip->router_infop) {
+			npda_rip->router_portmask = 
+				npda_rip->router_infop->ri_portmask;
+			npda_rip->router_slot = 
+				npda_rip->router_infop->ri_slotnum;
+		} else {
+			/* No router, no ports. */
+			npda_rip->router_portmask = 0;
+		}
+		npda_rip = npda_rip->router_next;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/ml_iograph.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/ml_iograph.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/ml_iograph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/ml_iograph.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,1505 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+
+/* #define IOGRAPH_DEBUG */
+#ifdef IOGRAPH_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* IOGRAPH_DEBUG */
+
+/* #define PROBE_TEST */
+
+/* At most 2 hubs can be connected to an xswitch */
+#define NUM_XSWITCH_VOLUNTEER 2
+
+/*
+ * Track which hubs have volunteered to manage devices hanging off of
+ * a Crosstalk Switch (e.g. xbow).  This structure is allocated,
+ * initialized, and hung off the xswitch vertex early on when the
+ * xswitch vertex is created.
+ */
+typedef struct xswitch_vol_s {
+	mutex_t xswitch_volunteer_mutex;
+	int		xswitch_volunteer_count;
+	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
+} *xswitch_vol_t;
+
+void
+xswitch_vertex_init(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+
+	xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
+	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
+	xvolinfo->xswitch_volunteer_count = 0;
+	rc = hwgraph_info_add_LBL(xswitch, 
+			INFO_LBL_XSWITCH_VOL,
+			(arbitrary_info_t)xvolinfo);
+	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
+}
+
+
+/*
+ * When assignment of hubs to widgets is complete, we no longer need the
+ * xswitch volunteer structure hanging around.  Destroy it.
+ */
+static void
+xswitch_volunteer_delete(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+
+	rc = hwgraph_info_remove_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL,
+				(arbitrary_info_t *)&xvolinfo);
+	kfree(xvolinfo);
+}
+/*
+ * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
+ */
+/* ARGSUSED */
+static void
+volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
+{
+	xswitch_vol_t xvolinfo = NULL;
+	devfs_handle_t hubv;
+	hubinfo_t hubinfo;
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    return;
+	}
+
+	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
+	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
+	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
+	xvolinfo->xswitch_volunteer_count++;
+
+	/*
+	 * if dual ported, make the lowest widgetid always be 
+	 * xswitch_volunteer[0].
+	 */
+	if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		hubinfo_get(hubv, &hubinfo);
+		if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
+			xvolinfo->xswitch_volunteer[0] = 
+						xvolinfo->xswitch_volunteer[1];
+			xvolinfo->xswitch_volunteer[1] = hubv;
+		}
+	}
+	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
+}
+
+extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
+
+/*
+ * Assign all the xwidgets hanging off the specified xswitch to the
+ * Crosstalk masters that have volunteered for xswitch duty.
+ */
+/* ARGSUSED */
+static void
+assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
+{
+	xswitch_info_t xswitch_info;
+	xswitch_vol_t xvolinfo = NULL;
+	xwidgetnum_t widgetnum;
+	int num_volunteer;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+	extern int iobrick_type_get_nasid(nasid_t);
+
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	
+	xswitch_info = xswitch_info_get(xswitch);
+	ASSERT(xswitch_info != NULL);
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    return;
+	}
+
+	num_volunteer = xvolinfo->xswitch_volunteer_count;
+	ASSERT(num_volunteer > 0);
+
+	/* Assign master hub for xswitch itself.  */
+	if (HUB_WIDGET_ID_MIN > 0) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
+	}
+
+	/*
+	 * TBD: Use administrative information to alter assignment of
+	 * widgets to hubs.
+	 */
+	for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		int i;
+
+		/*
+		 * Ignore disabled/empty ports.
+		 */
+		if (!xbow_port_io_enabled(nasid, widgetnum)) 
+		    continue;
+
+		/*
+		 * If this is the master IO board, assign it to the same 
+		 * hub that owned it in the prom.
+		 */
+		if (is_master_nasid_widget(nasid, widgetnum)) {
+			for (i=0; i<num_volunteer; i++) {
+				hubv = xvolinfo->xswitch_volunteer[i];
+				hubinfo_get(hubv, &hubinfo);
+				nasid = hubinfo->h_nasid;
+				if (nasid == get_console_nasid())
+					goto do_assignment;
+			}
+		}
+
+		/*
+		 * Assuming that we're dual-hosted and that PCI cards 
+		 * are naturally placed left-to-right, alternate PCI 
+		 * buses across both Cbricks.   For Pbricks, and Ibricks,
+                 * io_brick_map_widget() returns the PCI bus number
+                 * associated with the given brick type and widget number.
+                 * For Xbricks, it returns the XIO slot number.
+		 */
+
+		i = 0;
+		if (num_volunteer > 1) {
+                        int	       bt;
+
+                       	bt = iobrick_type_get_nasid(nasid);
+                        if (bt >= 0) {
+				/*
+				 * PXBRICK has two busses per widget so this
+				 * algorithm wouldn't work (all busses would
+				 * be assigned to one volunteer). Change the
+				 * bricktype to PBRICK whose mapping is setup
+				 * suchthat 2 of the PICs will be assigned to
+				 * one volunteer and the other one will be
+				 * assigned to the other volunteer.
+				 */
+				if (bt == MODULE_PXBRICK) 
+					bt = MODULE_PBRICK;
+
+			        i = io_brick_map_widget(bt, widgetnum) & 1;
+                        }
+                }
+
+		hubv = xvolinfo->xswitch_volunteer[i];
+
+do_assignment:
+		/*
+		 * At this point, we want to make hubv the master of widgetnum.
+		 */
+		xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
+	}
+
+	xswitch_volunteer_delete(xswitch);
+}
+
+/*
+ * Early iograph initialization.  Called by master CPU in mlreset().
+ * Useful for including iograph.o in kernel.o.
+ */
+void
+iograph_early_init(void)
+{
+/*
+ * Need new way to get this information ..
+ */
+	cnodeid_t cnode;
+	nasid_t nasid;
+	lboard_t *board;
+	
+	/*
+	 * Init. the board-to-hwgraph link early, so FRU analyzer
+	 * doesn't trip on leftover values if we panic early on.
+	 */
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		DBG("iograph_early_init: Found board 0x%p\n", board);
+
+		/* Check out all the board info stored on a node */
+		while(board) {
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+			board = KLCF_NEXT(board);
+			DBG("iograph_early_init: Found board 0x%p\n", board);
+		}
+	}
+
+	hubio_init();
+}
+
+/*
+ * Let boot processor know that we're done initializing our node's IO
+ * and then exit.
+ */
+/* ARGSUSED */
+static void
+io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
+{
+	/* Let boot processor know that we're done. */
+}
+
+/* 
+ * Probe to see if this hub's xtalk link is active.  If so,
+ * return the Crosstalk Identification of the widget that we talk to.  
+ * This is called before any of the Crosstalk infrastructure for 
+ * this hub is set up.  It's usually called on the node that we're
+ * probing, but not always.
+ *
+ * TBD: Prom code should actually do this work, and pass through 
+ * hwid for our use.
+ */
+static void
+early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
+{
+	hubreg_t llp_csr_reg;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+
+	llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
+	/* 
+	 * If link is up, read the widget's part number.
+	 * A direct connect widget must respond to widgetnum=0.
+	 */
+	if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
+		/* TBD: Put hub into "indirect" mode */
+		/*
+		 * We're able to read from a widget because our hub's 
+		 * WIDGET_ID was set up earlier.
+		 */
+		widgetreg_t widget_id = *(volatile widgetreg_t *)
+			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
+
+		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
+		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
+
+		hwid->part_num = XWIDGET_PART_NUM(widget_id);
+		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
+
+		/* TBD: link reset */
+	} else {
+
+		hwid->part_num = XWIDGET_PART_NUM_NONE;
+		hwid->rev_num = XWIDGET_REV_NUM_NONE;
+		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
+	}
+}
+
+/* Add inventory information to the widget vertex 
+ * Right now (module,slot,revision) is being
+ * added as inventory information.
+ */
+static void
+xwidget_inventory_add(devfs_handle_t 		widgetv,
+		      lboard_t 			*board,
+		      struct xwidget_hwid_s 	hwid)
+{
+	if (!board)
+		return;
+	/* Donot add inventory information for the baseio
+	 * on a speedo with an xbox. It has already been
+	 * taken care of in SN00_vmc.
+	 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
+	 */
+	device_inventory_add(widgetv,INV_IOBD,board->brd_type,
+			     board->brd_module,
+			     SLOTNUM_GETSLOT(board->brd_slot),
+			     hwid.rev_num);
+}
+
+/*
+ * io_xswitch_widget_init
+ *	
+ */
+
+void
+io_xswitch_widget_init(devfs_handle_t  	xswitchv,
+		       devfs_handle_t	hubv,
+		       xwidgetnum_t	widgetnum,
+		       async_attach_t	aa)
+{
+	xswitch_info_t		xswitch_info;
+	xwidgetnum_t		hub_widgetid;
+	devfs_handle_t		widgetv;
+	cnodeid_t		cnode;
+	widgetreg_t		widget_id;
+	nasid_t			nasid, peer_nasid;
+	struct xwidget_hwid_s 	hwid;
+	hubinfo_t		hubinfo;
+	/*REFERENCED*/
+	int			rc;
+	char 			pathname[128];
+	char			new_name[64];
+	moduleid_t		module;
+	slotid_t		slot;
+	lboard_t		*board = NULL;
+	char			buffer[16];
+	slotid_t get_widget_slotnum(int xbow, int widget);
+	
+	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
+
+	/*
+	 * Verify that xswitchv is indeed an attached xswitch.
+	 */
+	xswitch_info = xswitch_info_get(xswitchv);
+	ASSERT(xswitch_info != NULL);
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+	hub_widgetid = hubinfo->h_widgetid;
+
+	/*
+	 * Check that the widget is an io widget and is enabled
+	 * on this nasid or the `peer' nasid.  The peer nasid
+	 * is the other hub/bedrock connected to the xbow.
+	 */
+	peer_nasid = NODEPDA(cnode)->xbow_peer;
+	if (peer_nasid == INVALID_NASID)
+		/* If I don't have a peer, use myself. */
+		peer_nasid = nasid;
+	if (!xbow_port_io_enabled(nasid, widgetnum) &&
+	    !xbow_port_io_enabled(peer_nasid, widgetnum)) {
+		return;
+	}
+
+	if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
+		char			name[4];
+
+		/*
+		 * If the current hub is not supposed to be the master 
+		 * for this widgetnum, then skip this widget.
+		 */
+		if (xswitch_info_master_assignment_get(xswitch_info,
+						       widgetnum) != hubv) {
+			return;
+		}
+
+		module  = NODEPDA(cnode)->module_id;
+#ifdef XBRIDGE_REGS_SIM
+		/* hardwire for now...could do this with something like:
+		 * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl);
+		 * xbow_t xbow = soft->base;
+		 * xbowreg_t xwidget_id = xbow->xb_wid_id;
+		 * but I don't feel like figuring out vhdl right now..
+		 * and I know for a fact the answer is 0x2d000049 
+		 */
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+		DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
+		if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM)
+#else
+		if (nasid_has_xbridge(nasid))
+#endif /* XBRIDGE_REGS_SIM */
+		{
+			board = find_lboard_module_class(
+				(lboard_t *)KL_CONFIG_INFO(nasid),
+				module,
+				KLTYPE_IOBRICK);
+
+DBG("io_xswitch_widget_init: Board 0x%p\n", board);
+{
+		lboard_t dummy;
+
+
+			if (board) {
+				DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+			} else {
+				DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
+				board = &dummy;
+			}
+				
+}
+
+			/*
+	 		 * Make sure we really want to say xbrick, pbrick,
+			 * etc. rather than XIO, graphics, etc.
+	 		 */
+
+#ifdef SUPPORT_PRINTING_M_FORMAT
+			sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+				"%cbrick" "/%s/%d",
+				NODEPDA(cnode)->module_id,
+				
+#else
+			memset(buffer, 0, 16);
+			format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+			sprintf(pathname, EDGE_LBL_MODULE "/%s/"
+				"%cbrick" "/%s/%d",
+				buffer,
+#endif
+
+				(board->brd_type == KLTYPE_IBRICK) ? 'I' :
+				(board->brd_type == KLTYPE_PBRICK) ? 'P' :
+				(board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
+				EDGE_LBL_XTALK, widgetnum);
+		} 
+		
+		DBG("io_xswitch_widget_init: path= %s\n", pathname);
+		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+		
+		ASSERT(rc == GRAPH_SUCCESS);
+
+		/* This is needed to let the user programs to map the
+		 * module,slot numbers to the corresponding widget numbers
+		 * on the crossbow.
+		 */
+		rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+
+		/* If we are looking at the global master io6
+		 * then add information about the version of
+		 * the io6prom as a part of "detailed inventory"
+		 * information.
+		 */
+		if (is_master_baseio(nasid,
+				     NODEPDA(cnode)->module_id,
+ 				     get_widget_slotnum(0,widgetnum))) {
+			extern void klhwg_baseio_inventory_add(devfs_handle_t,
+							       cnodeid_t);
+			module 	= NODEPDA(cnode)->module_id;
+
+#ifdef XBRIDGE_REGS_SIM
+			DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+			if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM)
+#else
+			if (nasid_has_xbridge(nasid))
+#endif /* XBRIDGE_REGS_SIM */
+			{
+				board = find_lboard_module(
+					(lboard_t *)KL_CONFIG_INFO(nasid),
+					module);
+				/*
+				 * Change iobrick to correct i/o brick
+				 */
+#ifdef SUPPORT_PRINTING_M_FORMAT
+				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+#else
+				sprintf(pathname, EDGE_LBL_MODULE "/%x/"
+#endif
+					"iobrick" "/%s/%d",
+					NODEPDA(cnode)->module_id,
+					EDGE_LBL_XTALK, widgetnum);
+			} else {
+				slot = get_widget_slotnum(0, widgetnum);
+				board = get_board_name(nasid, module, slot,
+								new_name);
+				/*
+			 	 * Create the vertex for the widget, 
+				 * using the decimal 
+			 	 * widgetnum as the name of the primary edge.
+			 	 */
+#ifdef SUPPORT_PRINTING_M_FORMAT
+				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+                                                EDGE_LBL_SLOT "/%s",
+                                        NODEPDA(cnode)->module_id,
+                                        new_name);
+#else
+				memset(buffer, 0, 16);
+				format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+				sprintf(pathname, EDGE_LBL_MODULE "/%s/"
+					  	EDGE_LBL_SLOT "/%s",
+					buffer,
+					new_name);
+#endif
+			}
+
+			rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+			DBG("io_xswitch_widget_init: (2) path= %s\n", pathname);
+		        /*
+		         * This is a weird ass code needed for error injection
+		         * purposes.
+		         */
+		        rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+			
+			klhwg_baseio_inventory_add(widgetv,cnode);
+		}
+		sprintf(name, "%d", widgetnum);
+		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
+		rc = hwgraph_edge_add(xswitchv, widgetv, name);
+		
+		/*
+		 * crosstalk switch code tracks which
+		 * widget is attached to each link.
+		 */
+		xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
+		
+		/*
+		 * Peek at the widget to get its crosstalk part and
+		 * mfgr numbers, then present it to the generic xtalk
+		 * bus provider to have its driver attach routine
+		 * called (or not).
+		 */
+#ifdef XBRIDGE_REGS_SIM
+		widget_id = 0x2d000049;
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
+#else
+		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
+#endif /* XBRIDGE_REGS_SIM */
+		hwid.part_num = XWIDGET_PART_NUM(widget_id);
+		hwid.rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
+		/* Store some inventory information about
+		 * the xwidget in the hardware graph.
+		 */
+		xwidget_inventory_add(widgetv,board,hwid);
+		
+		(void)xwidget_register(&hwid, widgetv, widgetnum,
+				       hubv, hub_widgetid,
+				       aa);
+
+#ifdef	SN0_USE_BTE
+		bte_bpush_war(cnode, (void *)board);
+#endif
+	}
+}
+
+
+static void
+io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
+{
+	xwidgetnum_t		widgetnum;
+	async_attach_t          aa;
+
+	aa = async_attach_new();
+	
+	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
+	     widgetnum++) {
+		io_xswitch_widget_init(xswitchv,
+				       cnodeid_to_vertex(cnode),
+				       widgetnum, aa);
+	}
+	/* 
+	 * Wait for parallel attach threads, if any, to complete.
+	 */
+	async_attach_waitall(aa);
+	async_attach_free(aa);
+}
+
+/*
+ * For each PCI bridge connected to the xswitch, add a link from the
+ * board's klconfig info to the bridge's hwgraph vertex.  This lets
+ * the FRU analyzer find the bridge without traversing the hardware
+ * graph and risking hangs.
+ */
+static void
+io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
+{
+	xwidgetnum_t		widgetnum;
+	char 			pathname[128];
+	devfs_handle_t		vhdl;
+	nasid_t			nasid, peer_nasid;
+	lboard_t		*board;
+
+
+
+	/* And its connected hub's nasids */
+	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
+	peer_nasid = NODEPDA(cnodeid)->xbow_peer;
+
+	/* 
+	 * Look for paths matching "<widgetnum>/pci" under xswitchv.
+	 * For every widget, init. its lboard's hwgraph link.  If the
+	 * board has a PCI bridge, point the link to it.
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
+		 widgetnum++) {
+		sprintf(pathname, "%d", widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
+		    GRAPH_SUCCESS)
+			continue;
+
+		board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
+				NODEPDA(cnodeid)->module_id);
+		if (board == NULL && peer_nasid != INVALID_NASID) {
+			/*
+			 * Try to find the board on our peer
+			 */
+			board = find_lboard_module(
+				(lboard_t *)KL_CONFIG_INFO(peer_nasid),
+				NODEPDA(cnodeid)->module_id);
+		}
+		if (board == NULL) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+			printk(KERN_WARNING  "Could not find PROM info for vertex %v, "
+				"FRU analyzer may fail",
+				vhdl);
+#else
+			printk(KERN_WARNING  "Could not find PROM info for vertex 0x%p, "
+				"FRU analyzer may fail",
+				(void *)vhdl);
+#endif
+			return;
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) == 
+		    GRAPH_SUCCESS)
+			board->brd_graph_link = vhdl;
+		else
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+	}
+}
+
+/*
+ * Initialize all I/O on the specified node.
+ */
+static void
+io_init_node(cnodeid_t cnodeid)
+{
+	/*REFERENCED*/
+	devfs_handle_t hubv, switchv, widgetv;
+	struct xwidget_hwid_s hwid;
+	hubinfo_t hubinfo;
+	int is_xswitch;
+	nodepda_t	*npdap;
+	struct semaphore *peer_sema = 0;
+	uint32_t	widget_partnum;
+	nodepda_router_info_t *npda_rip;
+	cpu_cookie_t	c = 0;
+	extern int hubdev_docallouts(devfs_handle_t);
+
+#ifdef LATER
+	/* Try to execute on the node that we're initializing. */
+	c = setnoderun(cnodeid);
+#endif
+	npdap = NODEPDA(cnodeid);
+
+	/*
+	 * Get the "top" vertex for this node's hardware
+	 * graph; it will carry the per-hub hub-specific
+	 * data, and act as the crosstalk provider master.
+	 * It's canonical path is probably something of the
+	 * form /hw/module/%M/slot/%d/node
+	 */
+	hubv = cnodeid_to_vertex(cnodeid);
+	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
+
+	ASSERT(hubv != GRAPH_VERTEX_NONE);
+
+	hubdev_docallouts(hubv);
+
+	/*
+	 * Set up the dependent routers if we have any.
+	 */
+	npda_rip = npdap->npda_rip_first;
+
+	while(npda_rip) {
+		/* If the router info has not been initialized
+		 * then we need to do the router initialization
+		 */
+		if (!npda_rip->router_infop) {
+			router_init(cnodeid,0,npda_rip);
+		}
+		npda_rip = npda_rip->router_next;
+	}
+
+	/*
+	 * Read mfg info on this hub
+	 */
+
+	/* 
+	 * If nothing connected to this hub's xtalk port, we're done.
+	 */
+	early_probe_for_widget(hubv, &hwid);
+	if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
+#ifdef PROBE_TEST
+		if ((cnodeid == 1) || (cnodeid == 2)) {
+			int index;
+
+			for (index = 0; index < 600; index++)
+				DBG("Interfering with device probing!!!\n");
+		}
+#endif
+		/* io_init_done takes cpu cookie as 2nd argument 
+		 * to do a restorenoderun for the setnoderun done 
+		 * at the start of this thread 
+		 */
+		
+		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
+		return;
+		/* NOTREACHED */
+	}
+
+	/* 
+	 * attach our hub_provider information to hubv,
+	 * so we can use it as a crosstalk provider "master"
+	 * vertex.
+	 */
+	xtalk_provider_register(hubv, &hub_provider);
+	xtalk_provider_startup(hubv);
+
+	/*
+	 * Create a vertex to represent the crosstalk bus
+	 * attached to this hub, and a vertex to be used
+	 * as the connect point for whatever is out there
+	 * on the other side of our crosstalk connection.
+	 *
+	 * Crosstalk Switch drivers "climb up" from their
+	 * connection point to try and take over the switch
+	 * point.
+	 *
+	 * Of course, the edges and verticies may already
+	 * exist, in which case our net effect is just to
+	 * associate the "xtalk_" driver with the connection
+	 * point for the device.
+	 */
+
+	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
+
+	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
+
+	ASSERT(switchv != GRAPH_VERTEX_NONE);
+
+	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
+
+	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
+
+	/*
+	 * We need to find the widget id and update the basew_id field
+	 * accordingly. In particular, SN00 has direct connected bridge,
+	 * and hence widget id is Not 0.
+	 */
+
+	widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+
+	if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
+				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
+
+	} else if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == XXBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
+		/* 
+		 * Xbow control register does not have the widget ID field.
+		 * So, hard code the widget ID to be zero.
+		 */
+		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
+		npdap->basew_id = 0;
+
+	} else {
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
+
+		/*NOTREACHED*/
+	}
+	{
+		char widname[10];
+		sprintf(widname, "%x", npdap->basew_id);
+		(void)hwgraph_path_add(switchv, widname, &widgetv);
+		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
+		ASSERT(widgetv != GRAPH_VERTEX_NONE);
+	}
+	
+	nodepda->basew_xc = widgetv;
+
+	is_xswitch = xwidget_hwid_is_xswitch(&hwid);
+
+	/* 
+	 * Try to become the master of the widget.  If this is an xswitch
+	 * with multiple hubs connected, only one will succeed.  Mastership
+	 * of an xswitch is used only when touching registers on that xswitch.
+	 * The slave xwidgets connected to the xswitch can be owned by various
+	 * masters.
+	 */
+	if (device_master_set(widgetv, hubv) == 0) {
+
+		/* Only one hub (thread) per Crosstalk device or switch makes
+		 * it to here.
+		 */
+
+		/* 
+		 * Initialize whatever xwidget is hanging off our hub.
+		 * Whatever it is, it's accessible through widgetnum 0.
+		 */
+		hubinfo_get(hubv, &hubinfo);
+
+		(void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
+
+		if (!is_xswitch) {
+			/* io_init_done takes cpu cookie as 2nd argument 
+			 * to do a restorenoderun for the setnoderun done 
+			 * at the start of this thread 
+			 */
+			io_init_done(cnodeid,c);
+			/* NOTREACHED */
+		}
+
+		/* 
+		 * Special handling for Crosstalk Switches (e.g. xbow).
+		 * We need to do things in roughly the following order:
+		 *	1) Initialize xswitch hardware (done above)
+		 *	2) Determine which hubs are available to be widget masters
+		 *	3) Discover which links are active from the xswitch
+		 *	4) Assign xwidgets hanging off the xswitch to hubs
+		 *	5) Initialize all xwidgets on the xswitch
+		 */
+
+		volunteer_for_widgets(switchv, hubv);
+
+		/* If there's someone else on this crossbow, recognize him */
+		if (npdap->xbow_peer != INVALID_NASID) {
+			nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
+			peer_sema = &peer_npdap->xbow_sema;
+			volunteer_for_widgets(switchv, peer_npdap->node_vertex);
+		}
+
+		assign_widgets_to_volunteers(switchv, hubv);
+
+		/* Signal that we're done */
+		if (peer_sema) {
+			mutex_unlock(peer_sema);
+		}
+		
+	}
+	else {
+	    /* Wait 'til master is done assigning widgets. */
+	    mutex_lock(&npdap->xbow_sema);
+	}
+
+#ifdef PROBE_TEST
+	if ((cnodeid == 1) || (cnodeid == 2)) {
+		int index;
+
+		for (index = 0; index < 500; index++)
+			DBG("Interfering with device probing!!!\n");
+	}
+#endif
+	/* Now both nodes can safely inititialize widgets */
+	io_init_xswitch_widgets(switchv, cnodeid);
+	io_link_xswitch_widgets(switchv, cnodeid);
+
+	/* io_init_done takes cpu cookie as 2nd argument 
+	 * to do a restorenoderun for the setnoderun done 
+	 * at the start of this thread 
+	 */
+	io_init_done(cnodeid,c);
+
+	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
+}
+
+
+#define IOINIT_STKSZ	(16 * 1024)
+
+#define __DEVSTR1 	"/../.master/"
+#define __DEVSTR2 	"/target/"
+#define __DEVSTR3 	"/lun/0/disk/partition/"
+#define	__DEVSTR4	"/../ef"
+
+/*
+ * Currently, we need to allow for 5 IBrick slots with 1 FC each
+ * plus an internal 1394.
+ *
+ * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
+ */
+#define NUM_BASE_IO_SCSI_CTLR 6
+
+/*
+ * This tells ioconfig where it can start numbering scsi controllers.
+ * Below this base number, platform-specific handles the numbering.
+ * XXX Irix legacy..controller numbering should be part of devfsd's job
+ */
+int num_base_io_scsi_ctlr = 2; /* used by syssgi */
+devfs_handle_t		base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
+static devfs_handle_t	baseio_enet_vhdl,baseio_console_vhdl;
+
+/*
+ * Put the logical controller number information in the 
+ * scsi controller vertices for each scsi controller that
+ * is in a "fixed position".
+ */
+static void
+scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
+{
+	{
+		int i;
+
+		num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
+
+		/* Initialize base_io_scsi_ctlr_vhdl array */
+		for (i=0; i<num_base_io_scsi_ctlr; i++)
+			base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
+	}
+	{
+	/*
+	 * May want to consider changing the SN0 code, above, to work more like
+	 * the way this works.
+	 */
+	devfs_handle_t base_ibrick_xbridge_vhdl;
+	devfs_handle_t base_ibrick_xtalk_widget_vhdl;
+	devfs_handle_t scsi_ctlr_vhdl;
+	int i;
+	graph_error_t rv;
+
+	/*
+	 * This is a table of "well-known" SCSI controllers and their well-known
+	 * controller numbers.  The names in the table start from the base IBrick's
+	 * Xbridge vertex, so the first component is the xtalk widget number.
+	 */
+	static struct {
+		char	*base_ibrick_scsi_path;
+		int	controller_number;
+	} hardwired_scsi_controllers[] = {
+		{"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
+		{"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
+		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
+		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
+		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
+		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
+		{NULL, -1} /* must be last */
+	};
+
+	base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
+
+	base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
+	hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
+
+	/*
+	 * Iterate through the list of well-known SCSI controllers.
+	 * For each controller found, set it's controller number according
+	 * to the table.
+	 */
+	for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
+		rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
+			hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
+
+		if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
+			continue;
+
+		ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
+		base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
+		device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
+		hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
+	}
+
+	hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
+	}
+}
+
+
+#include <asm/sn/ioerror_handling.h>
+devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
+
+/* Define the system critical vertices and connect them through
+ * a canonical parent-child relationships for easy traversal
+ * during io error handling.
+ */
+static void
+sys_critical_graph_init(void)
+{
+	devfs_handle_t		bridge_vhdl,master_node_vhdl;
+	devfs_handle_t  		xbow_vhdl = GRAPH_VERTEX_NONE;
+	extern devfs_handle_t	hwgraph_root;
+	devfs_handle_t		pci_slot_conn;
+	int			slot;
+	devfs_handle_t		baseio_console_conn;
+
+	DBG("sys_critical_graph_init: FIXME.\n");
+	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
+
+	if (baseio_console_conn == NULL) {
+		return;
+	}
+
+	/* Get the vertex handle for the baseio bridge */
+	bridge_vhdl = device_master_get(baseio_console_conn);
+
+	/* Get the master node of the baseio card */
+	master_node_vhdl = cnodeid_to_vertex(
+				master_node_get(baseio_console_vhdl));
+	
+	/* Add the "root->node" part of the system critical graph */
+
+	sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
+
+	/* Check if we have a crossbow */
+	if (hwgraph_traverse(master_node_vhdl,
+			     EDGE_LBL_XTALK"/0",
+			     &xbow_vhdl) == GRAPH_SUCCESS) {
+		/* We have a crossbow.Add "node->xbow" part of the system 
+		 * critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
+		
+		/* Add "xbow->baseio bridge" of the system critical graph */
+		sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
+
+		hwgraph_vertex_unref(xbow_vhdl);
+	} else 
+		/* We donot have a crossbow. Add "node->baseio_bridge"
+		 * part of the system critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
+
+	/* Add all the populated PCI slot vertices to the system critical
+	 * graph with the bridge vertex as the parent.
+	 */
+	for (slot = 0 ; slot < 8; slot++) {
+		char	slot_edge[10];
+
+		sprintf(slot_edge,"%d",slot);
+		if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
+		    != GRAPH_SUCCESS)
+			continue;
+		sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	hwgraph_vertex_unref(bridge_vhdl);
+
+	/* Add the "ioc3 pci connection point  -> console ioc3" part 
+	 * of the system critical graph
+	 */
+
+	if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_console_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "ethernet pci connection point  -> base ethernet" part of 
+	 * the system  critical graph
+	 */
+	if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_enet_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "scsi controller pci connection point  -> base scsi 
+	 * controller" part of the system critical graph
+	 */
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[0]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[1]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	hwgraph_vertex_unref(baseio_console_conn);
+
+}
+
+static void
+baseio_ctlr_num_set(void)
+{
+	char 			name[MAXDEVNAME];
+	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
+	devfs_handle_t		ioc3_console_vhdl_get(void);
+
+
+	DBG("baseio_ctlr_num_set; FIXME\n");
+	console_vhdl = ioc3_console_vhdl_get();
+	if (console_vhdl == GRAPH_VERTEX_NONE)
+		return;
+	/* Useful for setting up the system critical graph */
+	baseio_console_vhdl = console_vhdl;
+
+	vertex_to_name(console_vhdl,name,MAXDEVNAME);
+
+	strcat(name,__DEVSTR1);
+	pci_vhdl =  hwgraph_path_to_vertex(name);
+	scsi_ctlr_nums_add(pci_vhdl);
+	/* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(pci_vhdl);
+
+	vertex_to_name(console_vhdl, name, MAXDEVNAME);
+	strcat(name, __DEVSTR4);
+	enet_vhdl = hwgraph_path_to_vertex(name);
+
+	/* Useful for setting up the system critical graph */
+	baseio_enet_vhdl = enet_vhdl;
+
+	device_controller_num_set(enet_vhdl, 0);
+	/* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(enet_vhdl);
+}
+/* #endif */
+
+void
+sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list)
+{
+	/* REFERENCED */
+	int rtn_val;
+
+	/* 
+	** sn00 population:		errb	orrb
+	**	0- ql			3+?
+	**	1- ql			        2
+	**	2- ioc3 ethernet	2+?
+	**	3- ioc3 secondary	        1
+	**	4-                      0
+	** 	5- PCI slot
+	** 	6- PCI slot
+	** 	7- PCI slot
+	*/	
+	
+	/* The following code implements this heuristic for getting 
+	 * maximum usage out of the rrbs
+	 *
+	 * constraints:
+	 *  8 bit ql1 needs 1+1
+	 *  ql0 or ql5,6,7 wants 1+2
+	 *  ethernet wants 2 or more
+	 *
+	 * rules for even rrbs:
+	 *  if nothing in slot 6 
+	 *   4 rrbs to 0 and 2  (0xc8889999)
+	 *  else 
+         *   3 2 3 to slots 0 2 6  (0xc8899bbb)
+	 *
+         * rules for odd rrbs
+	 *  if nothing in slot 5 or 7  (0xc8889999)
+	 *   4 rrbs to 1 and 3
+	 *  else if 1 thing in 5 or 7  (0xc8899aaa) or (0xc8899bbb)
+         *   3 2 3 to slots 1 3 5|7
+         *  else
+         *   2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this
+	 *           (0xc89aaabb)      may short what it wants therefore the
+	 *			       rule should be to plug pci slots in order)
+	 */
+
+
+	if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) {
+		/* something in slot 6 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0);
+	}
+	else {
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0);
+	}
+	if (rtn_val)
+		printk(KERN_WARNING  "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
+
+	if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && 
+	    (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) {
+		/* soemthing in slot 5 and 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0);
+	}
+	else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) {
+		/* soemthing in slot 5 but not 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0);
+	}
+	else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) {
+		/* soemthing in slot 7 but not 5 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0);
+	}
+	else {
+		/* nothing in slot 5 or 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0);
+	}
+	if (rtn_val)
+		printk(KERN_WARNING  "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
+}
+
+
+/*
+ * Initialize all I/O devices.  Starting closest to nodes, probe and
+ * initialize outward.
+ */
+void
+init_all_devices(void)
+{
+	/* Governor on init threads..bump up when safe 
+	 * (beware many devfs races) 
+	 */
+	cnodeid_t cnodeid, active;
+
+	active = 0;
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
+                DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
+                io_init_node(cnodeid);
+
+		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
+	}
+
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
+		/*
+	 	 * Update information generated by IO init.
+		 */
+		update_node_information(cnodeid);
+
+	baseio_ctlr_num_set();
+	/* Setup the system critical graph (which is a subgraph of the
+	 * main hwgraph). This information is useful during io error
+	 * handling.
+	 */
+	sys_critical_graph_init();
+
+#if HWG_PRINT
+	hwgraph_print();
+#endif
+
+}
+
+#define toint(x) ((int)(x) - (int)('0'))
+
+void
+devnamefromarcs(char *devnm)
+{
+	int 			val;
+	char 			tmpnm[MAXDEVNAME];
+	char 			*tmp1, *tmp2;
+	
+	val = strncmp(devnm, "dks", 3);
+	if (val != 0) 
+		return;
+	tmp1 = devnm + 3;
+	if (!isdigit(*tmp1))
+		return;
+
+	val = 0;
+	while (isdigit(*tmp1)) {
+		val = 10*val+toint(*tmp1);
+		tmp1++;
+	}
+
+	if(*tmp1 != 'd')
+		return;
+	else
+		tmp1++;
+
+	if ((val < 0) || (val >= num_base_io_scsi_ctlr)) {
+		int i;
+		int viable_found = 0;
+
+		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
+		DBG("prom \"root\" variables of the form dksXdXsX.\n");
+		DBG("To use another disk you must use the full hardware graph path\n\n");
+		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
+		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
+			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
+				DBG("%d ", i);
+				viable_found=1;
+			}
+		}
+		if (viable_found)
+			DBG("\n");
+		else
+			DBG("none found!\n");
+
+		DELAY(15000000);
+		//prom_reboot();
+		panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
+		/* NOTREACHED */
+	}
+		
+	ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
+	vertex_to_name(base_io_scsi_ctlr_vhdl[val],
+		       tmpnm,
+		       MAXDEVNAME);
+	tmp2 = 	tmpnm + strlen(tmpnm);
+	strcpy(tmp2, __DEVSTR2);
+	tmp2 += strlen(__DEVSTR2);
+	while (*tmp1 != 's') {
+		if((*tmp2++ = *tmp1++) == '\0')
+			return;
+	}	
+	tmp1++;
+	strcpy(tmp2, __DEVSTR3);
+	tmp2 += strlen(__DEVSTR3);
+	while ( (*tmp2++ = *tmp1++) )
+		;
+	tmp2--;
+	*tmp2++ = '/';
+	strcpy(tmp2, EDGE_LBL_BLOCK);
+	strcpy(devnm,tmpnm);
+}
+
+static
+struct io_brick_map_s io_brick_tab[] = {
+
+/* Ibrick widget number to PCI bus number map */
+ {      MODULE_IBRICK,                          /* Ibrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        0,                                      /* 0xc            */
+        0,                                      /* 0xd            */
+        2,                                      /* 0xe            */
+        1                                       /* 0xf            */
+     }
+ },
+
+/* Pbrick widget number to PCI bus number map */
+ {      MODULE_PBRICK,                          /* Pbrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        2,                                      /* 0x8            */
+        1,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        5,                                      /* 0xc            */
+        6,                                      /* 0xd            */
+        4,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* PXbrick widget number to PCI bus number map */
+ {      MODULE_PXBRICK,                         /* PXbrick type   */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        1,                                      /* 0xc            */
+        5,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* Xbrick widget to XIO slot map */
+ {      MODULE_XBRICK,                          /* Xbrick type    */ 
+    /*  XIO Slot #                                 Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        1,                                      /* 0x8            */
+        3,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        2,                                      /* 0xc            */
+        4,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        0                                       /* 0xf            */
+    }
+ }
+};
+
+/*
+ * Use the brick's type to map a widget number to a meaningful int
+ */
+int
+io_brick_map_widget(int brick_type, int widget_num)
+{
+        int num_bricks, i;
+
+        /* Calculate number of bricks in table */
+        num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
+
+        /* Look for brick prefix in table */
+        for (i = 0; i < num_bricks; i++) {
+               if (brick_type == io_brick_tab[i].ibm_type)
+                       return(io_brick_tab[i].ibm_map_wid[widget_num]);
+        }
+
+        return 0;
+
+}
+
+/*
+ * Use the device's vertex to map the device's widget to a meaningful int
+ */
+int
+io_path_map_widget(devfs_handle_t vertex)
+{
+        char hw_path_name[MAXDEVNAME];
+        char *wp, *bp, *sp = NULL;
+        int  widget_num;
+	long atoi(char *);
+	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
+
+
+        /* Get the full path name of the vertex */
+        if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
+                                                     MAXDEVNAME))
+                return 0;
+
+        /* Find the widget number in the path name */
+        wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
+        if (wp == NULL)
+                return 0;
+        widget_num = atoi(wp+7);
+        if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
+                return 0;
+
+        /* Find "brick" in the path name */
+        bp = strstr(hw_path_name, "brick");
+        if (bp == NULL)
+                return 0;
+
+        /* Find preceding slash */
+        sp = bp;
+        while (sp > hw_path_name) {
+                sp--;
+                if (*sp == '/')
+                        break;
+        }
+
+        /* Invalid if no preceding slash */
+        if (!sp)
+                return 0;
+
+        /* Bump slash pointer to "brick" prefix */
+        sp++;
+        /*
+         * Verify "brick" prefix length;  valid exaples:
+         * 'I' from "/Ibrick"
+         * 'P' from "/Pbrick"
+         * 'X' from "/Xbrick"
+         */
+         if ((bp - sp) != 1)
+                return 0;
+
+        return (io_brick_map_widget((int)*sp, widget_num));
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/module.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/module.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/module.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/module.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,311 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn1/hubdev.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/sn_cpuid.h>
+
+
+/* #define LDEBUG	1 */
+
+#ifdef LDEBUG
+#define DPRINTF		printk
+#define printf		printk
+#else
+#define DPRINTF(x...)
+#endif
+
+module_t	       *modules[MODULE_MAX];
+int			nummodules;
+
+#define SN00_SERIAL_FUDGE	0x3b1af409d513c2
+#define SN0_SERIAL_FUDGE	0x6e
+
+void
+encode_int_serial(uint64_t src,uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    val = src + SN00_SERIAL_FUDGE;
+
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)dest)[i] =
+	    ((char*)&val)[sizeof(long long)/2 +
+			 ((i%2) ? ((i/2 * -1) - 1) : (i/2))];
+    }
+}
+
+
+void
+decode_int_serial(uint64_t src, uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)&val)[sizeof(long long)/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
+	    ((char*)&src)[i];
+    }
+
+    *dest = val - SN00_SERIAL_FUDGE;
+}
+
+
+void
+encode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+
+	dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+void
+decode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+	dest[MAX_SERIAL_NUM_SIZE/2 +
+	    ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+
+module_t *module_lookup(moduleid_t id)
+{
+    int			i;
+
+    for (i = 0; i < nummodules; i++)
+	if (modules[i]->id == id) {
+	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
+	    return modules[i];
+	}
+
+    return NULL;
+}
+
+/*
+ * module_add_node
+ *
+ *   The first time a new module number is seen, a module structure is
+ *   inserted into the module list in order sorted by module number
+ *   and the structure is initialized.
+ *
+ *   The node number is added to the list of nodes in the module.
+ */
+
+module_t *module_add_node(moduleid_t id, cnodeid_t n)
+{
+    module_t	       *m;
+    int			i;
+    char		buffer[16];
+
+#ifdef __ia64
+    memset(buffer, 0, 16);
+    format_module_id(buffer, id, MODULE_FORMAT_BRIEF);
+    DPRINTF("module_add_node: id=%s node=%d\n", buffer, n);
+#endif
+
+    if ((m = module_lookup(id)) == 0) {
+#ifdef LATER
+	m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n);
+#else
+	m = kmalloc(sizeof (module_t), GFP_KERNEL);
+	memset(m, 0 , sizeof(module_t));
+#endif
+	ASSERT_ALWAYS(m);
+
+	m->id = id;
+	spin_lock_init(&m->lock);
+
+	mutex_init_locked(&m->thdcnt);
+
+	elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n));
+	spin_lock_init(&m->elsclock);
+
+	/* Insert in sorted order by module number */
+
+	for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--)
+	    modules[i] = modules[i - 1];
+
+	modules[i] = m;
+	nummodules++;
+    }
+
+    m->nodes[m->nodecnt++] = n;
+
+    DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
+
+    return m;
+}
+
+int module_probe_snum(module_t *m, nasid_t nasid)
+{
+    lboard_t	       *board;
+    klmod_serial_num_t *comp;
+    char * bcopy(const char * src, char * dest, int count);
+    char serial_number[16];
+
+    /*
+     * record brick serial number
+     */
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+    {
+#if	LDEBUG
+	printf ("module_probe_snum: no IP35 board found!\n");
+#endif
+	return 0;
+    }
+
+    board_serial_number_get( board, serial_number );
+    if( serial_number[0] != '\0' ) {
+	encode_str_serial( serial_number, m->snum.snum_str );
+	m->snum_valid = 1;
+    }
+#if	LDEBUG
+    else {
+	printf("module_probe_snum: brick serial number is null!\n");
+    }
+    printf("module_probe_snum: brick serial number == %s\n", serial_number);
+#endif /* DEBUG */
+
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
+			KLTYPE_IOBRICK_XBOW);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+	return 0;
+
+    comp = GET_SNUM_COMP(board);
+
+    if (comp) {
+#if LDEBUG
+	    int i;
+
+	    printf("********found module with id %x and string", m->id);
+
+	    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
+		printf(" %x ", comp->snum.snum_str[i]);
+
+	    printf("\n");	/* Fudged string is not ASCII */
+#endif
+
+	    if (comp->snum.snum_str[0] != '\0') {
+		bcopy(comp->snum.snum_str,
+		      m->sys_snum,
+		      MAX_SERIAL_NUM_SIZE);
+		m->sys_snum_valid = 1;
+	    }
+    }
+
+    if (m->sys_snum_valid)
+	return 1;
+    else {
+	DPRINTF("Invalid serial number for module %d, "
+		"possible missing or invalid NIC.", m->id);
+	return 0;
+    }
+}
+
+void
+io_module_init(void)
+{
+    cnodeid_t		node;
+    lboard_t	       *board;
+    nasid_t		nasid;
+    int			nserial;
+    module_t	       *m;
+
+    DPRINTF("*******module_init\n");
+
+    nserial = 0;
+
+    for (node = 0; node < numnodes; node++) {
+	nasid = COMPACT_TO_NASID_NODEID(node);
+
+	board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	ASSERT(board);
+
+	m = module_add_node(board->brd_module, node);
+
+	if (! m->snum_valid && module_probe_snum(m, nasid))
+	    nserial++;
+    }
+
+    DPRINTF("********found total of %d serial numbers in the system\n",
+	    nserial);
+
+    if (nserial == 0)
+	printk(KERN_WARNING  "io_module_init: No serial number found.\n");
+}
+
+elsc_t *get_elsc(void)
+{
+	return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc;
+}
+
+int
+get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info)
+{
+    int i;
+
+    if (cmod < 0 || cmod >= nummodules)
+	return -EINVAL;
+
+    if (! modules[cmod]->snum_valid)
+	return -ENXIO;
+
+    mod_info->mod_num = modules[cmod]->id;
+    {
+	char temp[MAX_SERIAL_NUM_SIZE];
+
+	decode_str_serial(modules[cmod]->snum.snum_str, temp);
+
+	/* if this is an invalid serial number return an error */
+	if (temp[0] != 'K')
+	    return -ENXIO;
+
+	mod_info->serial_num = 0;
+
+	for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) {
+	    mod_info->serial_num <<= 4;
+	    mod_info->serial_num |= (temp[i] & 0xf);
+
+	    mod_info->serial_str[i] = temp[i];
+	}
+
+	mod_info->serial_str[i] = '\0';
+    }
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pci_bus_cvlink.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pci_bus_cvlink.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pci_bus_cvlink.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pci_bus_cvlink.c	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,696 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <asm/sn/types.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/iograph.h>
+#include <asm/param.h>
+#include <asm/sn/pio.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_cpuid.h>
+
+extern int bridge_rev_b_data_check_disable;
+
+devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];
+nasid_t busnum_to_nid[MAX_PCI_XWIDGET];
+void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];
+unsigned char num_bridges;
+static int done_probing = 0;
+
+static int pci_bus_map_create(devfs_handle_t xtalk);
+devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);
+
+#define SN_IOPORTS_UNIT 256
+#define MAX_IOPORTS 0xffff
+#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN_IOPORTS_UNIT)
+struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS];
+unsigned long sn_allocate_ioports(unsigned long pci_address);
+extern unsigned char Is_pic_on_this_nasid[512];
+
+extern void sn_init_irq_desc(void);
+
+
+/*
+ * For the given device, initialize whether it is a PIC device.
+ */
+static void
+set_isPIC(struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+
+	device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);;
+}
+
+/*
+ * pci_bus_cvlink_init() - To be called once during initialization before 
+ *	SGI IO Infrastructure init is called.
+ */
+void
+pci_bus_cvlink_init(void)
+{
+	memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
+	memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET);
+
+	memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET);
+
+	memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs));
+
+	num_bridges = 0;
+}
+
+/*
+ * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated 
+ *	pci bus vertex from the SGI IO Infrastructure.
+ */
+devfs_handle_t
+pci_bus_to_vertex(unsigned char busnum)
+{
+
+	devfs_handle_t	pci_bus = NULL;
+
+
+	/*
+	 * First get the xwidget vertex.
+	 */
+	pci_bus = busnum_to_pcibr_vhdl[busnum];
+	return(pci_bus);
+}
+
+/*
+ * devfn_to_vertex() - returns the vertex of the device given the bus, slot, 
+ *	and function numbers.
+ */
+devfs_handle_t
+devfn_to_vertex(unsigned char busnum, unsigned int devfn)
+{
+
+	int slot = 0;
+	int func = 0;
+	char	name[16];
+	devfs_handle_t  pci_bus = NULL;
+	devfs_handle_t	device_vertex = (devfs_handle_t)NULL;
+
+	/*
+	 * Go get the pci bus vertex.
+	 */
+	pci_bus = pci_bus_to_vertex(busnum);
+	if (!pci_bus) {
+		/*
+		 * During probing, the Linux pci code invents non existant
+		 * bus numbers and pci_dev structures and tries to access
+		 * them to determine existance. Don't crib during probing.
+		 */
+		if (done_probing)
+			printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum);
+		return(NULL);
+	}
+
+
+	/*
+	 * Go get the slot&function vertex.
+	 * Should call pciio_slot_func_to_name() when ready.
+	 */
+	slot = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+
+	/*
+	 * For a NON Multi-function card the name of the device looks like:
+	 * ../pci/1, ../pci/2 ..
+	 */
+	if (func == 0) {
+        	sprintf(name, "%d", slot);
+		if (hwgraph_traverse(pci_bus, name, &device_vertex) == 
+			GRAPH_SUCCESS) {
+			if (device_vertex) {
+				return(device_vertex);
+			}
+		}
+	}
+			
+	/*
+	 * This maybe a multifunction card.  It's names look like:
+	 * ../pci/1a, ../pci/1b, etc.
+	 */
+	sprintf(name, "%d%c", slot, 'a'+func);
+	if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) {
+		if (!device_vertex) {
+			return(NULL);
+		}
+	}
+
+	return(device_vertex);
+}
+
+/*
+ * For the given device, initialize the addresses for both the Device(x) Flush 
+ * Write Buffer register and the Xbow Flush Register for the port the PCI bus 
+ * is connected.
+ */
+static void
+set_flush_addresses(struct pci_dev *device_dev, 
+	struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+    	bridge_t               *bridge = pcibr_soft->bs_base;
+
+	device_sysdata->dma_buf_sync = (volatile unsigned int *) 
+		&(bridge->b_wr_req_buf[pciio_slot].reg);
+	device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+		XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), 
+		pcibr_soft->bs_xid);
+#ifdef DEBUG
+
+	printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", 
+		device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync);
+
+	while((volatile unsigned int )*device_sysdata->dma_buf_sync);
+	while((volatile unsigned int )*device_sysdata->xbow_buf_sync);
+#endif
+
+}
+
+/*
+ * Most drivers currently do not properly tell the arch specific pci dma
+ * interfaces whether they can handle A64. Here is where we privately
+ * keep track of this.
+ */
+static void __init
+set_sn_pci64(struct pci_dev *dev)
+{
+	unsigned short vendor = dev->vendor;
+	unsigned short device = dev->device;
+
+	if (vendor == PCI_VENDOR_ID_QLOGIC) {
+		if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) ||
+				(device == PCI_DEVICE_ID_QLOGIC_ISP2200)) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+	if (vendor == PCI_VENDOR_ID_SGI) {
+		if (device == PCI_DEVICE_ID_SGI_IOC3) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+}
+
+/*
+ * sn_allocate_ioports() - This routine provides the allocation and 
+ *	mappings between Linux style IOPORTs management.
+ *
+ *	For simplicity sake, SN1 will allocate IOPORTs in chunks of 
+ *	256bytes .. irrespective of what the card desires.  This may 
+ *	have to change when we understand how to deal with legacy ioports 
+ *	which are hardcoded in some drivers e.g. SVGA.
+ *
+ *	Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers.
+ *	It will remain so.  The IO Infrastructure will continue to map 
+ *	IO Resource just like IRIX.  When this is done, we map IOPORT 
+ *	chunks to these resources.  The Linux drivers will see and use real 
+ *	IOPORT numbers.  The various IOPORT access macros e.g. inb/outb etc. 
+ *	does the munging of these IOPORT numbers to make a Uncache Virtual 
+ *	Address.  This address via the tlb entries generates the PCI Address 
+ *	allocated by the SN1 IO Infrastructure Layer.
+ */
+static unsigned long sn_ioport_num = 0x1000; /* Reserve room for Legacy stuff */
+unsigned long
+sn_allocate_ioports(unsigned long pci_address)
+{
+	
+	unsigned long ioport_index;
+
+	/*
+	 * Just some idiot checking ..
+	 */
+	if ( sn_ioport_num > 0xffff ) {
+		printk("sn_allocate_ioports: No more IO PORTS available\n");
+		return(-1);
+	}
+
+	/*
+	 * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's
+	 * Manual for details.
+	 */
+	ioport_index = sn_ioport_num / SN_IOPORTS_UNIT;
+
+	ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */
+	ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */
+	ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/
+	ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/
+	ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */
+	ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/
+	ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/
+	ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */
+	ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */
+	ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */
+
+	/* printk("sn_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */
+	
+	sn_ioport_num += SN_IOPORTS_UNIT;
+
+	return(sn_ioport_num - SN_IOPORTS_UNIT);
+}
+
+/*
+ * sn_pci_fixup() - This routine is called when platform_pci_fixup() is 
+ *	invoked at the end of pcibios_init() to link the Linux pci 
+ *	infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c
+ *
+ *	Other platform specific fixup can also be done here.
+ */
+void
+sn_pci_fixup(int arg)
+{
+	struct list_head *ln;
+	struct pci_bus *pci_bus = NULL;
+	struct pci_dev *device_dev = NULL;
+	struct sn_widget_sysdata *widget_sysdata;
+	struct sn_device_sysdata *device_sysdata;
+#ifdef SN_IOPORTS
+	unsigned long ioport;
+#endif
+	pciio_intr_t intr_handle;
+	int cpuid, bit;
+	devfs_handle_t device_vertex;
+	pciio_intr_line_t lines;
+	extern void sn_pci_find_bios(void);
+
+	if (arg == 0) {
+		sn_init_irq_desc();
+		sn_pci_find_bios();
+		return;
+	}
+
+	done_probing = 1;
+
+	/*
+	 * Initialize the pci bus vertex in the pci_bus struct.
+	 */
+	for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+		pci_bus = pci_bus_b(ln);
+		widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), 
+					GFP_KERNEL);
+		widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number);
+		pci_bus->sysdata = (void *)widget_sysdata;
+	}
+
+	/*
+ 	 * set the root start and end so that drivers calling check_region()
+	 * won't see a conflict
+	 */
+#ifdef SN_IOPORTS
+	ioport_resource.start  = sn_ioport_num;
+	ioport_resource.end = 0xffff;
+#else
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		/*
+		 * IDE legacy IO PORTs are supported in Medusa.
+		 * Just open up IO PORTs from 0 .. ioport_resource.end.
+		 */
+		ioport_resource.start = 0;
+	} else {
+		/*
+		 * We do not support Legacy IO PORT numbers.
+		 */
+		ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET;
+	}
+	ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET;
+#endif
+
+	/*
+	 * Set the root start and end for Mem Resource.
+	 */
+	iomem_resource.start = 0;
+	iomem_resource.end = 0xffffffffffffffff;
+
+	/*
+	 * Initialize the device vertex in the pci_dev struct.
+	 */
+	pci_for_each_dev(device_dev) {
+		unsigned int irq;
+		int idx;
+		u16 cmd;
+		devfs_handle_t vhdl;
+		unsigned long size;
+		extern int bit_pos_to_irq(int);
+
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+				device_dev->device == PCI_DEVICE_ID_SGI_IOC3) {
+			extern void pci_fixup_ioc3(struct pci_dev *d);
+			pci_fixup_ioc3(device_dev);
+		}
+
+		/* Set the device vertex */
+
+		device_sysdata = kmalloc(sizeof(struct sn_device_sysdata),
+					GFP_KERNEL);
+		device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn);
+		device_sysdata->isa64 = 0;
+		/*
+		 * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush 
+		 * register addresses.
+		 */
+		(void) set_flush_addresses(device_dev, device_sysdata);
+
+		device_dev->sysdata = (void *) device_sysdata;
+		set_sn_pci64(device_dev);
+		set_isPIC(device_sysdata);
+
+		pci_read_config_word(device_dev, PCI_COMMAND, &cmd);
+
+		/*
+		 * Set the resources address correctly.  The assumption here 
+		 * is that the addresses in the resource structure has been
+		 * read from the card and it was set in the card by our
+		 * Infrastructure ..
+		 */
+		vhdl = device_sysdata->vhdl;
+		for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
+			size = 0;
+			size = device_dev->resource[idx].end -
+				device_dev->resource[idx].start;
+			if (size) {
+				device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+				device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET;
+			}
+			else
+				continue;
+
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].start + size;
+
+			/*
+			 * Adjust the addresses to go to the SWIZZLE ..
+			 */
+			device_dev->resource[idx].start = 
+				device_dev->resource[idx].start & 0xfffff7ffffffffff;
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].end & 0xfffff7ffffffffff;
+
+			if (device_dev->resource[idx].flags & IORESOURCE_IO) {
+				cmd |= PCI_COMMAND_IO;
+#ifdef SN_IOPORTS
+				ioport = sn_allocate_ioports(device_dev->resource[idx].start);
+				if (ioport < 0) {
+					printk("sn_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number);
+					continue;
+				}
+				pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff)));
+
+				printk("sn_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff)));
+
+				device_dev->resource[idx].start = ioport;
+				device_dev->resource[idx].end = ioport + SN_IOPORTS_UNIT;
+#endif
+			}
+			if (device_dev->resource[idx].flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+		/*
+		 * Now handle the ROM resource ..
+		 */
+		size = device_dev->resource[PCI_ROM_RESOURCE].end -
+			device_dev->resource[PCI_ROM_RESOURCE].start;
+
+		if (size) {
+			device_dev->resource[PCI_ROM_RESOURCE].start =
+			(unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, 
+				size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+			device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET;
+			device_dev->resource[PCI_ROM_RESOURCE].end =
+			device_dev->resource[PCI_ROM_RESOURCE].start + size;
+
+                	/*
+                 	 * go through synergy swizzled space
+                 	 */
+			device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL;
+			device_dev->resource[PCI_ROM_RESOURCE].end   &= 0xfffff7ffffffffffUL;
+
+		}
+
+		/*
+		 * Update the Command Word on the Card.
+		 */
+		cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */
+					   /* bit gets dropped .. no harm */
+		pci_write_config_word(device_dev, PCI_COMMAND, cmd);
+
+		pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines);
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+			device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+				lines = 1;
+		}
+ 
+		device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata;
+		device_vertex = device_sysdata->vhdl;
+ 
+		intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex);
+
+		bit = intr_handle->pi_irq;
+		cpuid = intr_handle->pi_cpu;
+		irq = bit_pos_to_irq(bit);
+		irq = irq + (cpuid << 8);
+		pciio_intr_connect(intr_handle);
+		device_dev->irq = irq;
+#ifdef ajmtestintr
+		{
+			int slot = PCI_SLOT(device_dev->devfn);
+			static int timer_set = 0;
+			pcibr_intr_t	pcibr_intr = (pcibr_intr_t)intr_handle;
+			pcibr_soft_t	pcibr_soft = pcibr_intr->bi_soft;
+			extern void intr_test_handle_intr(int, void*, struct pt_regs *);
+
+			if (!timer_set) {
+				intr_test_set_timer();
+				timer_set = 1;
+			}
+			intr_test_register_irq(irq, pcibr_soft, slot);
+			request_irq(irq, intr_test_handle_intr,0,NULL, NULL);
+		}
+#endif
+
+	}
+}
+
+/*
+ * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job.
+ *
+ *	Linux PCI Bus numbers are assigned from lowest module_id numbers
+ *	(rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to 
+ *	HUB_WIDGET_ID_MIN:
+ *		widgetnum 15 gets lower Bus Number than widgetnum 14 etc.
+ *
+ *	Given 2 modules 001c01 and 001c02 we get the following mappings:
+ *		001c01, widgetnum 15 = Bus number 0
+ *		001c01, widgetnum 14 = Bus number 1
+ *		001c02, widgetnum 15 = Bus number 3
+ *		001c02, widgetnum 14 = Bus number 4
+ *		etc.
+ *
+ * The rational for starting Bus Number 0 with Widget number 15 is because 
+ * the system boot disks are always connected via Widget 15 Slot 0 of the 
+ * I-brick.  Linux creates /dev/sd* devices(naming) strating from Bus Number 0 
+ * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest 
+ * module id(Master Cnode) of the system.
+ *	
+ */
+static int 
+pci_bus_map_create(devfs_handle_t xtalk)
+{
+
+	devfs_handle_t master_node_vertex = NULL;
+	devfs_handle_t xwidget = NULL;
+	devfs_handle_t pci_bus = NULL;
+	hubinfo_t hubinfo = NULL;
+	xwidgetnum_t widgetnum;
+	char pathname[128];
+	graph_error_t rv;
+
+	/*
+	 * Loop throught this vertex and get the Xwidgets ..
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) {
+
+#if 0
+        {
+                int pos;
+                char dname[256];
+                pos = devfs_generate_path(xtalk, dname, 256);
+                printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+        }
+#endif
+
+		sprintf(pathname, "%d", widgetnum);
+		xwidget = NULL;
+		
+		/*
+		 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+		 *	     /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device
+		 */
+		rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+		if ( (rv != GRAPH_SUCCESS) ) {
+			if (!xwidget) {
+				continue;
+}
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		pci_bus = NULL;
+		if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+			if (!pci_bus) {
+				continue;
+}
+
+		/*
+		 * Assign the correct bus number and also the nasid of this 
+		 * pci Xwidget.
+		 * 
+		 * Should not be any race here ...
+		 */
+		num_bridges++;
+		busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+
+		/*
+		 * Get the master node and from there get the NASID.
+		 */
+		master_node_vertex = device_master_get(xwidget);
+		if (!master_node_vertex) {
+			printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+		}
+	
+		hubinfo_get(master_node_vertex, &hubinfo);
+		if (!hubinfo) {
+			printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+			return(1);
+		} else {
+			busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+		}
+
+		/*
+		 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+		 */
+		busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+		if (!busnum_to_atedmamaps[num_bridges - 1])
+			printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+
+		memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+
+	}
+
+        return(0);
+}
+
+/*
+ * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure   
+ *      initialization has completed to set up the mappings between Xbridge
+ *      and logical pci bus numbers.  We also set up the NASID for each of these
+ *      xbridges.
+ *
+ *      Must be called before pci_init() is invoked.
+ */
+int
+pci_bus_to_hcl_cvlink(void) 
+{
+
+	devfs_handle_t devfs_hdl = NULL;
+	devfs_handle_t xtalk = NULL;
+	int rv = 0;
+	char name[256];
+	int master_iobrick;
+	int i;
+
+	/*
+	 * Iterate throught each xtalk links in the system ..
+	 * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 
+	 *
+	 * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15
+	 *
+	 * What if it is not pci?
+	 */
+	devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module");
+
+	/*
+	 * To provide consistent(not persistent) device naming, we need to start 
+	 * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 
+	 * with an attached I-Brick.  Find the master_iobrick.
+	 */
+	master_iobrick = -1;
+	for (i = 0; i < nummodules; i++) {
+		moduleid_t iobrick_id; 
+		iobrick_id = iobrick_module_get(&modules[i]->elsc);
+		if (iobrick_id > 0) { /* Valid module id */
+			if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) {
+				master_iobrick = i;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * The master_iobrick gets bus 0 and 1.
+	 */
+	if (master_iobrick >= 0) {
+		memset(name, 0, 256);
+		format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+		
+	/*
+	 * Now go do the rest of the modules, starting from the C-Brick with the lowest 
+	 * module id, remembering to skip the master_iobrick, which was done above.
+	 */
+	for (i = 0; i < nummodules; i++) {
+		if (i == master_iobrick) {
+			continue; /* Did the master_iobrick already. */
+		}
+
+		memset(name, 0, 256);
+		format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+
+	return(0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pcibr.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pcibr.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pcibr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pcibr.c	2003-05-22 22:06:26.000000000 +0000
@@ -9,7 +9,6 @@
 int NeedXbridgeSwap = 0;
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <asm/sn/sgi.h>
@@ -332,7 +331,6 @@
 extern void rmfree(struct map *mp, size_t size, uint64_t a);
 extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
 extern long atoi(register char *p);
-extern void *swap_ptr(void **loc, void *new);
 extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen);
 extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl);
 extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr);
@@ -1628,243 +1626,6 @@
 			  "BAD"};
 
 
-#ifdef LATER
-
-void
-pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh,
-                            int func,
-                            pcibr_slot_func_info_resp_t funcp)
-{
-    pcibr_info_t                 pcibr_info = pcibr_infoh[func];
-    int                          win;
-
-    funcp->resp_f_status = 0;
-
-    if (!pcibr_info) {
-        return;
-    }
-
-    funcp->resp_f_status |= FUNC_IS_VALID;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
-#else
-    sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex);
-#endif
-
-    if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
-        funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
-    }
-
-    funcp->resp_f_bus = pcibr_info->f_bus;
-    funcp->resp_f_slot = pcibr_info->f_slot;
-    funcp->resp_f_func = pcibr_info->f_func;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
-#else
-    sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master);
-#endif
-    funcp->resp_f_pops = pcibr_info->f_pops;
-    funcp->resp_f_efunc = pcibr_info->f_efunc;
-    funcp->resp_f_einfo = pcibr_info->f_einfo;
-
-    funcp->resp_f_vendor = pcibr_info->f_vendor;
-    funcp->resp_f_device = pcibr_info->f_device;
-
-    for(win = 0 ; win < 6 ; win++) {
-        funcp->resp_f_window[win].resp_w_base =
-                                  pcibr_info->f_window[win].w_base;
-        funcp->resp_f_window[win].resp_w_size =
-                                  pcibr_info->f_window[win].w_size;
-        sprintf(funcp->resp_f_window[win].resp_w_space,
-                "%s",
-                pci_space_name[pcibr_info->f_window[win].w_space]);
-    }
-
-    funcp->resp_f_rbase = pcibr_info->f_rbase;
-    funcp->resp_f_rsize = pcibr_info->f_rsize;
-
-    for (win = 0 ; win < 4; win++) {
-        funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win];
-    }
-
-    funcp->resp_f_att_det_error = pcibr_info->f_att_det_error;
-
-}
-
-int
-pcibr_slot_info_return(pcibr_soft_t             pcibr_soft,
-                       pciio_slot_t             slot,
-                       pcibr_slot_info_resp_t   respp)
-{
-    pcibr_soft_slot_t            pss;
-    int                          func;
-    bridge_t                    *bridge = pcibr_soft->bs_base;
-    reg_p                        b_respp;
-    pcibr_slot_info_resp_t       slotp;
-    pcibr_slot_func_info_resp_t  funcp;
-
-    slotp = snia_kmem_zalloc(sizeof(*slotp), KM_SLEEP);
-    if (slotp == NULL) {
-        return(ENOMEM);
-    }
-
-    pss = &pcibr_soft->bs_slot[slot];
-    
-    printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot);
-
-    slotp->resp_has_host = pss->has_host;
-    slotp->resp_host_slot = pss->host_slot;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
-#else
-    sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn);
-#endif
-    slotp->resp_slot_status = pss->slot_status;
-    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
-
-    if (is_sys_critical_vertex(pss->slot_conn)) {
-        slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
-    }
-
-    slotp->resp_bss_ninfo = pss->bss_ninfo;
-
-    for (func = 0; func < pss->bss_ninfo; func++) {
-        funcp = &(slotp->resp_func[func]);
-        pcibr_slot_func_info_return(pss->bss_infos, func, funcp);
-    }
-
-    sprintf(slotp->resp_bss_devio_bssd_space, "%s",
-            pci_space_name[pss->bss_devio.bssd_space]);
-    slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base;
-    slotp->resp_bss_device = pss->bss_device;
-
-    slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr;
-    slotp->resp_bss_d32_uctr = pss->bss_d32_uctr;
-    slotp->resp_bss_d64_uctr = pss->bss_d64_uctr;
-
-    slotp->resp_bss_d64_base = pss->bss_d64_base;
-    slotp->resp_bss_d64_flags = pss->bss_d64_flags;
-    slotp->resp_bss_d32_base = pss->bss_d32_base;
-    slotp->resp_bss_d32_flags = pss->bss_d32_flags;
-
-    slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active);
-
-    slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
-    slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
-
-    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
-    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
-                                                      PCIBR_RRB_SLOT_VIRTUAL];
-    slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
-
-    if (slot & 1) {
-        b_respp = &bridge->b_odd_resp;
-    } else {
-        b_respp = &bridge->b_even_resp;
-    }
-
-    slotp->resp_b_resp = *b_respp;
-
-    slotp->resp_b_int_device = bridge->b_int_device;
-    slotp->resp_b_int_enable = bridge->b_int_enable;
-    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
-
-    if (COPYOUT(slotp, respp, sizeof(*respp))) {
-        return(EFAULT);
-    }
-
-    snia_kmem_free(slotp, sizeof(*slotp));
-
-    return(0);
-}
-
-/*
- * pcibr_slot_query
- *	Return information about the PCI slot maintained by the infrastructure.
- *	Information is requested in the request structure.
- *
- *      Information returned in the response structure:
- *		Slot hwgraph name
- *		Vendor/Device info
- *		Base register info
- *		Interrupt mapping from device pins to the bridge pins
- *		Devio register
- *		Software RRB info
- *		RRB register info
- *		Host/Gues info
- *		PCI Bus #,slot #, function #
- *		Slot provider hwgraph name
- *		Provider Functions
- *		Error handler
- *		DMA mapping usage counters
- *		DMA direct translation info
- *		External SSRAM workaround info
- */
-int
-pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp)
-{
-    pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t            slot = reqp->req_slot;
-    pciio_slot_t            tmp_slot;
-    pcibr_slot_info_resp_t  respp = (pcibr_slot_info_resp_t) reqp->req_respp;
-    int                     size = reqp->req_size;
-    int                     error;
-
-    /* Make sure that we are dealing with a bridge device vertex */
-    if (!pcibr_soft) {
-        return(EINVAL);
-    }
-
-    /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
-        return(EINVAL);
-    }
-
-    /* Return information for the requested PCI slot */
-    if (slot != PCIIO_SLOT_NONE) {
-        if (size < sizeof(*respp)) {
-            return(EINVAL);
-        }
-
-        /* Acquire read access to the slot */
-        mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO);
-
-        error = pcibr_slot_info_return(pcibr_soft, slot, respp);
-
-        /* Release the slot lock */
-        mrunlock(pcibr_soft->bs_slot[slot].slot_lock);
-
-        return(error);
-    }
-
-    /* Return information for all the slots */
-    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
-
-        if (size < sizeof(*respp)) {
-            return(EINVAL);
-        }
-
-        /* Acquire read access to the slot */
-        mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO);
-
-        error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
-
-        /* Release the slot lock */
-        mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock);
-
-        if (error) {
-            return(error);
-        }
-
-        ++respp;
-        size -= sizeof(*respp);
-    }
-
-    return(error);
-}
-#endif	/* LATER */
-
-
 /*ARGSUSED */
 int
 pcibr_ioctl(devfs_handle_t dev,
@@ -3617,7 +3378,7 @@
 	self->bl_soft = pcibr_soft;
 	self->bl_vhdl = pcibr_vhdl;
 	self->bl_next = pcibr_list;
-	self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self);
+        pcibr_list = self; 
     }
 #endif
 
@@ -6455,9 +6216,7 @@
 
 	    intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
 	    cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-#if defined(CONFIG_IA64_SGI_SN1)
 	    REMOTE_CPU_SEND_INTR(cpu, intr_bit);
-#endif
 	}
 }
 
@@ -6822,13 +6581,8 @@
     bridgereg_t            *int_addr = (bridgereg_t *)
     xtalk_intr_sfarg_get(xtalk_intr);
 
-#ifdef CONFIG_IA64_SGI_SN2
-    *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 26)) |
-		 (BRIDGE_INT_ADDR_FLD & vect));
-#elif CONFIG_IA64_SGI_SN1
     *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
 		 (BRIDGE_INT_ADDR_FLD & vect));
-#endif
 }
 
 /*ARGSUSED */
@@ -7485,7 +7239,7 @@
 
 #ifdef LITTLE_ENDIAN
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pciio.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pciio.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pciio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/pciio.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,1681 @@
+/* $Id: pciio.c,v 1.2 2002/11/16 02:23:19 steiner Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#define	USRPCI	0
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/ate_utils.h>
+#include <asm/sn/simulator.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
+#define DEBUG_PCIIO
+#undef DEBUG_PCIIO	/* turn this on for yet more console output */
+
+
+#define GET_NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DO_DEL(ptr)	(kfree(ptr))
+
+char                    pciio_info_fingerprint[] = "pciio_info";
+
+cdl_p                   pciio_registry = NULL;
+
+int
+badaddr_val(volatile void *addr, int len, volatile void *ptr)
+{
+	int ret = 0;
+	volatile void *new_addr;
+
+	switch (len) {
+		case 4:
+			new_addr = (void *)(((u64) addr)^4);
+			ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr);
+			break;
+		default:
+			printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len);
+	}
+
+	if (ret < 0)
+		panic("badaddr_val: unexpected status (%d) in probing", ret);
+	return(ret);
+
+}
+
+
+nasid_t
+get_console_nasid(void)
+{
+	extern nasid_t console_nasid;
+	if (console_nasid < 0) {
+		console_nasid = ia64_sn_get_console_nasid();
+		if (console_nasid < 0) {
+// ZZZ What do we do if we don't get a console nasid on the hardware????
+			if (IS_RUNNING_ON_SIMULATOR() )
+				console_nasid = master_nasid;
+		}
+	} 
+	return console_nasid;
+}
+
+int
+hub_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+	return(0);
+}
+
+int
+hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+	return(0);
+}
+
+void
+ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror)
+{
+}
+
+/******
+ ****** end hack defines ......
+ ******/
+
+
+
+
+/* =====================================================================
+ *    PCI Generic Bus Provider
+ * Implement PCI provider operations.  The pciio* layer provides a
+ * platform-independent interface for PCI devices.  This layer
+ * switches among the possible implementations of a PCI adapter.
+ */
+
+/* =====================================================================
+ *    Provider Function Location SHORTCUT
+ *
+ * On platforms with only one possible PCI provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+/*
+ *    For the moment, we will assume that IP27
+ *      only use Bridge ASICs to provide PCI support.
+ */
+#include <asm/sn/pci/pcibr.h>
+#define DEV_FUNC(dev,func)	pcibr_##func
+#define CAST_PIOMAP(x)		((pcibr_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pcibr_dmamap_t)(x))
+#define CAST_INTR(x)		((pcibr_intr_t)(x))
+
+/* =====================================================================
+ *    Function Table of Contents
+ */
+
+#if !defined(DEV_FUNC)
+static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev);
+#endif
+
+pciio_piomap_t          pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);
+void                    pciio_piomap_free(pciio_piomap_t);
+caddr_t                 pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t);
+
+void                    pciio_piomap_done(pciio_piomap_t);
+caddr_t                 pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);
+caddr_t			pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned);
+
+iopaddr_t               pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);
+void                    pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);
+
+pciio_dmamap_t          pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+alenlist_t              pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned);
+void                    pciio_dmamap_done(pciio_dmamap_t);
+iopaddr_t               pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			pciio_dmamap_drain(pciio_dmamap_t);
+void			pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);
+void			pciio_dmalist_drain(devfs_handle_t, alenlist_t);
+iopaddr_t               pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned);
+
+pciio_intr_t            pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
+void                    pciio_intr_free(pciio_intr_t);
+int                     pciio_intr_connect(pciio_intr_t);
+void                    pciio_intr_disconnect(pciio_intr_t);
+devfs_handle_t            pciio_intr_cpu_get(pciio_intr_t);
+
+void			pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t);
+
+void                    pciio_provider_startup(devfs_handle_t);
+void                    pciio_provider_shutdown(devfs_handle_t);
+
+pciio_endian_t          pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);
+pciio_priority_t        pciio_priority_set(devfs_handle_t, pciio_priority_t);
+devfs_handle_t            pciio_intr_dev_get(pciio_intr_t);
+
+devfs_handle_t            pciio_pio_dev_get(pciio_piomap_t);
+pciio_slot_t            pciio_pio_slot_get(pciio_piomap_t);
+pciio_space_t           pciio_pio_space_get(pciio_piomap_t);
+iopaddr_t               pciio_pio_pciaddr_get(pciio_piomap_t);
+ulong                   pciio_pio_mapsz_get(pciio_piomap_t);
+caddr_t                 pciio_pio_kvaddr_get(pciio_piomap_t);
+
+devfs_handle_t            pciio_dma_dev_get(pciio_dmamap_t);
+pciio_slot_t            pciio_dma_slot_get(pciio_dmamap_t);
+
+pciio_info_t            pciio_info_chk(devfs_handle_t);
+pciio_info_t            pciio_info_get(devfs_handle_t);
+void                    pciio_info_set(devfs_handle_t, pciio_info_t);
+devfs_handle_t            pciio_info_dev_get(pciio_info_t);
+pciio_slot_t            pciio_info_slot_get(pciio_info_t);
+pciio_function_t        pciio_info_function_get(pciio_info_t);
+pciio_vendor_id_t       pciio_info_vendor_id_get(pciio_info_t);
+pciio_device_id_t       pciio_info_device_id_get(pciio_info_t);
+devfs_handle_t            pciio_info_master_get(pciio_info_t);
+arbitrary_info_t        pciio_info_mfast_get(pciio_info_t);
+pciio_provider_t       *pciio_info_pops_get(pciio_info_t);
+error_handler_f	       *pciio_info_efunc_get(pciio_info_t);
+error_handler_arg_t    *pciio_info_einfo_get(pciio_info_t);
+pciio_space_t		pciio_info_bar_space_get(pciio_info_t, int);
+iopaddr_t		pciio_info_bar_base_get(pciio_info_t, int);
+size_t			pciio_info_bar_size_get(pciio_info_t, int);
+iopaddr_t		pciio_info_rom_base_get(pciio_info_t);
+size_t			pciio_info_rom_size_get(pciio_info_t);
+
+void                    pciio_init(void);
+int                     pciio_attach(devfs_handle_t);
+
+void                    pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns);
+void                    pciio_provider_unregister(devfs_handle_t);
+pciio_provider_t       *pciio_provider_fns_get(devfs_handle_t);
+
+int                     pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned);
+void                    pciio_driver_unregister(char *driver_prefix);
+
+devfs_handle_t            pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+
+void			pciio_device_unregister(devfs_handle_t);
+pciio_info_t		pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+void			pciio_device_info_free(pciio_info_t);
+devfs_handle_t		pciio_device_info_register(devfs_handle_t, pciio_info_t);
+void			pciio_device_info_unregister(devfs_handle_t, pciio_info_t);
+int                     pciio_device_attach(devfs_handle_t, int);
+int			pciio_device_detach(devfs_handle_t, int);
+void                    pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
+
+int                     pciio_reset(devfs_handle_t);
+int                     pciio_write_gather_flush(devfs_handle_t);
+int                     pciio_slot_inuse(devfs_handle_t);
+
+/* =====================================================================
+ *    Provider Function Location
+ *
+ *      If there is more than one possible provider for
+ *      this platform, we need to examine the master
+ *      vertex of the current vertex for a provider
+ *      function structure, and indirect through the
+ *      appropriately named member.
+ */
+
+#if !defined(DEV_FUNC)
+
+static pciio_provider_t *
+pciio_to_provider_fns(devfs_handle_t dev)
+{
+    pciio_info_t            card_info;
+    pciio_provider_t       *provider_fns;
+
+    /*
+     * We're called with two types of vertices, one is
+     * the bridge vertex (ends with "pci") and the other is the
+     * pci slot vertex (ends with "pci/[0-8]").  For the first type
+     * we need to get the provider from the PFUNCS label.  For
+     * the second we get it from fastinfo/c_pops.
+     */
+    provider_fns = pciio_provider_fns_get(dev);
+    if (provider_fns == NULL) {
+	card_info = pciio_info_get(dev);
+	if (card_info != NULL) {
+		provider_fns = pciio_info_pops_get(card_info);
+	}
+    }
+
+    if (provider_fns == NULL)
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	PRINT_PANIC("%v: provider_fns == NULL", dev);
+#else
+	PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev);
+#endif
+
+    return provider_fns;
+
+}
+
+#define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func
+#define CAST_PIOMAP(x)		((pciio_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pciio_dmamap_t)(x))
+#define CAST_INTR(x)		((pciio_intr_t)(x))
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define PIOMAP_FUNC(map,func)		DEV_FUNC((map)->pp_dev,func)
+#define DMAMAP_FUNC(map,func)		DEV_FUNC((map)->pd_dev,func)
+#define INTR_FUNC(intr_hdl,func)	DEV_FUNC((intr_hdl)->pi_dev,func)
+
+/* =====================================================================
+ *          PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      pciio space on a specified card
+ */
+
+pciio_piomap_t
+pciio_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		   iopaddr_t addr,	/* lowest address (or offset in window) */
+		   size_t byte_count,	/* size of region containing our mappings */
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{					/* defined in sys/pio.h */
+    return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, space, addr, byte_count, byte_count_max, flags);
+}
+
+void
+pciio_piomap_free(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_free)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piomap_addr(pciio_piomap_t pciio_piomap,	/* mapping resources */
+		  iopaddr_t pciio_addr,	/* map for this pciio address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr)
+	(CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count);
+
+    return pciio_piomap->pp_kvaddr;
+}
+
+void
+pciio_piomap_done(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_done)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		    iopaddr_t addr,	/* starting address (or offset in window) */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{					/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, space, addr, byte_count, flags);
+}
+
+caddr_t
+pciio_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       pciio_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_piomap_t          map = 0;
+    int			    errfree = 0;
+    caddr_t                 res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_piotrans_addr
+	(dev, dev_desc, space, addr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_piotrans worked */
+
+    if (!map) {
+	map = pciio_piomap_alloc
+	    (dev, dev_desc, space, addr, byte_count, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_piomap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_piomap_free(map);
+	return res;			/* pciio_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_piomap_addr succeeded */
+}
+
+iopaddr_t
+pciio_piospace_alloc(devfs_handle_t dev,	/* Device requiring space */
+		     device_desc_t dev_desc,	/* Device descriptor */
+		     pciio_space_t space,	/* MEM32/MEM64/IO */
+		     size_t byte_count,	/* Size of mapping */
+		     size_t align)
+{					/* Alignment needed */
+    if (align < NBPP)
+	align = NBPP;
+    return DEV_FUNC(dev, piospace_alloc)
+	(dev, dev_desc, space, byte_count, align);
+}
+
+void
+pciio_piospace_free(devfs_handle_t dev,	/* Device freeing space */
+		    pciio_space_t space,	/* Type of space        */
+		    iopaddr_t pciaddr,	/* starting address */
+		    size_t byte_count)
+{					/* Range of address   */
+    DEV_FUNC(dev, piospace_free)
+	(dev, space, pciaddr, byte_count);
+}
+
+/* =====================================================================
+ *          DMA MANAGEMENT
+ *
+ *      For mapping from pci space to system
+ *      physical space.
+ */
+
+pciio_dmamap_t
+pciio_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{					/* defined in dma.h */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+void
+pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+	(CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+alenlist_t
+pciio_dmamap_list(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_list)
+	(CAST_DMAMAP(pciio_dmamap), alenlist, flags);
+}
+
+void
+pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+alenlist_t
+pciio_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+iopaddr_t
+pciio_dma_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       paddr_t paddr,		/* system physical address */
+	       size_t byte_count,	/* length */
+	       pciio_dmamap_t *mapp,	/* map to use, then map we used */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_dmamap_t          map = 0;
+    int			    errfree = 0;
+    iopaddr_t               res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_dmatrans_addr
+	(dev, dev_desc, paddr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_dmatrans worked */
+
+    if (!map) {
+	map = pciio_dmamap_alloc
+	    (dev, dev_desc, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_dmamap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_dmamap_addr
+	(map, paddr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_dmamap_free(map);
+	return res;			/* pciio_dmamap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_dmamap_addr succeeded */
+}
+
+void
+pciio_dmamap_drain(pciio_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *          INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+pciio_intr_t
+pciio_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 pciio_intr_line_t lines,	/* INTR line(s) to attach */
+		 devfs_handle_t owner_dev)
+{					/* owner of this interrupt */
+    return (pciio_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, lines, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+pciio_intr_free(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Associate resources allocated with a previous pciio_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+pciio_intr_connect(pciio_intr_t intr_hdl)	/* pciio intr resource handle */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+pciio_intr_disconnect(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+pciio_intr_cpu_get(pciio_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+void
+pciio_slot_func_to_name(char		       *name,
+			pciio_slot_t		slot,
+			pciio_function_t	func)
+{
+    /*
+     * standard connection points:
+     *
+     * PCIIO_SLOT_NONE:	.../pci/direct
+     * PCIIO_FUNC_NONE: .../pci/<SLOT>			ie. .../pci/3
+     * multifunction:   .../pci/<SLOT><FUNC>		ie. .../pci/3c
+     */
+
+    if (slot == PCIIO_SLOT_NONE)
+	sprintf(name, EDGE_LBL_DIRECT);
+    else if (func == PCIIO_FUNC_NONE)
+	sprintf(name, "%d", slot);
+    else
+	sprintf(name, "%d%c", slot, 'a'+func);
+}
+
+/* =====================================================================
+ *          CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+pciio_provider_startup(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_startup)
+	(pciio_provider);
+}
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+pciio_provider_shutdown(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_shutdown)
+	(pciio_provider);
+}
+
+/*
+ * Specify endianness constraints.  The driver tells us what the device
+ * does and how it would like to see things in memory.  We reply with
+ * how things will actually appear in memory.
+ */
+pciio_endian_t
+pciio_endian_set(devfs_handle_t dev,
+		 pciio_endian_t device_end,
+		 pciio_endian_t desired_end)
+{
+    ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE));
+    ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));
+
+#if DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_ALERT  "%v: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#else
+    printk(KERN_ALERT  "0x%x: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#endif
+#endif
+
+    return DEV_FUNC(dev, endian_set)
+	(dev, device_end, desired_end);
+}
+
+/*
+ * Specify PCI arbitration priority.
+ */
+pciio_priority_t
+pciio_priority_set(devfs_handle_t dev,
+		   pciio_priority_t device_prio)
+{
+    ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW));
+
+    return DEV_FUNC(dev, priority_set)
+	(dev, device_prio);
+}
+
+/*
+ * Read value of configuration register
+ */
+uint64_t
+pciio_config_get(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size)
+{
+    uint64_t	value = 0;
+    unsigned	shift = 0;
+
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+
+	value |= DEV_FUNC(dev, config_get)
+	    (dev, reg, biw) << shift;
+
+	shift += 8*biw;
+	reg += biw;
+	size -= biw;
+    }
+    return value;
+}
+
+/*
+ * Change value of configuration register
+ */
+void
+pciio_config_set(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size,
+		 uint64_t	value)
+{
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+	    
+	DEV_FUNC(dev, config_set)
+	    (dev, reg, biw, value);
+	reg += biw;
+	size -= biw;
+	value >>= biw * 8;
+    }
+}
+
+/* =====================================================================
+ *          GENERIC PCI SUPPORT FUNCTIONS
+ */
+
+/*
+ * Issue a hardware reset to a card.
+ */
+int
+pciio_reset(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, reset) (dev);
+}
+
+/*
+ * flush write gather buffers
+ */
+int
+pciio_write_gather_flush(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, write_gather_flush) (dev);
+}
+
+devfs_handle_t
+pciio_intr_dev_get(pciio_intr_t pciio_intr)
+{
+    return (pciio_intr->pi_dev);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+pciio_pio_dev_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_dev);
+}
+
+pciio_slot_t
+pciio_pio_slot_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_slot);
+}
+
+pciio_space_t
+pciio_pio_space_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_space);
+}
+
+iopaddr_t
+pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_pciaddr);
+}
+
+ulong
+pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_mapsz);
+}
+
+caddr_t
+pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_kvaddr);
+}
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_dev);
+}
+
+pciio_slot_t
+pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_slot);
+}
+
+/****** Generic pci slot information interfaces ******/
+
+pciio_info_t
+pciio_info_chk(devfs_handle_t pciio)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo);
+    return (pciio_info_t) ainfo;
+}
+
+pciio_info_t
+pciio_info_get(devfs_handle_t pciio)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio);
+
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pciio, dname, 256);
+	printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    if ((pciio_info != NULL) &&
+	(pciio_info->c_fingerprint != pciio_info_fingerprint)
+	&& (pciio_info->c_fingerprint != NULL)) {
+
+	return((pciio_info_t)-1); /* Should panic .. */
+    }
+	
+
+    return pciio_info;
+}
+
+void
+pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info)
+{
+    if (pciio_info != NULL)
+	pciio_info->c_fingerprint = pciio_info_fingerprint;
+    hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info);
+
+    /* Also, mark this vertex as a PCI slot
+     * and use the pciio_info, so pciio_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO,
+			 (arbitrary_info_t) pciio_info);
+}
+
+devfs_handle_t
+pciio_info_dev_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vertex);
+}
+
+pciio_slot_t
+pciio_info_slot_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_slot);
+}
+
+pciio_function_t
+pciio_info_function_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_func);
+}
+
+pciio_vendor_id_t
+pciio_info_vendor_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vendor);
+}
+
+pciio_device_id_t
+pciio_info_device_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_device);
+}
+
+devfs_handle_t
+pciio_info_master_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_master);
+}
+
+arbitrary_info_t
+pciio_info_mfast_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_mfast);
+}
+
+pciio_provider_t       *
+pciio_info_pops_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_pops);
+}
+
+error_handler_f	       *
+pciio_info_efunc_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_efunc);
+}
+
+error_handler_arg_t    *
+pciio_info_einfo_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_einfo);
+}
+
+pciio_space_t
+pciio_info_bar_space_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_space;
+}
+
+iopaddr_t
+pciio_info_bar_base_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_base;
+}
+
+size_t
+pciio_info_bar_size_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_size;
+}
+
+iopaddr_t
+pciio_info_rom_base_get(pciio_info_t info)
+{
+    return info->c_rbase;
+}
+
+size_t
+pciio_info_rom_size_get(pciio_info_t info)
+{
+    return info->c_rsize;
+}
+
+
+/* =====================================================================
+ *          GENERIC PCI INITIALIZATION FUNCTIONS
+ */
+
+/*
+ *    pciioinit: called once during device driver
+ *      initializtion if this driver is configured into
+ *      the system.
+ */
+void
+pciio_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("pciio_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (pciio_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_PCI, "vendor", "device");
+	if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(pciio_registry != NULL);
+}
+
+/*
+ *    pciioattach: called for each vertex in the graph
+ *      that is a PCI provider.
+ */
+/*ARGSUSED */
+int
+pciio_attach(devfs_handle_t pciio)
+{
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_attach\n", pciio);
+#else
+    printk("0x%x: pciio_attach\n", pciio);
+#endif
+#endif
+    return 0;
+}
+
+/*
+ * Associate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns)
+{
+    hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns);
+}
+
+/*
+ * Disassociate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_unregister(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo;
+
+    hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo);
+}
+
+/*
+ * Obtain a pointer to the pciio_provider functions for a specified Crosstalk
+ * provider.
+ */
+pciio_provider_t       *
+pciio_provider_fns_get(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo);
+    return (pciio_provider_t *) ainfo;
+}
+
+/*ARGSUSED4 */
+int
+pciio_driver_register(
+			 pciio_vendor_id_t vendor_id,
+			 pciio_device_id_t device_id,
+			 char *driver_prefix,
+			 unsigned flags)
+{
+    /* a driver's init routine might call
+     * pciio_driver_register before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    return cdl_add_driver(pciio_registry,
+			  vendor_id, device_id,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Remove an initialization function.
+ */
+void
+pciio_driver_unregister(
+			   char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called register; so
+     * we can assume we have a registry here.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    cdl_del_driver(pciio_registry, driver_prefix, NULL);
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being registered.
+ */
+void
+pciio_driver_reg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being unregistered.
+ */
+void
+pciio_driver_unreg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+pciio_iterate(char *driver_prefix,
+	      pciio_iter_f * func)
+{
+    /* a driver's init routine might call
+     * pciio_iterate before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    ASSERT(pciio_registry != NULL);
+
+    cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func);
+}
+
+devfs_handle_t
+pciio_device_register(
+		devfs_handle_t connectpt,	/* vertex for /hw/.../pciio/%d */
+		devfs_handle_t master,	/* card's master ASIC (PCI provider) */
+		pciio_slot_t slot,	/* card's slot */
+		pciio_function_t func,	/* card's func */
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    return pciio_device_info_register
+	(connectpt, pciio_device_info_new (NULL, master, slot, func,
+					   vendor_id, device_id));
+}
+
+void
+pciio_device_unregister(devfs_handle_t pconn)
+{
+    DEV_FUNC(pconn,device_unregister)(pconn);
+}
+
+pciio_info_t
+pciio_device_info_new(
+		pciio_info_t pciio_info,
+		devfs_handle_t master,
+		pciio_slot_t slot,
+		pciio_function_t func,
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    if (!pciio_info)
+	GET_NEW(pciio_info);
+    ASSERT(pciio_info != NULL);
+
+    pciio_info->c_slot = slot;
+    pciio_info->c_func = func;
+    pciio_info->c_vendor = vendor_id;
+    pciio_info->c_device = device_id;
+    pciio_info->c_master = master;
+    pciio_info->c_mfast = hwgraph_fastinfo_get(master);
+    pciio_info->c_pops = pciio_provider_fns_get(master);
+    pciio_info->c_efunc = 0;
+    pciio_info->c_einfo = 0;
+
+    return pciio_info;
+}
+
+void
+pciio_device_info_free(pciio_info_t pciio_info)
+{
+    /* NOTE : pciio_info is a structure within the pcibr_info
+     *	      and not a pointer to memory allocated on the heap !!
+     */
+    BZERO((char *)pciio_info,sizeof(pciio_info));
+}
+
+devfs_handle_t
+pciio_device_info_register(
+		devfs_handle_t connectpt,		/* vertex at center of bus */
+		pciio_info_t pciio_info)	/* details about the connectpt */
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+    int device_master_set(devfs_handle_t, devfs_handle_t);
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_path_add(connectpt, name, &pconn))
+	return pconn;
+
+    pciio_info->c_vertex = pconn;
+    pciio_info_set(pconn, pciio_info);
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pconn, dname, 256);
+	printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    /*
+     * create link to our pci provider
+     */
+
+    device_master_set(pconn, pciio_info->c_master);
+
+#if USRPCI
+    /*
+     * Call into usrpci provider to let it initialize for
+     * the given slot.
+     */
+    if (pciio_info->c_slot != PCIIO_SLOT_NONE)
+	usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot);
+#endif
+
+    return pconn;
+}
+
+void
+pciio_device_info_unregister(devfs_handle_t connectpt,
+			     pciio_info_t pciio_info)
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+
+    if (!pciio_info)
+	return;
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    hwgraph_edge_remove(connectpt,name,&pconn);
+    pciio_info_set(pconn,0);
+
+    /* Remove the link to our pci provider */
+    hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL);
+
+
+    hwgraph_vertex_unref(pconn);
+    hwgraph_vertex_destroy(pconn);
+    
+}
+/* Add the pci card inventory information to the hwgraph
+ */
+static void
+pciio_device_inventory_add(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t	pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+
+    /* Donot add inventory  for non-existent devices */
+    if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE)	||
+	(pciio_info->c_device == PCIIO_DEVICE_ID_NONE))
+	return;
+    device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP,
+			 pciio_info->c_vendor,pciio_info->c_device,
+			 pciio_info->c_slot);
+}
+
+/*ARGSUSED */
+int
+pciio_device_attach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+
+    pciio_device_inventory_add(pconn);
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));
+}
+
+int
+pciio_device_detach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_del_connpt(pciio_registry, vendor_id, device_id,
+		          pconn, drv_flags));
+
+}
+
+/* SN2 */
+/*
+ * Allocate (if necessary) and initialize a PCI window mapping structure.
+ */
+pciio_win_map_t
+pciio_device_win_map_new(pciio_win_map_t win_map,
+			 size_t region_size,
+			 size_t page_size)
+{
+	ASSERT((page_size & (page_size - 1)) == 0);
+	ASSERT((region_size & (page_size - 1)) == 0);
+
+	if (win_map == NULL)
+		NEW(win_map);
+
+	/*
+	 * The map array tracks the free ``pages'' in the region.  The worst
+	 * case scenario is when every other page in the region is free --
+	 * e.i. maximum fragmentation.  This leads to (max pages + 1) / 2 + 1
+	 * map entries.  The first "+1" handles the divide by 2 rounding; the
+	 * second handles the need for an end marker sentinel.
+	 */
+	win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1);
+	win_map->wm_page_size = page_size;
+	ASSERT(win_map->wm_map != NULL);
+
+	return win_map;
+}
+
+/*
+ * Free resources associated with a PCI window mapping structure.
+ */
+extern void
+pciio_device_win_map_free(pciio_win_map_t win_map)
+{
+	rmfreemap(win_map->wm_map);
+	bzero(win_map, sizeof *win_map);
+}
+
+/*
+ * Populate window map with specified free range.
+ */
+void
+pciio_device_win_populate(pciio_win_map_t win_map,
+                          iopaddr_t ioaddr,
+                          size_t size)
+{
+	ASSERT((size & (win_map->wm_page_size - 1)) == 0);
+	ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0);
+
+	rmfree(win_map->wm_map,
+	       size / win_map->wm_page_size,
+	       (unsigned long)ioaddr / win_map->wm_page_size);
+	       
+}
+/*
+ * Allocate space from the specified PCI window mapping resource.  On
+ * success record information about the allocation in the supplied window
+ * allocation cookie (if non-NULL) and return the address of the allocated
+ * window.  On failure return NULL.
+ *
+ * The "size" parameter is usually from a PCI device's Base Address Register
+ * (BAR) decoder.  As such, the allocation must be aligned to be a multiple of
+ * that.  The "align" parameter acts as a ``minimum alignment'' allocation
+ * constraint.  The alignment contraint reflects system or device addressing
+ * restrictions such as the inability to share higher level ``windows''
+ * between devices, etc.  The returned PCI address allocation will be a
+ * multiple of the alignment constraint both in alignment and size.  Thus, the
+ * returned PCI address block is aligned to the maximum of the requested size
+ * and alignment.
+ */
+iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,
+		       pciio_win_alloc_t win_alloc,
+		       size_t size, size_t align)
+{
+	unsigned long base;
+
+#ifdef PIC_LATER
+	ASSERT((size & (size - 1)) == 0);
+	ASSERT((align & (align - 1)) == 0);
+
+	/*
+	 * Convert size and alignment to pages.  If size is greated than the
+	 * requested alignment, we bump the alignment up to size; otherwise
+	 * convert the size into a multiple of the alignment request.
+	 */
+	size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size;
+	align = align / win_map->wm_page_size;
+	if (size > align)
+		align = size;
+	else
+		size = (size + align - 1) & ~(align - 1);
+
+	/* XXXX */
+	base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP);
+	if (base == RMALLOC_FAIL)
+		return((iopaddr_t)NULL);
+#else
+    int                 index_page, index_page_align;
+    int                 align_pages, size_pages;
+    int                 alloc_pages, free_pages;
+    int                 addr_align;
+
+    /* Convert PCI bus alignment from bytes to pages */
+    align_pages = align / win_map->wm_page_size;
+
+    /* Convert PCI request from bytes to pages */
+    size_pages = (size / win_map->wm_page_size) +
+                  ((size % win_map->wm_page_size) ? 1 : 0);
+
+    /* Align address with the larger of the size or the requested slot align */
+    if (size_pages > align_pages)
+        align_pages = size_pages;
+  
+    /*
+     * Avoid wasting space by aligning - 1; this will prevent crossing
+     * another alignment boundary.
+     */
+    alloc_pages = size_pages + (align_pages - 1);
+
+    /* Allocate PCI bus space in pages */
+    index_page = (int) rmalloc(win_map->wm_map,
+                               (size_t) alloc_pages);
+
+    /* Error if no PCI bus address space available */
+    if (!index_page)
+        return 0;
+
+    /* PCI bus address index starts at 0 */
+    index_page--;
+
+    /* Align the page offset as requested */
+    index_page_align = (index_page + (align_pages - 1)) -
+                       ((index_page + (align_pages - 1)) % align_pages);
+
+    free_pages = (align_pages - 1) - (index_page_align - index_page);
+
+    /* Free unused PCI bus pages adjusting the index to start at 1 */
+    rmfree(win_map->wm_map, 
+           free_pages,
+           (index_page_align + 1) + size_pages);
+
+    /* Return aligned PCI bus space in bytes */ 
+    addr_align = (index_page_align * win_map->wm_page_size); 
+    base = index_page;
+    size = alloc_pages - free_pages;
+#endif	/* PIC_LATER */
+
+	/*
+	 * If a window allocation cookie has been supplied, use it to keep
+	 * track of all the allocated space assigned to this window.
+	 */
+	if (win_alloc) {
+		win_alloc->wa_map = win_map;
+		win_alloc->wa_base = base;
+		win_alloc->wa_pages = size;
+	}
+
+	return base * win_map->wm_page_size;
+}
+
+/*
+ * Free the specified window allocation back into the PCI window mapping
+ * resource.  As noted above, we keep page addresses offset by 1 ...
+ */
+void
+pciio_device_win_free(pciio_win_alloc_t win_alloc)
+{
+	if (win_alloc->wa_pages)
+		rmfree(win_alloc->wa_map->wm_map,
+		       win_alloc->wa_pages,
+		       win_alloc->wa_base);
+}
+
+/*
+ * pciio_error_register:
+ * arrange for a function to be called with
+ * a specified first parameter plus other
+ * information when an error is encountered
+ * and traced to the pci slot corresponding
+ * to the connection point pconn.
+ *
+ * may also be called with a null function
+ * pointer to "unregister" the error handler.
+ *
+ * NOTE: subsequent calls silently overwrite
+ * previous data for this vertex. We assume that
+ * cooperating drivers, well, cooperate ...
+ */
+void
+pciio_error_register(devfs_handle_t pconn,
+		     error_handler_f *efunc,
+		     error_handler_arg_t einfo)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = pciio_info_get(pconn);
+    ASSERT(pciio_info != NULL);
+    pciio_info->c_efunc = efunc;
+    pciio_info->c_einfo = einfo;
+}
+
+/*
+ * Check if any device has been found in this slot, and return
+ * true or false
+ * vhdl is the vertex for the slot
+ */
+int
+pciio_slot_inuse(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+    if (pciio_info->c_vendor) {
+	/*
+	 * Non-zero value for vendor indicate
+	 * a board being found in this slot.
+	 */
+	return 1;
+    }
+    return 0;
+}
+
+int
+pciio_dma_enabled(devfs_handle_t pconn_vhdl)
+{
+	return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl);
+}
+
+/*
+ * These are complementary Linux interfaces that takes in a pci_dev * as the 
+ * first arguement instead of devfs_handle_t.
+ */
+iopaddr_t               snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned);
+pciio_dmamap_t          snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned);
+void                    snia_pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+void                    snia_pciio_dmamap_done(pciio_dmamap_t);
+pciio_endian_t          snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end,
+					      pciio_endian_t desired_end);
+
+#include <linux/module.h>
+EXPORT_SYMBOL(snia_pciio_dmatrans_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_alloc);
+EXPORT_SYMBOL(snia_pciio_dmamap_free);
+EXPORT_SYMBOL(snia_pciio_dmamap_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_done);
+EXPORT_SYMBOL(snia_pciio_endian_set);
+
+int
+snia_pcibr_rrb_alloc(struct pci_dev *pci_dev,
+	int *count_vchan0,
+	int *count_vchan1)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+	return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1);
+}
+EXPORT_SYMBOL(snia_pcibr_rrb_alloc);
+
+pciio_endian_t
+snia_pciio_endian_set(struct pci_dev *pci_dev,
+	pciio_endian_t device_end,
+	pciio_endian_t desired_end)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+	
+	return DEV_FUNC(dev, endian_set)
+		(dev, device_end, desired_end);
+}
+
+iopaddr_t
+snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */
+                    device_desc_t dev_desc,     /* device descriptor */
+                    paddr_t paddr,      /* system physical address */
+                    size_t byte_count,  /* length */
+                    unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    return DEV_FUNC(dev, dmatrans_addr)
+        (dev, dev_desc, paddr, byte_count, flags);
+}
+
+pciio_dmamap_t
+snia_pciio_dmamap_alloc(struct pci_dev *pci_dev,  /* set up mappings for this device */
+                   device_desc_t dev_desc,      /* device descriptor */
+                   size_t byte_count_max,       /* max size of a mapping */
+                   unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+        (dev, dev_desc, byte_count_max, flags);
+}
+
+void
+snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,  /* use these mapping resources */
+                  paddr_t paddr,        /* map for this address */
+                  size_t byte_count)
+{                                       /* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+        (CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+void
+snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/sgi_io_init.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/sgi_io_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/sgi_io_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/sgi_io_init.c	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,324 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pciba.h>
+#include <linux/smp.h>
+
+extern void mlreset(int );
+extern int init_hcl(void);
+extern void klgraph_hack_init(void);
+extern void hubspc_init(void);
+extern void pciio_init(void);
+extern void pcibr_init(void);
+extern void xtalk_init(void);
+extern void xbow_init(void);
+extern void xbmon_init(void);
+extern void pciiox_init(void);
+extern void usrpci_init(void);
+extern void ioc3_init(void);
+extern void initialize_io(void);
+extern void intr_clear_all(nasid_t);
+extern void klhwg_add_all_modules(devfs_handle_t);
+extern void klhwg_add_all_nodes(devfs_handle_t);
+
+void sn_mp_setup(void);
+extern devfs_handle_t hwgraph_root;
+extern void io_module_init(void);
+extern void pci_bus_cvlink_init(void);
+extern void temp_hack(void);
+
+extern int pci_bus_to_hcl_cvlink(void);
+
+/* #define DEBUG_IO_INIT 1 */
+#ifdef DEBUG_IO_INIT
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_IO_INIT */
+
+/*
+ * per_hub_init
+ *
+ * 	This code is executed once for each Hub chip.
+ */
+static void
+per_hub_init(cnodeid_t cnode)
+{
+	nasid_t		nasid;
+	nodepda_t	*npdap;
+	ii_icmr_u_t	ii_icmr;
+	ii_ibcr_u_t	ii_ibcr;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+	ASSERT(nasid != INVALID_NASID);
+	ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode);
+
+	npdap = NODEPDA(cnode);
+
+	/* initialize per-node synergy perf instrumentation */
+	npdap->synergy_perf_enabled = 0; /* off by default */
+	npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED;
+	npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT;
+	npdap->synergy_inactive_intervals = 0;
+	npdap->synergy_active_intervals = 0;
+	npdap->synergy_perf_data = NULL;
+	npdap->synergy_perf_first = NULL;
+
+
+	/*
+	 * Set the total number of CRBs that can be used.
+	 */
+	ii_icmr.ii_icmr_regval= 0x0;
+	ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF;
+	REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval);
+
+	/*
+	 * Set the number of CRBs that both of the BTEs combined
+	 * can use minus 1.
+	 */
+	ii_ibcr.ii_ibcr_regval= 0x0;
+	ii_ibcr.ii_ibcr_fld_s.i_count = 0x8;
+	REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval);
+
+	/*
+	 * Set CRB timeout to be 10ms.
+	 */
+	REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 );
+	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
+
+
+	/* Reserve all of the hardwired interrupt levels. */
+	intr_reserve_hardwired(cnode);
+
+	/* Initialize error interrupts for this hub. */
+	hub_error_init(cnode);
+}
+
+/*
+ * This routine is responsible for the setup of all the IRIX hwgraph style
+ * stuff that's been pulled into linux.  It's called by sn_pci_find_bios which
+ * is called just before the generic Linux PCI layer does its probing (by 
+ * platform_pci_fixup aka sn_pci_fixup).
+ *
+ * It is very IMPORTANT that this call is only made by the Master CPU!
+ *
+ */
+
+void
+sgi_master_io_infr_init(void)
+{
+	int cnode;
+
+	/*
+	 * Do any early init stuff .. einit_tbl[] etc.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling init_hcl().\n");
+	init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */
+
+#ifdef Colin
+
+printk("Testing out Xbridge Access .. if it hangs Xbridge is not init yet.\n");
+printk("	Reading Xbridge WID at address 0xc00000080f000000 0x%p\n", (* (volatile uint32_t *)(0xc00000080f000000)));
+
+printk("Testing out PCI Address Space Accesses\n");
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020000 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020000)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020001 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020001)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020002 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020002)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020003 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020003)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020004)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020005 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020005)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020006 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020006)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020007 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020007)));
+
+printk("	Testing PCI Config Word: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020004)));
+
+printk("	Testing PCI Config Word: address 0xc00000080f020008 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020008)));
+
+#endif
+
+	/*
+	 * initialize the Linux PCI to xwidget vertexes ..
+	 */
+	DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n");
+	pci_bus_cvlink_init();
+
+#ifdef BRINGUP
+	/*
+	 * Hack to provide statically initialzed klgraph entries.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n");
+	klgraph_hack_init();
+#endif /* BRINGUP */
+
+	/*
+	 * This is the Master CPU.  Emulate mlsetup and main.c in Irix.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n");
+	mlreset(0); /* Master .. */
+
+	/*
+	 * allowboot() is called by kern/os/main.c in main()
+	 * Emulate allowboot() ...
+	 *   per_cpu_init() - only need per_hub_init()
+	 *   cpu_io_setup() - Nothing to do.
+	 * 
+	 */
+	DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n");
+	sn_mp_setup();
+
+	DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n");
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		per_hub_init(cnode);
+	}
+
+	/* We can do headless hub cnodes here .. */
+
+	/*
+	 * io_init[] stuff.
+	 *
+	 * Get SGI IO Infrastructure drivers to init and register with 
+	 * each other etc.
+	 */
+
+	DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n");
+	hubspc_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pciio_init()\n");
+	pciio_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n");
+	pcibr_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n");
+	xtalk_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xbow_init()\n");
+	xbow_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n");
+	xbmon_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n");
+	pciiox_init();
+
+	DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n");
+	usrpci_init();
+
+	DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n");
+	ioc3_init();
+
+	/*
+	 *
+	 * Our IO Infrastructure drivers are in place .. 
+	 * Initialize the whole IO Infrastructure .. xwidget/device probes.
+	 *
+	 */
+	DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n");
+	initialize_io();
+
+	DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n");
+	pci_bus_to_hcl_cvlink();
+
+#ifdef CONFIG_PCIBA
+	DBG("--> sgi_master_io_infr_init: calling pciba_init()\n");
+ 	pciba_init();
+#endif
+
+	DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n");
+}
+
+/*
+ * sgi_slave_io_infr_init - This routine must be called on all cpus except 
+ * the Master CPU.
+ */
+void
+sgi_slave_io_infr_init(void)
+{
+	/* Emulate cboot() .. */
+	mlreset(1); /* This is a slave cpu */
+
+	// per_hub_init(0); /* Need to get and send in actual cnode number */
+
+	/* Done */
+}
+
+/*
+ * One-time setup for MP SN.
+ * Allocate per-node data, slurp prom klconfig information and
+ * convert it to hwgraph information.
+ */
+void
+sn_mp_setup(void)
+{
+	cnodeid_t	cnode;
+	cpuid_t		cpu;
+
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		/* Skip holes in CPU space */
+		if (cpu_enabled(cpu)) {
+			init_platform_pda(cpu);
+		}
+	}
+
+	/*
+	 * Initialize platform-dependent vertices in the hwgraph:
+	 *	module
+	 *	node
+	 *	cpu
+	 *	memory
+	 *	slot
+	 *	hub
+	 *	router
+	 *	xbow
+	 */
+
+	DBG("sn_mp_io_setup: calling io_module_init()\n");
+	io_module_init(); /* Use to be called module_init() .. */
+
+	DBG("sn_mp_setup: calling klhwg_add_all_modules()\n");
+	klhwg_add_all_modules(hwgraph_root);
+	DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n");
+	klhwg_add_all_nodes(hwgraph_root);
+
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+
+		/*
+		 * This routine clears the Hub's Interrupt registers.
+		 */
+		/*
+		 * We need to move this intr_clear_all() routine 
+		 * from SN/intr.c to a more appropriate file.
+		 * Talk to Al Mayer.
+		 */
+                intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
+		/* now init the hub */
+	//	per_hub_init(cnode);
+
+	}
+
+	synergy_perf_init();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/xbow.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/xbow.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/xbow.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/xbow.c	2003-05-22 22:06:46.000000000 +0000
@@ -0,0 +1,1086 @@
+/* $Id: xbow.c,v 1.3 2002/11/21 17:51:57 jh Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/simulator.h>
+
+/* #define DEBUG		1 */
+/* #define XBOW_DEBUG	1 */
+
+
+/*
+ * Files needed to get the device driver entry points
+ */
+
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+
+#include <asm/sn/prio.h>
+#include <asm/sn/hcl_util.h>
+
+
+#define NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DEL(ptr)	(kfree(ptr))
+
+int                     xbow_devflag = D_MP;
+
+/*
+ * This file supports the Xbow chip.  Main functions: initializtion,
+ * error handling, and GBR.
+ */
+
+/*
+ * each vertex corresponding to an xbow chip
+ * has a "fastinfo" pointer pointing at one
+ * of these things.
+ */
+typedef struct xbow_soft_s *xbow_soft_t;
+
+struct xbow_soft_s {
+    devfs_handle_t            conn;	/* our connection point */
+    devfs_handle_t            vhdl;	/* xbow's private vertex */
+    devfs_handle_t            busv;	/* the xswitch vertex */
+    xbow_t                 *base;	/* PIO pointer to crossbow chip */
+    char                   *name;	/* hwgraph name */
+
+    xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
+    xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
+    xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
+    spinlock_t              xbow_perf_lock;
+    int                     link_monitor;
+    widget_cfg_t	   *wpio[MAX_XBOW_PORTS];	/* cached PIO pointer */
+
+    /* Bandwidth allocation state. Bandwidth values are for the
+     * destination port since contention happens there.
+     * Implicit mapping from xbow ports (8..f) -> (0..7) array indices.
+     */
+    spinlock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
+    unsigned long long	    bw_hiwm[MAX_XBOW_PORTS];	/* hiwater mark values */
+    unsigned long long      bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */
+};
+
+#define xbow_soft_set(v,i)	hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))
+#define xbow_soft_get(v)	((xbow_soft_t)hwgraph_fastinfo_get((v)))
+
+/*
+ * Function Table of Contents
+ */
+
+void                    xbow_mlreset(xbow_t *);
+void                    xbow_init(void);
+int                     xbow_attach(devfs_handle_t);
+
+int                     xbow_open(devfs_handle_t *, int, int, cred_t *);
+int                     xbow_close(devfs_handle_t, int, int, cred_t *);
+
+int                     xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
+int                     xbow_unmap(devfs_handle_t, vhandl_t *);
+int                     xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
+
+int                     xbow_widget_present(xbow_t *, int);
+static int              xbow_link_alive(xbow_t *, int);
+devfs_handle_t            xbow_widget_lookup(devfs_handle_t, int);
+
+void                    xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
+
+
+
+void                    xbow_update_perf_counters(devfs_handle_t);
+xbow_perf_link_t       *xbow_get_perf_counters(devfs_handle_t);
+int                     xbow_enable_perf_counter(devfs_handle_t, int, int, int);
+xbow_link_status_t     *xbow_get_llp_status(devfs_handle_t);
+void                    xbow_update_llp_status(devfs_handle_t);
+
+int                     xbow_disable_llp_monitor(devfs_handle_t);
+int                     xbow_enable_llp_monitor(devfs_handle_t);
+int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
+                                unsigned long long, unsigned long long);
+
+xswitch_reset_link_f    xbow_reset_link;
+
+void                    idbg_xbowregs(int64_t);
+
+xswitch_provider_t      xbow_provider =
+{
+    xbow_reset_link,
+};
+
+/*
+ *    xbow_mlreset: called at mlreset time if the
+ *      platform specific code determines that there is
+ *      a crossbow in a critical path that must be
+ *      functional before the driver would normally get
+ *      the device properly set up.
+ *
+ *      what do we need to do, that the boot prom can
+ *      not be counted on to have already done, that is
+ *      generic across all platforms using crossbows?
+ */
+/*ARGSUSED */
+void
+xbow_mlreset(xbow_t * xbow)
+{
+}
+
+/*
+ *    xbow_init: called with the rest of the device
+ *      driver XXX_init routines. This platform *might*
+ *      have a Crossbow chip, or even several, but it
+ *      might have none. Register with the crosstalk
+ *      generic provider so when we encounter the chip
+ *      the right magic happens.
+ */
+void
+xbow_init(void)
+{
+
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_init\n");
+#endif
+
+    xwidget_driver_register(PXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+
+    xwidget_driver_register(XXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+    xwidget_driver_register(XBOW_WIDGET_PART_NUM,
+			    XBOW_WIDGET_MFGR_NUM,
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+}
+
+#ifdef XBRIDGE_REGS_SIM
+/*    xbow_set_simulated_regs: sets xbow regs as needed
+ *	for powering through the boot
+ */
+void
+xbow_set_simulated_regs(xbow_t *xbow, int port)
+{
+    /*
+     * turn on link
+     */
+    xbow->xb_link(port).link_status = (1<<31);
+    /*
+     * and give it a live widget too
+     */
+    xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT;
+    /*
+     * zero the link control reg
+     */
+    xbow->xb_link(port).link_control = 0x0;
+}
+#endif /* XBRIDGE_REGS_SIM */
+
+/*
+ *    xbow_attach: the crosstalk provider has
+ *      determined that there is a crossbow widget
+ *      present, and has handed us the connection
+ *      point for that vertex.
+ *
+ *      We not only add our own vertex, but add
+ *      some "xtalk switch" data to the switch
+ *      vertex (at the connect point's parent) if
+ *      it does not have any.
+ */
+
+/*ARGSUSED */
+int
+xbow_attach(devfs_handle_t conn)
+{
+    /*REFERENCED */
+    devfs_handle_t            vhdl;
+    devfs_handle_t            busv;
+    xbow_t                 *xbow;
+    xbow_soft_t             soft;
+    int                     port;
+    xswitch_info_t          info;
+    char                    devnm[MAXDEVNAME], *s;
+    xbowreg_t               id;
+    int                     rev;
+    int			    i;
+    int			    xbow_num;
+	
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: xbow_attach\n", conn);
+#else
+    printk("0x%x: xbow_attach\n", conn);
+#endif
+#endif
+
+    /*
+     * Get a PIO pointer to the base of the crossbow
+     * chip.
+     */
+#ifdef XBRIDGE_REGS_SIM
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t));
+    xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL);
+    /*
+     * turn on ports e and f like in a real live ibrick
+     */
+    xbow_set_simulated_regs(xbow, 0xe);
+    xbow_set_simulated_regs(xbow, 0xf);
+#else
+    xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0);
+#endif /* XBRIDGE_REGS_SIM */
+
+    /*
+     * Locate the "switch" vertex: it is the parent
+     * of our connection point.
+     */
+    busv = hwgraph_connectpt_get(conn);
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);
+#endif
+
+    ASSERT(busv != GRAPH_VERTEX_NONE);
+
+    /*
+     * Create our private vertex, and connect our
+     * driver information to it. This makes it possible
+     * for diagnostic drivers to open the crossbow
+     * vertex for access to registers.
+     */
+
+    /*
+     * We need to teach xbow drivers to provide the right set of
+     * file ops.
+     */
+    vhdl = NULL;
+    vhdl = hwgraph_register(conn, EDGE_LBL_XBOW,
+                        0, DEVFS_FL_AUTO_DEVNUM,
+                        0, 0,
+                        S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                        /* &hcl_fops */ (void *)&vhdl, NULL);
+    if (!vhdl) {
+        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
+                (void *)conn);
+    }
+
+    /*
+     * Allocate the soft state structure and attach
+     * it to the xbow's vertex
+     */
+    NEW(soft);
+    soft->conn = conn;
+    soft->vhdl = vhdl;
+    soft->busv = busv;
+    soft->base = xbow;
+    /* does the universe really need another macro?  */
+    /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */
+    hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft);
+
+#define XBOW_NUM_SUFFIX_FORMAT	"[xbow# %d]"
+
+    /* Add xbow number as a suffix to the hwgraph name of the xbow.
+     * This is helpful while looking at the error/warning messages.
+     */
+    xbow_num = 0;
+
+    /*
+     * get the name of this xbow vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(vhdl, devnm, MAXDEVNAME);
+    soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, 
+			    GFP_KERNEL);
+    sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num);
+
+#ifdef XBRIDGE_REGS_SIM
+    /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined
+     * as 0xd000, so I'm using that for the partnum bitfield.
+     */
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n");
+    id = 0x2d000049;
+#else
+    id = xbow->xb_wid_id;
+#endif /* XBRIDGE_REGS_SIM */
+    rev = XWIDGET_PART_REV_NUM(id);
+
+    mutex_spinlock_init(&soft->xbow_perf_lock);
+    soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
+    soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;
+
+    /* Initialization for GBR bw allocation */
+    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);
+
+#define	XBOW_8_BIT_PORT_BW_MAX		(400 * 1000 * 1000)	/* 400 MB/s */
+#define XBOW_16_BIT_PORT_BW_MAX		(800 * 1000 * 1000)	/* 800 MB/s */
+
+    /* Set bandwidth hiwatermark and current values */
+    for (i = 0; i < MAX_XBOW_PORTS; i++) {
+	soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX;	/* for now */
+	soft->bw_cur_used[i] = 0;
+    }
+
+    /*
+     * Enable xbow error interrupts
+     */
+    xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE);
+
+    /*
+     * take a census of the widgets present,
+     * leaving notes at the switch vertex.
+     */
+    info = xswitch_info_new(busv);
+
+    for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	 port < MAX_PORT_NUM; ++port) {
+	if (!xbow_link_alive(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is not alive\n",
+		    busv, port);
+#endif
+	    continue;
+	}
+	if (!xbow_widget_present(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port);
+#endif
+	    continue;
+	}
+#if DEBUG && XBOW_DEBUG
+	printk(KERN_INFO "0x%p link %d has a widget\n",
+		busv, port);
+#endif
+
+	xswitch_info_link_is_ok(info, port);
+	/*
+	 * Turn some error interrupts on
+	 * and turn others off. The PROM has
+	 * some things turned on we don't
+	 * want to see (bandwidth allocation
+	 * errors for instance); so if it
+	 * is not listed here, it is not on.
+	 */
+	xbow->xb_link(port).link_control =
+	    ( (xbow->xb_link(port).link_control
+	/*
+	 * Turn off these bits; they are non-fatal,
+	 * but we might want to save some statistics
+	 * on the frequency of these errors.
+	 * XXX FIXME XXX
+	 */
+	    & ~XB_CTRL_RCV_CNT_OFLOW_IE
+	    & ~XB_CTRL_XMT_CNT_OFLOW_IE
+	    & ~XB_CTRL_BNDWDTH_ALLOC_IE
+	    & ~XB_CTRL_RCV_IE)
+	/*
+	 * These are the ones we want to turn on.
+	 */
+	    | (XB_CTRL_ILLEGAL_DST_IE
+	    | XB_CTRL_OALLOC_IBUF_IE
+	    | XB_CTRL_XMT_MAX_RTRY_IE
+	    | XB_CTRL_MAXREQ_TOUT_IE
+	    | XB_CTRL_XMT_RTRY_IE
+	    | XB_CTRL_SRC_TOUT_IE) );
+    }
+
+    xswitch_provider_register(busv, &xbow_provider);
+
+    return 0;				/* attach successful */
+}
+
+/*ARGSUSED */
+int
+xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
+{
+    return 0;
+
+}
+
+/*ARGSUSED */
+int
+xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
+{
+    devfs_handle_t            vhdl = dev_to_vhdl(dev);
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    int                     error;
+
+    ASSERT(soft);
+    len = ctob(btoc(len));
+    /* XXX- this ignores the offset!!! */
+    error = v_mapphys(vt, (void *) soft->base, len);
+    return error;
+}
+
+/*ARGSUSED */
+int
+xbow_unmap(devfs_handle_t dev, vhandl_t *vt)
+{
+    return 0;
+}
+
+/* This contains special-case code for grio. There are plans to make
+ * this general sometime in the future, but till then this should
+ * be good enough.
+ */
+xwidgetnum_t
+xbow_widget_num_get(devfs_handle_t dev)
+{
+	devfs_handle_t	tdev;
+	char		devname[MAXDEVNAME];
+	xwidget_info_t	xwidget_info;
+	int		i;
+
+	vertex_to_name(dev, devname, MAXDEVNAME);
+
+	/* If this is a pci controller vertex, traverse up using
+	 * the ".." links to get to the widget.
+	 */
+	if (strstr(devname, EDGE_LBL_PCI) &&
+			strstr(devname, EDGE_LBL_CONTROLLER)) {
+		tdev = dev;
+		for (i=0; i< 2; i++) {
+			if (hwgraph_edge_get(tdev,
+				HWGRAPH_EDGELBL_DOTDOT, &tdev) !=
+					GRAPH_SUCCESS)
+				return XWIDGET_NONE;
+		}
+
+		if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) {
+			return (xwidget_info_id_get(xwidget_info));
+		} else {
+			return XWIDGET_NONE;
+		}
+	}
+
+	return XWIDGET_NONE;
+}
+
+int
+xbow_ioctl(devfs_handle_t dev,
+	   int cmd,
+	   void *arg,
+	   int flag,
+	   struct cred *cr,
+	   int *rvalp)
+{
+    devfs_handle_t            vhdl;
+    int                     error = 0;
+
+#if defined (DEBUG)
+    int                     rc;
+    devfs_handle_t            conn;
+    struct xwidget_info_s  *xwidget_info;
+    xbow_soft_t             xbow_soft;
+#endif
+    *rvalp = 0;
+
+    vhdl = dev_to_vhdl(dev);
+#if defined (DEBUG)
+    xbow_soft = xbow_soft_get(vhdl);
+    conn = xbow_soft->conn;
+
+    xwidget_info = xwidget_info_get(conn);
+    ASSERT_ALWAYS(xwidget_info != NULL);
+
+    rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid);
+    ASSERT_ALWAYS(rc != 0);
+#endif
+    switch (cmd) {
+
+    case XBOWIOC_LLP_ERROR_ENABLE:
+	if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    case XBOWIOC_LLP_ERROR_DISABLE:
+
+	if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    default:
+	break;
+
+    }
+    return error;
+}
+
+/*
+ * xbow_widget_present: See if a device is present
+ * on the specified port of this crossbow.
+ */
+int
+xbow_widget_present(xbow_t *xbow, int port)
+{
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		if ( (port == 14) || (port == 15) ) {
+			return 1;
+		}
+		else {
+			return 0;
+		}
+	}
+	else {
+		/* WAR: port 0xf on PIC is missing present bit */
+		/* Need this for PIC */
+		if (IS_PIC_XBOW(xbow->xb_wid_id) && port == 0xf) {
+			return 1;
+		}
+		return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT;
+	}
+}
+
+static int
+xbow_link_alive(xbow_t * xbow, int port)
+{
+    xbwX_stat_t             xbow_linkstat;
+
+    xbow_linkstat.linkstatus = xbow->xb_link(port).link_status;
+    return (xbow_linkstat.link_alive);
+}
+
+/*
+ * xbow_widget_lookup
+ *      Lookup the edges connected to the xbow specified, and
+ *      retrieve the handle corresponding to the widgetnum
+ *      specified.
+ *      If not found, return 0.
+ */
+devfs_handle_t
+xbow_widget_lookup(devfs_handle_t vhdl,
+		   int widgetnum)
+{
+    xswitch_info_t          xswitch_info;
+    devfs_handle_t            conn;
+
+    xswitch_info = xswitch_info_get(vhdl);
+    conn = xswitch_info_vhdl_get(xswitch_info, widgetnum);
+    return conn;
+}
+
+/*
+ * xbow_intr_preset: called during mlreset time
+ * if the platform specific code needs to route
+ * an xbow interrupt before the xtalk infrastructure
+ * is available for use.
+ *
+ * Also called from xbow_setwidint, so we don't
+ * replicate the guts of the routine.
+ *
+ * XXX- probably should be renamed xbow_wid_intr_set or
+ * something to reduce confusion.
+ */
+/*ARGSUSED3 */
+void
+xbow_intr_preset(void *which_widget,
+		 int which_widget_intr,
+		 xwidgetnum_t targ,
+		 iopaddr_t addr,
+		 xtalk_intr_vector_t vect)
+{
+    xbow_t                 *xbow = (xbow_t *) which_widget;
+
+    xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) |
+			      (0x000F0000 & (targ << 16)) |
+			      XTALK_ADDR_TO_UPPER(addr));
+    xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
+
+}
+
+int                     xbow_xmit_retry_errors = 0;
+
+int
+xbow_xmit_retry_error(xbow_soft_t soft,
+		      int port)
+{
+    xswitch_info_t          info;
+    devfs_handle_t            vhdl;
+    widget_cfg_t           *wid;
+    widgetreg_t             id;
+    int                     part;
+    int                     mfgr;
+
+    wid = soft->wpio[port - BASE_XBOW_PORT];
+    if (wid == NULL) {
+	/* If we can't track down a PIO
+	 * pointer to our widget yet,
+	 * leave our caller knowing that
+	 * we are interested in this
+	 * interrupt if it occurs in
+	 * the future.
+	 */
+	info = xswitch_info_get(soft->busv);
+	if (!info)
+	    return 1;
+	vhdl = xswitch_info_vhdl_get(info, port);
+	if (vhdl == GRAPH_VERTEX_NONE)
+	    return 1;
+	wid = (widget_cfg_t *) xtalk_piotrans_addr
+	    (vhdl, 0, 0, sizeof *wid, 0);
+	if (!wid)
+	    return 1;
+	soft->wpio[port - BASE_XBOW_PORT] = wid;
+    }
+    id = wid->w_id;
+    part = XWIDGET_PART_NUM(id);
+    mfgr = XWIDGET_MFG_NUM(id);
+
+    /* If this thing is not a Bridge,
+     * do not activate the WAR, and
+     * tell our caller we do not need
+     * to be called again.
+     */
+    if ((part != BRIDGE_WIDGET_PART_NUM) ||
+	(mfgr != BRIDGE_WIDGET_MFGR_NUM)) {
+		/* FIXME: add Xbridge to the WAR.
+		 * Shouldn't hurt anything.  Later need to
+		 * check if we can remove this.
+                 */
+    		if ((part != XBRIDGE_WIDGET_PART_NUM) ||
+		    (mfgr != XBRIDGE_WIDGET_MFGR_NUM))
+			return 0;
+    }
+
+    /* count how many times we
+     * have picked up after
+     * LLP Transmit problems.
+     */
+    xbow_xmit_retry_errors++;
+
+    /* rewrite the control register
+     * to fix things up.
+     */
+    wid->w_control = wid->w_control;
+    wid->w_control;
+
+    return 1;
+}
+
+void
+xbow_update_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     link, i;
+
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
+	if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
+	    continue;
+
+	s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+	perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+
+	link = perf_reg.xb_perf.link_select;
+
+	(xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] +=
+	    ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK);
+	xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    }
+}
+
+xbow_perf_link_t       *
+xbow_get_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_link_t       *xbow_perf_link = xbow_soft->xbow_perflink;
+
+    return xbow_perf_link;
+}
+
+int
+xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_linkctrl_t         xbow_link_ctrl;
+    xbow_t                 *xbow = xbow_soft->base;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     i;
+
+    link -= BASE_XBOW_PORT;
+    if ((link < 0) || (link >= MAX_XBOW_PORTS))
+	return -1;
+
+    if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK))
+	return -1;
+
+    if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS))
+	return -1;
+
+    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+    if ((xbow_perf + counter)->xp_mode && mode) {
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	return -1;
+    }
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++) {
+	if (i == counter)
+	    continue;
+	if (((xbow_perf + i)->xp_link == link) &&
+	    ((xbow_perf + i)->xp_mode)) {
+	    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	    return -1;
+	}
+    }
+    xbow_perf += counter;
+
+    xbow_perf->xp_curlink = xbow_perf->xp_link = link;
+    xbow_perf->xp_curmode = xbow_perf->xp_mode = mode;
+
+    xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control;
+    xbow_link_ctrl.xb_linkcontrol.perf_mode = mode;
+    xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword;
+
+    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+    perf_reg.xb_perf.link_select = link;
+    *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
+    xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    return 0;
+}
+
+xbow_link_status_t     *
+xbow_get_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+
+    return xbow_llp_status;
+}
+
+void
+xbow_update_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+    xbow_t                 *xbow;
+    xbwX_stat_t             lnk_sts;
+    xbow_aux_link_status_t  aux_sts;
+    int                     link;
+    devfs_handle_t	    xwidget_vhdl;
+    char		   *xwidget_name;	
+
+    xbow = (xbow_t *) xbow_soft->base;
+    for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) {
+	/* Get the widget name corresponding the current link.
+	 * Note : 0 <= link < MAX_XBOW_PORTS(8).
+	 * 	  BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10)
+	 */
+	xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT);
+	xwidget_name = xwidget_name_get(xwidget_vhdl);
+	aux_sts.aux_linkstatus
+	    = xbow->xb_link_raw[link].link_aux_status;
+	lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr;
+
+	if (lnk_sts.link_alive == 0)
+	    continue;
+
+	xbow_llp_status->rx_err_count +=
+	    aux_sts.xb_aux_linkstatus.rx_err_cnt;
+
+	xbow_llp_status->tx_retry_count +=
+	    aux_sts.xb_aux_linkstatus.tx_retry_cnt;
+
+	if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
+#ifdef	LATER
+	    printk(KERN_WARNING  "link %d[%s]: bad status 0x%x\n",
+		    link, xwidget_name, lnk_sts.linkstatus);
+#endif
+	}
+    }
+}
+
+int
+xbow_disable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    int                     port;
+
+    for (port = 0; port < MAX_XBOW_PORTS; port++) {
+	xbow_soft->xbow_link_status[port].rx_err_count = 0;
+	xbow_soft->xbow_link_status[port].tx_retry_count = 0;
+    }
+
+    xbow_soft->link_monitor = 0;
+    return 0;
+}
+
+int
+xbow_enable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+
+    xbow_soft->link_monitor = 1;
+    return 0;
+}
+
+
+int
+xbow_reset_link(devfs_handle_t xconn_vhdl)
+{
+    xwidget_info_t          widget_info;
+    xwidgetnum_t            port;
+    xbow_t                 *xbow;
+    xbowreg_t               ctrl;
+    xbwX_stat_t             stat;
+    unsigned                itick;
+    unsigned                dtick;
+    static int              ticks_per_ms = 0;
+
+    if (!ticks_per_ms) {
+	itick = get_timestamp();
+	us_delay(1000);
+	ticks_per_ms = get_timestamp() - itick;
+    }
+    widget_info = xwidget_info_get(xconn_vhdl);
+    port = xwidget_info_id_get(widget_info);
+
+#ifdef XBOW_K1PTR			/* defined if we only have one xbow ... */
+    xbow = XBOW_K1PTR;
+#else
+    {
+	devfs_handle_t            xbow_vhdl;
+	xbow_soft_t             xbow_soft;
+
+	hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl);
+	xbow_soft = xbow_soft_get(xbow_vhdl);
+	xbow = xbow_soft->base;
+    }
+#endif
+
+    /*
+     * This requires three PIOs (reset the link, check for the
+     * reset, restore the control register for the link) plus
+     * 10us to wait for the reset. We allow up to 1ms for the
+     * widget to come out of reset before giving up and
+     * returning a failure.
+     */
+    ctrl = xbow->xb_link(port).link_control;
+    xbow->xb_link(port).link_reset = 0;
+    itick = get_timestamp();
+    while (1) {
+	stat.linkstatus = xbow->xb_link(port).link_status;
+	if (stat.link_alive)
+	    break;
+	dtick = get_timestamp() - itick;
+	if (dtick > ticks_per_ms) {
+	    return -1;			/* never came out of reset */
+	}
+	DELAY(2);			/* don't beat on link_status */
+    }
+    xbow->xb_link(port).link_control = ctrl;
+    return 0;
+}
+
+/*
+ * Dump xbow registers.
+ * input parameter is either a pointer to
+ * the xbow chip or the vertex handle for
+ * an xbow vertex.
+ */
+void
+idbg_xbowregs(int64_t regs)
+{
+    xbow_t                 *xbow;
+    int                     i;
+    xb_linkregs_t          *link;
+
+    xbow = (xbow_t *) regs;
+
+#ifdef LATER
+    qprintf("Printing xbow registers starting at 0x%x\n", xbow);
+    qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
+	    xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
+	    xbow->xb_wid_err_lower, xbow->xb_wid_control,
+	    xbow->xb_wid_req_timeout);
+    qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n",
+	    xbow->xb_wid_int_upper, xbow->xb_wid_int_lower,
+	    xbow->xb_wid_err_cmdword, xbow->xb_wid_llp,
+	    xbow->xb_wid_arb_reload);
+#endif
+
+    for (i = 8; i <= 0xf; i++) {
+	link = &xbow->xb_link(i);
+#ifdef LATER
+	qprintf("Link %d registers\n", i);
+	qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
+		link->link_control, link->link_status,
+		link->link_arb_upper, link->link_arb_lower,
+		link->link_aux_status);
+#endif
+    }
+}
+
+
+#define XBOW_ARB_RELOAD_TICKS		25
+					/* granularity: 4 MB/s, max: 124 MB/s */
+#define GRANULARITY			((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)
+
+#define XBOW_BYTES_TO_GBR(BYTES_per_s)	(int) (BYTES_per_s / GRANULARITY)
+
+#define XBOW_GBR_TO_BYTES(cnt)		(bandwidth_t) ((cnt) * GRANULARITY)
+
+#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec)	\
+			((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)
+
+#define XBOW_ARB_GBR_MAX		31
+
+#define ABS(x)				((x > 0) ? (x) : (-1 * x))
+					/* absolute value */
+
+int
+xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec)
+{
+    int                     gbr_granted;
+    int                     new_total_gbr;
+    int                     change_gbr;
+    bandwidth_t             new_total_bw;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n",
+		old_bytes_per_sec, bytes_per_sec);
+#endif	/* GRIO_DEBUG */
+
+    gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)),
+			old_bytes_per_sec);
+    new_total_bw = old_bytes_per_sec + bytes_per_sec;
+    new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)),
+			new_total_bw);
+
+    change_gbr = new_total_gbr - gbr_granted;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n",
+		gbr_granted, new_total_gbr, change_gbr);
+#endif	/* GRIO_DEBUG */
+
+    return (change_gbr);
+}
+
+/* Conversion from GBR to bytes */
+bandwidth_t
+xbow_gbr_to_bytes(int gbr)
+{
+    return (XBOW_GBR_TO_BYTES(gbr));
+}
+
+/* Given the vhdl for the desired xbow, the src and dest. widget ids
+ * and the req_bw value, this xbow driver entry point accesses the
+ * xbow registers and allocates the desired bandwidth if available.
+ *
+ * If bandwidth allocation is successful, return success else return failure.
+ */
+int
+xbow_prio_bw_alloc(devfs_handle_t vhdl,
+		xwidgetnum_t src_wid,
+		xwidgetnum_t dest_wid,
+		unsigned long long old_alloc_bw,
+		unsigned long long req_bw)
+{
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    volatile xbowreg_t     *xreg;
+    xbowreg_t               mask;
+    unsigned long           s;
+    int                     error = 0;
+    bandwidth_t             old_bw_BYTES, req_bw_BYTES;
+    xbowreg_t               old_xreg;
+    int                     old_bw_GBR, req_bw_GBR, new_bw_GBR;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n",
+		(int) vhdl, (int) src_wid, (int) dest_wid, req_bw);
+#endif
+
+    ASSERT(XBOW_WIDGET_IS_VALID(src_wid));
+    ASSERT(XBOW_WIDGET_IS_VALID(dest_wid));
+
+    s = mutex_spinlock(&soft->xbow_bw_alloc_lock);
+
+    /* Get pointer to the correct register */
+    xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid);
+
+    /* Get mask for GBR count value */
+    mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid);
+
+    req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw);
+    req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR)))
+		: xbow_gbr_to_bytes(req_bw_GBR);
+
+#ifdef GRIO_DEBUG
+    printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n",
+		req_bw, req_bw_BYTES, req_bw_GBR);
+#endif	/* GRIO_DEBUG */
+
+    old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS];
+    old_xreg = *xreg;
+    old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));
+
+#ifdef GRIO_DEBUG
+    ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR);
+
+    printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR);
+
+    printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n",
+		req_bw_BYTES, old_bw_BYTES,
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]);
+	   
+#endif				/* GRIO_DEBUG */
+
+    /* Accept the request only if we don't exceed the destination
+     * port HIWATER_MARK *AND* the max. link GBR arbitration count
+     */
+    if (((old_bw_BYTES + req_bw_BYTES) <=
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) &&
+		(req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) {
+
+	new_bw_GBR = (old_bw_GBR + req_bw_GBR);
+
+	/* Set this in the xbow link register */
+	*xreg = (old_xreg & ~mask) | \
+	    (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask);
+
+	soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] =
+			xbow_gbr_to_bytes(new_bw_GBR);
+    } else {
+	error = 1;
+    }
+
+    mutex_spinunlock(&soft->xbow_bw_alloc_lock, s);
+
+    return (error);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/xtalk.c linux-2.4.21-rc3/arch/ia64/sn/io/sn1/xtalk.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/xtalk.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn1/xtalk.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,1003 @@
+/* $Id: xtalk.c,v 1.2 2002/11/21 17:51:57 jh Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+
+/*
+ * Implement crosstalk provider operations.  The xtalk* layer provides a
+ * platform-independent interface for crosstalk devices.  This layer
+ * switches among the possible implementations of a crosstalk adapter.
+ *
+ * On platforms with only one possible xtalk provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+#define	NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define	DEL(ptr)	(kfree(ptr))
+
+char                    widget_info_fingerprint[] = "widget_info";
+
+cdl_p                   xtalk_registry = NULL;
+
+#define	DEV_FUNC(dev,func)	hub_##func
+#define	CAST_PIOMAP(x)		((hub_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((hub_dmamap_t)(x))
+#define	CAST_INTR(x)		((hub_intr_t)(x))
+
+/* =====================================================================
+ *            Function Table of Contents
+ */
+xtalk_piomap_t          xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned);
+void                    xtalk_piomap_free(xtalk_piomap_t);
+caddr_t                 xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t);
+void                    xtalk_piomap_done(xtalk_piomap_t);
+caddr_t                 xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned);
+caddr_t                 xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned);
+void                    xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *);
+caddr_t                 xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+static caddr_t          null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+xtalk_dmamap_t          xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    xtalk_dmamap_free(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t);
+alenlist_t              xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned);
+void                    xtalk_dmamap_done(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			xtalk_dmamap_drain(xtalk_dmamap_t);
+void			xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t);
+void			xtalk_dmalist_drain(devfs_handle_t, alenlist_t);
+xtalk_intr_t            xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t);
+xtalk_intr_t            xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t);
+void                    xtalk_intr_free(xtalk_intr_t);
+int                     xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *);
+void                    xtalk_intr_disconnect(xtalk_intr_t);
+devfs_handle_t            xtalk_intr_cpu_get(xtalk_intr_t);
+int                     xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);
+int                     xtalk_error_devenable(devfs_handle_t, int, int);
+void                    xtalk_provider_startup(devfs_handle_t);
+void                    xtalk_provider_shutdown(devfs_handle_t);
+devfs_handle_t            xtalk_intr_dev_get(xtalk_intr_t);
+xwidgetnum_t            xtalk_intr_target_get(xtalk_intr_t);
+xtalk_intr_vector_t     xtalk_intr_vector_get(xtalk_intr_t);
+iopaddr_t               xtalk_intr_addr_get(struct xtalk_intr_s *);
+void                   *xtalk_intr_sfarg_get(xtalk_intr_t);
+devfs_handle_t            xtalk_pio_dev_get(xtalk_piomap_t);
+xwidgetnum_t            xtalk_pio_target_get(xtalk_piomap_t);
+iopaddr_t               xtalk_pio_xtalk_addr_get(xtalk_piomap_t);
+ulong                   xtalk_pio_mapsz_get(xtalk_piomap_t);
+caddr_t                 xtalk_pio_kvaddr_get(xtalk_piomap_t);
+devfs_handle_t            xtalk_dma_dev_get(xtalk_dmamap_t);
+xwidgetnum_t            xtalk_dma_target_get(xtalk_dmamap_t);
+xwidget_info_t          xwidget_info_chk(devfs_handle_t);
+xwidget_info_t          xwidget_info_get(devfs_handle_t);
+void                    xwidget_info_set(devfs_handle_t, xwidget_info_t);
+devfs_handle_t            xwidget_info_dev_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_id_get(xwidget_info_t);
+devfs_handle_t            xwidget_info_master_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_masterid_get(xwidget_info_t);
+xwidget_part_num_t      xwidget_info_part_num_get(xwidget_info_t);
+xwidget_mfg_num_t       xwidget_info_mfg_num_get(xwidget_info_t);
+char 			*xwidget_info_name_get(xwidget_info_t);
+void                    xtalk_init(void);
+void                    xtalk_provider_register(devfs_handle_t, xtalk_provider_t *);
+void                    xtalk_provider_unregister(devfs_handle_t);
+xtalk_provider_t       *xtalk_provider_fns_get(devfs_handle_t);
+int                     xwidget_driver_register(xwidget_part_num_t, 
+						xwidget_mfg_num_t, 
+						char *, unsigned);
+void                    xwidget_driver_unregister(char *);
+int                     xwidget_register(xwidget_hwid_t, devfs_handle_t, 
+					 xwidgetnum_t, devfs_handle_t, 
+					 xwidgetnum_t, async_attach_t);
+int			xwidget_unregister(devfs_handle_t);
+void                    xwidget_reset(devfs_handle_t);
+char			*xwidget_name_get(devfs_handle_t);
+#if !defined(DEV_FUNC)
+/*
+ * There is more than one possible provider
+ * for this platform. We need to examine the
+ * master vertex of the current vertex for
+ * a provider function structure, and indirect
+ * through the appropriately named member.
+ */
+#define	DEV_FUNC(dev,func)	xwidget_to_provider_fns(dev)->func
+#define	CAST_PIOMAP(x)		((xtalk_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((xtalk_dmamap_t)(x))
+#define	CAST_INTR(x)		((xtalk_intr_t)(x))
+
+static xtalk_provider_t *
+xwidget_to_provider_fns(devfs_handle_t xconn)
+{
+    xwidget_info_t          widget_info;
+    xtalk_provider_t       *provider_fns;
+
+    widget_info = xwidget_info_get(xconn);
+    ASSERT(widget_info != NULL);
+
+    provider_fns = xwidget_info_pops_get(widget_info);
+    ASSERT(provider_fns != NULL);
+
+    return (provider_fns);
+}
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define	PIOMAP_FUNC(map,func)	DEV_FUNC(map->xp_dev,func)
+#define	DMAMAP_FUNC(map,func)	DEV_FUNC(map->xd_dev,func)
+#define	INTR_FUNC(intr,func)	DEV_FUNC(intr_hdl->xi_dev,func)
+
+/* =====================================================================
+ *                    PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      xtalk space on a specified widget
+ */
+
+xtalk_piomap_t
+xtalk_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   iopaddr_t xtalk_addr,	/* map for this xtalk_addr range */
+		   size_t byte_count,
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{				/* defined in sys/pio.h */
+    return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags);
+}
+
+
+void
+xtalk_piomap_free(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_free)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap,	/* mapping resources */
+		  iopaddr_t xtalk_addr,		/* map for this xtalk address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return PIOMAP_FUNC(xtalk_piomap, piomap_addr)
+	(CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count);
+}
+
+
+void
+xtalk_piomap_done(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_done)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    iopaddr_t xtalk_addr,	/* Crosstalk address */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{				/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, xtalk_addr, byte_count, flags);
+}
+
+caddr_t
+xtalk_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       xtalk_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    xtalk_piomap_t          map = 0;
+    caddr_t                 res;
+
+    if (mapp)
+	*mapp = 0;			/* record "no map used" */
+
+    res = xtalk_piotrans_addr
+	(dev, dev_desc, addr, byte_count, flags);
+    if (res)
+	return res;			/* xtalk_piotrans worked */
+
+    map = xtalk_piomap_alloc
+	(dev, dev_desc, addr, byte_count, byte_count, flags);
+    if (!map)
+	return res;			/* xtalk_piomap_alloc failed */
+
+    res = xtalk_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	xtalk_piomap_free(map);
+	return res;			/* xtalk_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* xtalk_piomap_addr succeeded */
+}
+
+/* =====================================================================
+ *            EARLY PIOTRANS SUPPORT
+ *
+ *      There are places where drivers (mgras, for instance)
+ *      need to get PIO translations before the infrastructure
+ *      is extended to them (setting up textports, for
+ *      instance). These drivers should call
+ *      xtalk_early_piotrans_addr with their xtalk ID
+ *      information, a sequence number (so we can use the second
+ *      mgras for instance), and the usual piotrans parameters.
+ *
+ *      Machine specific code should provide an implementation
+ *      of early_piotrans_addr, and present a pointer to this
+ *      function to xtalk_set_early_piotrans_addr so it can be
+ *      used by clients without the clients having to know what
+ *      platform or what xtalk provider is in use.
+ */
+
+static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr;
+
+xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr;
+
+/* xtalk_set_early_piotrans_addr:
+ * specify the early_piotrans_addr implementation function.
+ */
+void
+xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl)
+{
+    impl_early_piotrans_addr = impl;
+}
+
+/* xtalk_early_piotrans_addr:
+ * figure out a PIO address for the "nth" crosstalk widget that
+ * matches the specified part and mfgr number. Returns NULL if
+ * there is no such widget, or if the requested mapping can not
+ * be constructed.
+ * Limitations on which crosstalk slots (and busses) are
+ * checked, and definitions of the ordering of the search across
+ * the crosstalk slots, are defined by the platform.
+ */
+caddr_t
+xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			  xwidget_mfg_num_t mfg_num,
+			  int which,
+			  iopaddr_t xtalk_addr,
+			  size_t byte_count,
+			  unsigned flags)
+{
+    return impl_early_piotrans_addr
+	(part_num, mfg_num, which, xtalk_addr, byte_count, flags);
+}
+
+/* null_xtalk_early_piotrans_addr:
+ * used as the early_piotrans_addr implementation until and
+ * unless a real implementation is provided. In DEBUG kernels,
+ * we want to know who is calling before the implementation is
+ * registered; in non-DEBUG kernels, return NULL representing
+ * lack of mapping support.
+ */
+/*ARGSUSED */
+static caddr_t
+null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			       xwidget_mfg_num_t mfg_num,
+			       int which,
+			       iopaddr_t xtalk_addr,
+			       size_t byte_count,
+			       unsigned flags)
+{
+#if DEBUG
+    PRINT_PANIC("null_xtalk_early_piotrans_addr");
+#endif
+    return NULL;
+}
+
+/* =====================================================================
+ *                    DMA MANAGEMENT
+ *
+ *      For mapping from crosstalk space to system
+ *      physical space.
+ */
+
+xtalk_dmamap_t
+xtalk_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{				/* defined in dma.h */
+    return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+
+void
+xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_free)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr)
+	(CAST_DMAMAP(xtalk_dmamap), paddr, byte_count);
+}
+
+
+alenlist_t
+xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_list)
+	(CAST_DMAMAP(xtalk_dmamap), alenlist, flags);
+}
+
+
+void
+xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_done)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+
+alenlist_t
+xtalk_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+void
+xtalk_dmamap_drain(xtalk_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *                    INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 devfs_handle_t owner_dev)
+{				/* owner of this interrupt */
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Unconditionally setup resources to be non-threaded.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc_nothd(devfs_handle_t dev,	/* which Crosstalk device */
+		 	device_desc_t dev_desc,	/* device descriptor */
+		 	devfs_handle_t owner_dev)	/* owner of this interrupt */
+{
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+xtalk_intr_free(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Associate resources allocated with a previous xtalk_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+xtalk_intr_connect(xtalk_intr_t intr_hdl,	/* xtalk intr resource handle */
+		   xtalk_intr_setfunc_t setfunc,	/* func to set intr hw */
+		   void *setfunc_arg)	/* arg to setfunc */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), setfunc, setfunc_arg);
+}
+
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+xtalk_intr_disconnect(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+xtalk_intr_cpu_get(xtalk_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/* =====================================================================
+ *                    CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+xtalk_provider_startup(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_startup)
+	(xtalk_provider);
+}
+
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+xtalk_provider_shutdown(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_shutdown)
+	(xtalk_provider);
+}
+
+/* 
+ * Enable a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum);
+}
+
+/* 
+ * Shutdown a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum);
+}
+
+int
+xtalk_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+    return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl);
+}
+/*
+ * Generic crosstalk functions, for use with all crosstalk providers
+ * and all crosstalk devices.
+ */
+
+/****** Generic crosstalk interrupt interfaces ******/
+devfs_handle_t
+xtalk_intr_dev_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_dev);
+}
+
+xwidgetnum_t
+xtalk_intr_target_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_target);
+}
+
+xtalk_intr_vector_t
+xtalk_intr_vector_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_vector);
+}
+
+iopaddr_t
+xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr)
+{
+    return (xtalk_intr->xi_addr);
+}
+
+void                   *
+xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_sfarg);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_dev);
+}
+
+xwidgetnum_t
+xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_target);
+}
+
+iopaddr_t
+xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_xtalk_addr);
+}
+
+ulong
+xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_mapsz);
+}
+
+caddr_t
+xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_kvaddr);
+}
+
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_dev);
+}
+
+xwidgetnum_t
+xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_target);
+}
+
+
+/****** Generic crosstalk widget information interfaces ******/
+
+/* xwidget_info_chk:
+ * check to see if this vertex is a widget;
+ * if so, return its widget_info (if any).
+ * if not, return NULL.
+ */
+xwidget_info_t
+xwidget_info_chk(devfs_handle_t xwidget)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo);
+    return (xwidget_info_t) ainfo;
+}
+
+
+xwidget_info_t
+xwidget_info_get(devfs_handle_t xwidget)
+{
+    xwidget_info_t          widget_info;
+
+    widget_info = (xwidget_info_t)
+	hwgraph_fastinfo_get(xwidget);
+
+#ifdef	LATER
+    if ((widget_info != NULL) &&
+	(widget_info->w_fingerprint != widget_info_fingerprint))
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v bad xwidget_info", xwidget);
+#else
+	PRINT_PANIC("%x bad xwidget_info", xwidget);
+#endif
+#endif	/* LATER */
+
+    return (widget_info);
+}
+
+void
+xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info)
+{
+    if (widget_info != NULL)
+	widget_info->w_fingerprint = widget_info_fingerprint;
+
+    hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info);
+
+    /* Also, mark this vertex as an xwidget,
+     * and use the widget_info, so xwidget_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET,
+			 (arbitrary_info_t) widget_info);
+}
+
+devfs_handle_t
+xwidget_info_dev_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_vertex);
+}
+
+xwidgetnum_t
+xwidget_info_id_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_id);
+}
+
+
+devfs_handle_t
+xwidget_info_master_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_master);
+}
+
+xwidgetnum_t
+xwidget_info_masterid_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_masterid);
+}
+
+xwidget_part_num_t
+xwidget_info_part_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.part_num);
+}
+
+xwidget_mfg_num_t
+xwidget_info_mfg_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.mfg_num);
+}
+/* Extract the widget name from the widget information
+ * for the xtalk widget.
+ */
+char *
+xwidget_info_name_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget info");
+    return(xwidget_info->w_name);
+}
+/****** Generic crosstalk initialization interfaces ******/
+
+/*
+ * One-time initialization needed for systems that support crosstalk.
+ */
+void
+xtalk_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("xtalk_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (xtalk_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr");
+	if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(xtalk_registry != NULL);
+}
+
+/*
+ * Associate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns);
+}
+
+/*
+ * Disassociate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_unregister(devfs_handle_t provider)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL);
+}
+
+/*
+ * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk
+ * provider.
+ */
+xtalk_provider_t       *
+xtalk_provider_fns_get(devfs_handle_t provider)
+{
+    return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider));
+}
+
+/*
+ * Announce a driver for a particular crosstalk part.
+ * Returns 0 on success or -1 on failure.  Failure occurs if the
+ * specified hardware already has a driver.
+ */
+/*ARGSUSED4 */
+int
+xwidget_driver_register(xwidget_part_num_t part_num,
+			xwidget_mfg_num_t mfg_num,
+			char *driver_prefix,
+			unsigned flags)
+{
+    /* a driver's init routine could call
+     * xwidget_driver_register before the
+     * system calls xtalk_init; so, we
+     * make the call here.
+     */
+    if (xtalk_registry == NULL)
+	xtalk_init();
+
+    return cdl_add_driver(xtalk_registry,
+			  part_num, mfg_num,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Inform xtalk infrastructure that a driver is no longer available for
+ * handling any widgets.
+ */
+void
+xwidget_driver_unregister(char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called registger; so we
+     * can assume we have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_del_driver(xtalk_registry, driver_prefix, NULL);
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+xtalk_iterate(char *driver_prefix,
+	      xtalk_iter_f *func)
+{
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func);
+}
+
+/*
+ * xwidget_register:
+ *	Register a xtalk device (xwidget) by doing the following.
+ *      -allocate and initialize xwidget_info data
+ *      -allocate a hwgraph vertex with name based on widget number (id)
+ *      -look up the widget's initialization function and call it,
+ *      or remember the vertex for later initialization.
+ *
+ */
+int
+xwidget_register(xwidget_hwid_t hwid,		/* widget's hardware ID */
+		 devfs_handle_t 	widget,		/* widget to initialize */
+		 xwidgetnum_t 	id,		/* widget's target id (0..f) */
+		 devfs_handle_t 	master,		/* widget's master vertex */
+		 xwidgetnum_t 	targetid,	/* master's target id (9/a) */
+		 async_attach_t aa)
+{			
+    xwidget_info_t          widget_info;
+    char		    *s,devnm[MAXDEVNAME];
+
+    /* Allocate widget_info and associate it with widget vertex */
+    NEW(widget_info);
+
+    /* Initialize widget_info */
+    widget_info->w_vertex = widget;
+    widget_info->w_id = id;
+    widget_info->w_master = master;
+    widget_info->w_masterid = targetid;
+    widget_info->w_hwid = *hwid;	/* structure copy */
+    widget_info->w_efunc = 0;
+    widget_info->w_einfo = 0;
+    /*
+     * get the name of this xwidget vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(widget,devnm,MAXDEVNAME);
+    widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
+    strcpy(widget_info->w_name,s);
+    
+    xwidget_info_set(widget, widget_info);
+
+    device_master_set(widget, master);
+
+    /* All the driver init routines (including
+     * xtalk_init) are called before we get into
+     * attaching devices, so we can assume we
+     * have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    /* 
+     * Add pointer to async attach info -- tear down will be done when
+     * the particular descendant is done with the info.
+     */
+    if (aa)
+	    async_attach_add_info(widget, aa);
+
+    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                          widget, 0);
+}
+
+/*
+ * xwidget_unregister :
+ *	Unregister the xtalk device and detach all its hwgraph namespace.
+ */
+int
+xwidget_unregister(devfs_handle_t widget)
+{
+    xwidget_info_t	widget_info;
+    xwidget_hwid_t	hwid;
+
+    /* Make sure that we have valid widget information initialized */
+    if (!(widget_info = xwidget_info_get(widget)))
+	return(1);
+
+    /* Remove the inventory information associated
+     * with the widget.
+     */
+    hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1);
+    
+    hwid = &(widget_info->w_hwid);
+
+    cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                   widget, 0);
+
+    /* Clean out the xwidget information */
+    (void)kfree(widget_info->w_name);
+    BZERO((void *)widget_info, sizeof(widget_info));
+    DEL(widget_info);
+    
+    return(0);
+}
+
+/*
+ * Issue a link reset to a widget.
+ */
+void
+xwidget_reset(devfs_handle_t xwidget)
+{
+    xswitch_reset_link(xwidget);
+
+}
+
+
+void
+xwidget_gfx_reset(devfs_handle_t xwidget)
+{
+    xwidget_info_t info;
+
+    xswitch_reset_link(xwidget);
+    info = xwidget_info_get(xwidget);
+#ifdef LATER
+    ASSERT_ALWAYS(info != NULL);
+#endif
+
+    /*
+     * Enable this for other architectures once we add widget_reset to the
+     * xtalk provider interface.
+     */
+    DEV_FUNC(xtalk_provider, widget_reset)
+	(xwidget_info_master_get(info), xwidget_info_id_get(info));
+}
+
+#define ANON_XWIDGET_NAME	"No Name"	/* Default Widget Name */
+
+/* Get the canonical hwgraph  name of xtalk widget */
+char *
+xwidget_name_get(devfs_handle_t xwidget_vhdl)
+{
+	xwidget_info_t  info;
+
+	/* If we have a bogus widget handle then return
+	 * a default anonymous widget name.
+	 */
+	if (xwidget_vhdl == GRAPH_VERTEX_NONE)
+	    return(ANON_XWIDGET_NAME);
+	/* Read the widget name stored in the widget info
+	 * for the widget setup during widget initialization.
+	 */
+	info = xwidget_info_get(xwidget_vhdl);
+	ASSERT(info != NULL);
+	return(xwidget_info_name_get(info));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/Makefile linux-2.4.21-rc3/arch/ia64/sn/io/sn2/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn2/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,27 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn2 io routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+O_TARGET := snio.o
+
+export-objs := pciio.o 
+
+obj-y				+= ml_SN_intr.o shub_intr.o shuberror.o shub.o \
+				   bte_error.o pcibr/pcibr.o pic.o geo_op.o \
+				   l1.o l1_command.o klconflib.o klgraph.o \
+				   ml_SN_init.o ml_iograph.o module.o pciio.o \
+				   xbow.o xtalk.o \
+				   pci_bus_cvlink.o sgi_io_init.o shubio.o
+
+subdir-y			+= pcibr
+
+obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/bte_error.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/bte_error.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/bte_error.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/bte_error.c	2003-05-22 22:06:47.000000000 +0000
@@ -54,96 +54,14 @@
  *									*
  ************************************************************************/
 
-#ifdef BTE_ERROR
-// This routine is not called.  Yet.  It may be someday.  It probably
-// *should* be someday.  Until then, ifdef it out.
-bte_result_t
-bte_error_handler(bte_handle_t *bh)
-/*
- * Function: 	bte_error_handler
- * Purpose:	Process a BTE error after a transfer has failed.
- * Parameters:	bh - bte handle of bte that failed.
- * Returns:	The BTE error type.
- * Notes:
+/* 
+ * >>> bte_crb_error_handler needs to be broken into two parts.  The
+ * first should cleanup the CRB.  The second should wait until all bte
+ * related CRB's are complete and then do the error reset.
  */
-{
-    devfs_handle_t	hub_v;
-    hubinfo_t		hinfo;
-    int			il;
-    hubreg_t		iidsr, imem, ieclr;
-    hubreg_t		bte_status;
-
-    bh->bh_bte->bte_error_count++;
-
-    /* 
-     * Process any CRB logs - we know that the bte_context contains
-     * the BTE completion status, but to avoid a race with error
-     * processing, we force a call to pick up any CRB errors pending. 
-     * After this call, we know that we have any CRB errors related to 
-     * this BTE transfer in the context.
-     */
-    hub_v = cnodeid_to_vertex(bh->bh_bte->bte_cnode);
-    hubinfo_get(hub_v, &hinfo);
-    (void)hubiio_crb_error_handler(hub_v, hinfo);
-
-    /* Be sure BTE is stopped */
-
-    (void)BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_CTRL);
-
-    /*	
-     * Now clear up the rest of the error - be sure to hold crblock 
-     * to avoid race with other cpu on this node.
-     */
-    imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM);
-    ieclr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IECLR);
-    if (bh->bh_bte->bte_num == 0) {
-	imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD;
-	ieclr|= IECLR_BTE0;
-    } else {
-	imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD;
-	ieclr|= IECLR_BTE1;
-    }
-
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IMEM, imem);
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, ieclr);
-
-    iidsr  = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR);
-    iidsr &= ~IIO_IIDSR_SENT_MASK;
-    iidsr |= IIO_IIDSR_ENB_MASK;
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, iidsr);
-    mutex_spinunlock(&hinfo->h_crblock, il);
-
-    bte_status = BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT);
-    BTE_STORE(bh->bh_bte->bte_base, BTEOFF_STAT, bte_status & ~IBLS_BUSY);
-    ASSERT(!BTE_IS_BUSY(BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT)));
-
-    switch(bh->bh_error) {
-    case IIO_ICRB_ECODE_PERR:
-	return(BTEFAIL_POISON);
-    case IIO_ICRB_ECODE_WERR:
-	return(BTEFAIL_PROT);
-    case IIO_ICRB_ECODE_AERR:
-	return(BTEFAIL_ACCESS);
-    case IIO_ICRB_ECODE_TOUT:
-	return(BTEFAIL_TOUT);
-    case IIO_ICRB_ECODE_XTERR:
-	return(BTEFAIL_ERROR);
-    case IIO_ICRB_ECODE_DERR:
-	return(BTEFAIL_DIR);
-    case IIO_ICRB_ECODE_PWERR:
-    case IIO_ICRB_ECODE_PRERR:
-	/* NO BREAK */
-    default:
-	printk("BTE failure (%d) unexpected\n", 
-		bh->bh_error);
-	return(BTEFAIL_ERROR);
-    }
-}
-#endif // BTE_ERROR
-
 void
 bte_crb_error_handler(devfs_handle_t hub_v, int btenum, 
-		      int crbnum, ioerror_t *ioe)
+		      int crbnum, ioerror_t *ioe, int bteop)
 /*
  * Function: 	bte_crb_error_handler
  * Purpose:	Process a CRB for a specific HUB/BTE
@@ -162,29 +80,70 @@
 	icrba_t		crba; 
 	icrbb_t		crbb; 
 	nasid_t		n;
+	hubreg_t	iidsr, imem, ieclr;
 
 	hubinfo_get(hub_v, &hinfo);
 
 
 	n = hinfo->h_nasid;
 	
-	/* Step 1 */
-	crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum));
-	crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum));
 
+	/*
+	 * The following 10 lines (or so) are adapted from IRIXs
+	 * bte_crb_error function.  No clear documentation tells
+	 * why the crb needs to complete normally in order for
+	 * the BTE to resume normal operations.  This first step
+	 * appears vital!
+	 */
 
-	/* Zero error and error code to prevent error_dump complaining
-	 * about these CRBs. 
+	/*
+	 * Zero error and error code to prevent error_dump complaining
+	 * about these CRBs. Copy the CRB to the notification line.
+	 * The crb address is in shub format (physical address shifted
+	 * right by cacheline size).
 	 */
+	crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum));
 	crbb.b_error=0;
 	crbb.b_ecode=0;
+	REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval);
 
-	/* Step 2 */
+	crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum));
+	crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3;
+	crba.a_valid = 1;
 	REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval);
-	/* Step 3 */
+
 	REMOTE_HUB_S(n, IIO_ICCR, 
 		     IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum);
+
 	while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING)
 	    ;
+
+
+	/* Terminate the BTE. */
+	/* >>> The other bte transfer will need to be restarted. */
+	HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr +
+		       IIO_IBCT0 - IIO_IBLS0)));
+
+	imem = REMOTE_HUB_L(n, IIO_IMEM);
+	ieclr = REMOTE_HUB_L(n, IIO_IECLR);
+	if (btenum == 0) {
+		imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD;
+		ieclr|= IECLR_BTE0;
+	} else {
+		imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD;
+		ieclr|= IECLR_BTE1;
+	}
+	REMOTE_HUB_S(n, IIO_IMEM, imem);
+	REMOTE_HUB_S(n, IIO_IECLR, ieclr);
+		
+	iidsr  = REMOTE_HUB_L(n, IIO_IIDSR);
+	iidsr &= ~IIO_IIDSR_SENT_MASK;
+	iidsr |= IIO_IIDSR_ENB_MASK;
+	REMOTE_HUB_S(n, IIO_IIDSR, iidsr);
+
+
+ 	bte_reset_nasid(n);
+
+	*nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/efi-rtc.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/efi-rtc.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/efi-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/efi-rtc.c	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,202 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2001 by Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/efi.h>
+#include <asm/sn/klclock.h>
+
+/*
+ * No locking necessary when this is called from efirtc which protects us
+ * from racing by efi_rtc_lock.
+ */
+#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3))
+#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr))
+#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data))
+
+#define TOD_SGS_M48T35		1
+#define TOD_DALLAS_DS1386	2
+
+#define TYPE_IOC3		1
+#define TYPE_IOC4		2
+
+static unsigned long nvram_base = 0;
+static int tod_chip_type;
+static int ioc_type;
+
+static int
+get_tod_chip_type(void)
+{
+	unsigned char testval;
+
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+	write_io_port(RTC_DAL_DAY_ADDR, 0xff);
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+
+	testval = read_io_port(RTC_DAL_DAY_ADDR);
+	if (testval == 0xff)
+		return TOD_SGS_M48T35;
+
+	return TOD_DALLAS_DS1386;
+}
+
+efi_status_t
+ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	memset(time, 0, sizeof(*time));
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
+
+		time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF;
+		time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR));
+		time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR));
+		time->nanosecond = 0;
+
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+
+		time->nanosecond = 0;
+		time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR));
+		time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR));
+		time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF;
+
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	if (caps) {
+		caps->resolution = 50000000;	/*  50PPM */
+		caps->accuracy = 1000;		/*  1ms */
+		caps->sets_to_zero = 0;
+	}
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t ioc3_set_time (efi_time_t *t)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE);
+        	write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_SGS_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_SGS_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+		write_io_port(RTC_DAL_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_DAL_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	return EFI_SUCCESS;
+}
+
+/* The following two are not supported atm.  */
+static efi_status_t
+ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static __init int efi_ioc_time_init(void)
+{
+	struct pci_dev *dev = NULL;
+	static void *ioc_base;
+
+        while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID, dev))) {
+		if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+			ioc_type = TYPE_IOC3;
+			break;
+		}
+		else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) {
+			ioc_type = TYPE_IOC4;
+			break;
+		}
+		else
+			;; // keep looking
+	}
+
+	if ( !dev ) {
+		printk(KERN_CRIT "Couldn't find master IOC\n");
+		return -ENODEV;
+	}
+
+	ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+	if ( ioc_type == TYPE_IOC3 )
+		nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0;
+	if ( ioc_type == TYPE_IOC4 )
+		nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0;
+
+	tod_chip_type = get_tod_chip_type();
+	if (tod_chip_type == 1)
+		printk(KERN_NOTICE "TOD type is SGS M48T35\n");
+	else if (tod_chip_type == 2)
+		printk(KERN_NOTICE "TOD type is Dallas DS1386\n");
+	else
+		printk(KERN_CRIT "No or unknown TOD\n");
+
+	efi.get_time = ioc3_get_time;
+	efi.set_time = ioc3_set_time;
+	efi.get_wakeup_time = ioc3_get_wakeup_time;
+	efi.set_wakeup_time = ioc3_set_wakeup_time;
+
+	return 0;
+}
+
+module_init(efi_ioc_time_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/geo_op.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/geo_op.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/geo_op.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/geo_op.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,314 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * @doc file m:hwcfg
+ * DESCRIPTION:
+ * 
+ * This file contains routines for manipulating and generating 
+ * Geographic IDs.  They are in a file by themself since they have
+ * no dependencies on other modules.
+ *  
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/types.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sn/sn2/shubio.h>
+#include <asm/sal.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/module.h>
+#include <asm/sn/geo.h>
+
+/********** Global functions and data (visible outside the module) ***********/
+
+/*
+ * @doc gf:geo_module
+ * 
+ * moduleid_t geo_module(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the moduleid component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Return INVALID_MODULE for an invalid geoid.  Otherwise extract the
+ * moduleid from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+moduleid_t
+geo_module(geoid_t g)
+{
+    if (g.any.type == GEO_TYPE_INVALID)
+	return INVALID_MODULE;
+    else
+	return g.any.module;
+}
+
+
+/*
+ * @doc gf:geo_slab
+ * 
+ * slabid_t geo_slab(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the slabid component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Return INVALID_SLAB for an invalid geoid.  Otherwise extract the
+ * slabid from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+slabid_t
+geo_slab(geoid_t g)
+{
+    if (g.any.type == GEO_TYPE_INVALID)
+	return INVALID_SLAB;
+    else
+	return g.any.slab;
+}
+
+
+/*
+ * @doc gf:geo_type
+ * 
+ * geo_type_t geo_type(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the type component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Extract the type from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+geo_type_t
+geo_type(geoid_t g)
+{
+    return g.any.type;
+}
+
+
+/*
+ * @doc gf:geo_valid
+ * 
+ * int geo_valid(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return nonzero if g has a valid geoid type.
+ *  
+ * INTERNALS:
+ * 
+ * Test the type against GEO_TYPE_INVALID, and return the result.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+int
+geo_valid(geoid_t g)
+{
+    return g.any.type != GEO_TYPE_INVALID;
+}
+
+
+/*
+ * @doc gf:geo_cmp
+ * 
+ * int geo_cmp(geoid_t g0, geoid_t g1)
+ * 
+ * DESCRIPTION:
+ * 
+ * Compare two geoid_t values, from the coarsest field to the finest.
+ * The comparison should be consistent with the physical locations of
+ * of the hardware named by the geoids.
+ *  
+ * INTERNALS:
+ * 
+ * First compare the module, then the slab, type, and type-specific fields.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+int
+geo_cmp(geoid_t g0, geoid_t g1)
+{
+    int rv;
+
+    /* Compare the common fields */
+    rv = MODULE_CMP(geo_module(g0), geo_module(g1));
+    if (rv != 0)
+	return rv;
+
+    rv = geo_slab(g0) - geo_slab(g1);
+    if (rv != 0)
+	return rv;
+
+    /* Within a slab, sort by type */
+    rv = geo_type(g0) - geo_type(g1);
+    if (rv != 0)
+	return rv;
+
+    switch(geo_type(g0)) {
+    case GEO_TYPE_CPU:
+	rv = g0.cpu.slice - g1.cpu.slice;
+	break;
+
+    case GEO_TYPE_IOCARD:
+	rv = g0.pcicard.bus - g1.pcicard.bus;
+	if (rv) break;
+	rv = SLOTNUM_GETSLOT(g0.pcicard.slot) -
+	    SLOTNUM_GETSLOT(g1.pcicard.slot);
+	break;
+
+    case GEO_TYPE_MEM:
+	rv = g0.mem.membus - g1.mem.membus;
+	if (rv) break;
+	rv = g0.mem.memslot - g1.mem.memslot;
+	break;
+
+    default:
+	rv = 0;
+    }
+
+    return rv;
+}
+
+
+/*
+ * @doc gf:geo_new
+ * 
+ * geoid_t geo_new(geo_type_t type, ...)
+ * 
+ * DESCRIPTION:
+ * 
+ * Generate a new geoid_t value of the given type from its components.
+ * Expected calling sequences:
+ * \@itemize \@bullet
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_INVALID)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_MODULE, moduleid_t m)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_NODE, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_RTR, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_IOCNTL, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_IOCARD, moduleid_t m, slabid_t s, char bus, slotid_t slot)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_CPU, moduleid_t m, slabid_t s, char slice)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_MEM, moduleid_t m, slabid_t s, char membus, char slot)\}
+ * \@end itemize
+ *
+ * Invalid types return a GEO_TYPE_INVALID geoid_t.
+ *  
+ * INTERNALS:
+ * 
+ * Use the type to determine which fields to expect.  Write the fields into
+ * a new geoid_t and return it.  Note:  scalars smaller than an "int" are
+ * promoted to "int" by the "..." operator, so we need extra casts on "char",
+ * "slotid_t", and "slabid_t".
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+geoid_t
+geo_new(geo_type_t type, ...)
+{
+    va_list al;
+    geoid_t g;
+    memset(&g, 0, sizeof(g));
+
+    va_start(al, type);
+
+    /* Make sure the type is sane */
+    if (type >= GEO_TYPE_MAX)
+	type = GEO_TYPE_INVALID;
+
+    g.any.type = type;
+    if (type == GEO_TYPE_INVALID)
+	goto done;		/* invalid geoids have no components at all */
+
+    g.any.module = va_arg(al, moduleid_t);
+    if (type == GEO_TYPE_MODULE)
+	goto done;
+
+    g.any.slab = (slabid_t)va_arg(al, int);
+
+    /* Some types have additional components */
+    switch(type) {
+    case GEO_TYPE_CPU:
+	g.cpu.slice = (char)va_arg(al, int);
+	break;
+
+    case GEO_TYPE_IOCARD:
+	g.pcicard.bus = (char)va_arg(al, int);
+	g.pcicard.slot = (slotid_t)va_arg(al, int);
+	break;
+
+    case GEO_TYPE_MEM:
+	g.mem.membus = (char)va_arg(al, int);
+	g.mem.memslot = (char)va_arg(al, int);
+	break;
+
+    default:
+	break;
+    }
+
+ done:
+    va_end(al);
+    return g;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/klconflib.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/klconflib.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/klconflib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/klconflib.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,933 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/module.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+
+#define printf printk
+int hasmetarouter;
+
+#define LDEBUG 0
+#define NIC_UNKNOWN ((nic_t) -1)
+
+#undef DEBUG_KLGRAPH
+#ifdef DEBUG_KLGRAPH
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_KLGRAPH */
+
+static void sort_nic_names(lboard_t *) ;
+
+u64 klgraph_addr[MAX_COMPACT_NODES];
+int module_number = 0;
+
+lboard_t *
+find_lboard(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (start->brd_type == brd_type)
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_class(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+klinfo_t *
+find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
+{
+	int index, j;
+
+	if (kli == (klinfo_t *)NULL) {
+		index = 0;
+	} else {
+		for (j = 0; j < KLCF_NUM_COMPS(brd); j++) {
+			if (kli == KLCF_COMP(brd, j))
+				break;
+		}
+		index = j;
+		if (index == KLCF_NUM_COMPS(brd)) {
+			DBG("find_component: Bad pointer: 0x%p\n", kli);
+			return (klinfo_t *)NULL;
+		}
+		index++;	/* next component */
+	}
+	
+	for (; index < KLCF_NUM_COMPS(brd); index++) {		
+		kli = KLCF_COMP(brd, index);
+		DBG("find_component: brd %p kli %p  request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli));
+		if (KLCF_COMP_TYPE(kli) == struct_type)
+			return kli;
+	}
+
+	/* Didn't find it. */
+	return (klinfo_t *)NULL;
+}
+
+klinfo_t *
+find_first_component(lboard_t *brd, unsigned char struct_type)
+{
+	return find_component(brd, (klinfo_t *)NULL, struct_type);
+}
+
+lboard_t *
+find_lboard_modslot(lboard_t *start, geoid_t geoid)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (geo_cmp(start->brd_geoid, geoid))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module(lboard_t *start, geoid_t geoid)
+{
+        /* Search all boards stored on this node. */
+        while (start) {
+                if (geo_cmp(start->brd_geoid, geoid))
+                        return start;
+                start = KLCF_NEXT(start);
+        }
+
+        /* Didn't find it. */
+        return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module_class(lboard_t *start, geoid_t geoid,
+                                                unsigned char brd_type)
+{
+	while (start) {
+		DBG("find_lboard_module_class: lboard 0x%p, start->brd_geoid 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_geoid, geoid, start->brd_type, brd_type);
+
+		if (geo_cmp(start->brd_geoid, geoid) &&
+			(KLCLASS(start->brd_type) == KLCLASS(brd_type)))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+/*
+ * Convert a NIC name to a name for use in the hardware graph.
+ */
+void
+nic_name_convert(char *old_name, char *new_name)
+{
+        int i;
+        char c;
+        char *compare_ptr;
+
+	if ((old_name[0] == '\0') || (old_name[1] == '\0')) {
+                strcpy(new_name, EDGE_LBL_XWIDGET);
+        } else {
+                for (i = 0; i < strlen(old_name); i++) {
+                        c = old_name[i];
+
+                        if (isalpha(c))
+                                new_name[i] = tolower(c);
+                        else if (isdigit(c))
+                                new_name[i] = c;
+                        else
+                                new_name[i] = '_';
+                }
+                new_name[i] = '\0';
+        }
+
+        /* XXX -
+         * Since a bunch of boards made it out with weird names like
+         * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and
+         * replace it with "baseio" to avoid confusion in the field.
+	 * We also have to make sure we don't report media_io instead of
+	 * baseio.
+         */
+
+        /* Skip underscores at the beginning of the name */
+        for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++)
+                ;
+
+	/*
+	 * Check for some names we need to replace.  Early boards
+	 * had junk following the name so check only the first
+	 * characters.
+	 */
+        if (!strncmp(new_name, "io6", 3) || 
+            !strncmp(new_name, "mio", 3) || 
+	    !strncmp(new_name, "media_io", 8))
+		strcpy(new_name, "baseio");
+	else if (!strncmp(new_name, "divo", 4))
+		strcpy(new_name, "divo") ;
+
+}
+
+/*
+ * Find the lboard structure and get the board name.
+ * If we can't find the structure or it's too low a revision,
+ * use default name.
+ */
+lboard_t *
+get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name)
+{
+	lboard_t *brd;
+
+	brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
+				  geoid);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			brd = find_lboard_modslot((lboard_t *)
+				KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				geoid);
+	}
+#endif
+
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, name);
+	}
+
+	/*
+	 * PV # 540860
+	 * If the name is not 'baseio'
+	 * get the lowest of all the names in the nic string.
+	 * This is needed for boards like divo, which can have
+	 * a bunch of daughter cards, but would like to be called
+	 * divo. We could do this for baseio
+	 * but it has some special case names that we would not
+	 * like to disturb at this point.
+	 */
+
+	/* gfx boards don't need any of this name scrambling */
+	if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) {
+		return(brd);
+	}
+
+	if (!(!strcmp(name, "baseio") )) {
+		if (brd) {
+			sort_nic_names(brd) ;
+			/* Convert to small case, '-' to '_' etc */
+			nic_name_convert(brd->brd_name, name) ;
+		}
+	}
+
+	return(brd);
+}
+
+/*
+ * get_actual_nasid
+ *
+ *	Completely disabled brds have their klconfig on 
+ *	some other nasid as they have no memory. But their
+ *	actual nasid is hidden in the klconfig. Use this
+ *	routine to get it. Works for normal boards too.
+ */
+nasid_t
+get_actual_nasid(lboard_t *brd)
+{
+	klhub_t	*hub ;
+
+	if (!brd)
+		return INVALID_NASID ;
+
+	/* find out if we are a completely disabled brd. */
+
+        hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+	if (!hub)
+                return INVALID_NASID ;
+	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
+		return hub->hub_info.physid ;
+	else
+		return brd->brd_nasid ;
+}
+
+int
+xbow_port_io_enabled(nasid_t nasid, int link)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+
+	/*
+	 * look for boards that might contain an xbow or xbridge
+	 */
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
+	if (brd == NULL) return 0;
+		
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return 0;
+
+	if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
+	    return 0;
+
+	return 1;
+}
+
+void
+board_to_path(lboard_t *brd, char *path)
+{
+	moduleid_t modnum;
+	char *board_name;
+	char buffer[16];
+
+	ASSERT(brd);
+
+	switch (KLCLASS(brd->brd_type)) {
+
+		case KLCLASS_NODE:
+			board_name = EDGE_LBL_NODE;
+			break;
+		case KLCLASS_ROUTER:
+			if (brd->brd_type == KLTYPE_META_ROUTER) {
+				board_name = EDGE_LBL_META_ROUTER;
+				hasmetarouter++;
+			} else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
+				board_name = EDGE_LBL_REPEATER_ROUTER;
+				hasmetarouter++;
+			} else
+				board_name = EDGE_LBL_ROUTER;
+			break;
+		case KLCLASS_MIDPLANE:
+			board_name = EDGE_LBL_MIDPLANE;
+			break;
+		case KLCLASS_IO:
+			board_name = EDGE_LBL_IO;
+			break;
+		case KLCLASS_IOBRICK:
+			if (brd->brd_type == KLTYPE_PBRICK)
+				board_name = EDGE_LBL_PBRICK;
+			else if (brd->brd_type == KLTYPE_IBRICK)
+				board_name = EDGE_LBL_IBRICK;
+			else if (brd->brd_type == KLTYPE_XBRICK)
+				board_name = EDGE_LBL_XBRICK;
+			else
+				board_name = EDGE_LBL_IOBRICK;
+			break;
+		default:
+			board_name = EDGE_LBL_UNKNOWN;
+	}
+			
+	modnum = geo_module(brd->brd_geoid);
+	memset(buffer, 0, 16);
+	format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
+	sprintf(path, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/%s", buffer, geo_slab(brd->brd_geoid), board_name);
+}
+
+/*
+ * Get the module number for a NASID.
+ */
+moduleid_t
+get_module_id(nasid_t nasid)
+{
+	lboard_t *brd;
+
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+	if (!brd)
+		return INVALID_MODULE;
+	else
+		return geo_module(brd->brd_geoid);
+}
+
+
+#define MHZ	1000000
+
+
+/* Get the canonical hardware graph name for the given pci component
+ * on the given io board.
+ */
+void
+device_component_canonical_name_get(lboard_t 	*brd,
+				    klinfo_t 	*component,
+				    char 	*name)
+{
+	slotid_t 	slot;
+	char 		board_name[20];
+
+	ASSERT(brd);
+
+	/* Convert the [ CLASS | TYPE ] kind of slotid
+	 * into a string
+	 */
+	slot = brd->brd_slot;
+
+	/* Get the io board name  */
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, board_name);
+	}
+
+	/* Give out the canonical  name of the pci device*/
+	sprintf(name,
+		"/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLAB"/%d/"
+		EDGE_LBL_SLOT"/%s/"EDGE_LBL_PCI"/%d",
+		geo_module(brd->brd_geoid), geo_slab(brd->brd_geoid), 
+		board_name, KLCF_BRIDGE_W_ID(component));
+}
+
+/*
+ * Get the serial number of the main  component of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ * Assumptions: Nic manufacturing string  has the following format
+ *			*Serial:<serial_number>;*
+ */
+static int
+component_serial_number_get(lboard_t 		*board,
+			    klconf_off_t 	mfg_nic_offset,
+			    char		*serial_number,
+			    char		*key_pattern)
+{
+
+	char	*mfg_nic_string;
+	char	*serial_string,*str;
+	int	i;
+	char	*serial_pattern = "Serial:";
+
+	/* We have an error on a null mfg nic offset */
+	if (!mfg_nic_offset)
+		return(1);
+	/* Get the hub's manufacturing nic information
+	 * which is in the form of a pre-formatted string
+	 */
+	mfg_nic_string = 
+		(char *)NODE_OFFSET_TO_K0(NASID_GET(board),
+					  mfg_nic_offset);
+	/* There is no manufacturing nic info */
+	if (!mfg_nic_string)
+		return(1);
+
+	str = mfg_nic_string;
+	/* Look for the key pattern first (if it is  specified)
+	 * and then print the serial number corresponding to that.
+	 */
+	if (strcmp(key_pattern,"") && 
+	    !(str = strstr(mfg_nic_string,key_pattern)))
+		return(1);
+
+	/* There is no serial number info in the manufacturing
+	 * nic info
+	 */
+	if (!(serial_string = strstr(str,serial_pattern)))
+		return(1);
+
+	serial_string = serial_string + strlen(serial_pattern);
+	/*  Copy the serial number information from the klconfig */
+	i = 0;
+	while (serial_string[i] != ';') {
+		serial_number[i] = serial_string[i];
+		i++;
+	}
+	serial_number[i] = 0;
+	
+	return(0);
+}
+/*
+ * Get the serial number of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ */
+
+int
+board_serial_number_get(lboard_t *board,char *serial_number)
+{
+	ASSERT(board && serial_number);
+	if (!board || !serial_number)
+		return(1);
+
+	strcpy(serial_number,"");
+	switch(KLCLASS(board->brd_type)) {
+	case KLCLASS_CPU: {	/* Node board */
+		klhub_t	*hub;
+		
+		/* Get the hub component information */
+		hub = (klhub_t *)find_first_component(board,
+						      KLSTRUCT_HUB);
+		/* If we don't have a hub component on an IP27
+		 * then we have a weird klconfig.
+		 */
+		if (!hub)
+			return(1);
+		/* Get the serial number information from
+		 * the hub's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						hub->hub_mfg_nic,
+						serial_number,
+						"IP37"))
+				return(1);
+		break;
+	}
+	case KLCLASS_IO: {	/* IO board */
+		if (KLTYPE(board->brd_type) == KLTYPE_TPU) {
+		/* Special case for TPU boards */
+			kltpu_t *tpu;	
+		
+			/* Get the tpu component information */
+			tpu = (kltpu_t *)find_first_component(board,
+						      KLSTRUCT_TPU);
+			/* If we don't have a tpu component on a tpu board
+			 * then we have a weird klconfig.
+			 */
+			if (!tpu)
+				return(1);
+			/* Get the serial number information from
+			 * the tpu's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						tpu->tpu_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else  if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ||
+		            (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) {
+		/* Special case for GSN boards */
+			klgsn_t *gsn;	
+		
+			/* Get the gsn component information */
+			gsn = (klgsn_t *)find_first_component(board,
+			      ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ?
+					KLSTRUCT_GSN_A : KLSTRUCT_GSN_B));
+			/* If we don't have a gsn component on a gsn board
+			 * then we have a weird klconfig.
+			 */
+			if (!gsn)
+				return(1);
+			/* Get the serial number information from
+			 * the gsn's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						gsn->gsn_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else {
+		     	klbri_t	*bridge;
+		
+			/* Get the bridge component information */
+			bridge = (klbri_t *)find_first_component(board,
+							 KLSTRUCT_BRI);
+			/* If we don't have a bridge component on an IO board
+			 * then we have a weird klconfig.
+			 */
+			if (!bridge)
+				return(1);
+			/* Get the serial number information from
+		 	 * the bridge's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						bridge->bri_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		}
+	}
+	case KLCLASS_ROUTER: {	/* Router board */
+		klrou_t *router;	
+		
+		/* Get the router component information */
+		router = (klrou_t *)find_first_component(board,
+							 KLSTRUCT_ROU);
+		/* If we don't have a router component on a router board
+		 * then we have a weird klconfig.
+		 */
+		if (!router)
+			return(1);
+		/* Get the serial number information from
+		 * the router's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						router->rou_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	case KLCLASS_GFX: {	/* Gfx board */
+		klgfx_t *graphics;
+		
+		/* Get the graphics component information */
+		graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX);
+		/* If we don't have a gfx component on a gfx board
+		 * then we have a weird klconfig.
+		 */
+		if (!graphics)
+			return(1);
+		/* Get the serial number information from
+		 * the graphics's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						graphics->gfx_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	default:
+		strcpy(serial_number,"");
+		break;
+	}
+	return(0);
+}
+
+#include "asm/sn/sn_private.h"
+
+xwidgetnum_t
+nodevertex_widgetnum_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, 
+			     (arbitrary_info_t *) &hubinfo_p);
+	return(hubinfo_p->h_widgetid);
+}
+
+devfs_handle_t
+nodevertex_xbow_peer_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+	nasid_t xbow_peer_nasid;
+	cnodeid_t xbow_peer;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
+				     (arbitrary_info_t *) &hubinfo_p);
+	xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer;
+	if(xbow_peer_nasid == INVALID_NASID) 
+			return ( (devfs_handle_t)-1);
+	xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid);
+	return(NODEPDA(xbow_peer)->node_vertex);
+}
+
+/* NIC Sorting Support */
+
+#define MAX_NICS_PER_STRING 	32
+#define MAX_NIC_NAME_LEN	32
+
+static char *
+get_nic_string(lboard_t *lb)
+{
+        int         	i;
+        klinfo_t    	*k = NULL ;
+    	klconf_off_t    mfg_off = 0 ;
+    	char            *mfg_nic = NULL ;
+
+        for (i = 0; i < KLCF_NUM_COMPS(lb); i++) {
+                k = KLCF_COMP(lb, i) ;
+                switch(k->struct_type) {
+                        case KLSTRUCT_BRI:
+            			mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_HUB:
+            			mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_ROU:
+            			mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GFX:
+            			mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_TPU:
+            			mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GSN_A:
+                        case KLSTRUCT_GSN_B:
+            			mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_XTHD:
+                                mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
+                                break;
+
+			default:
+				mfg_off = 0 ;
+                                break ;
+                }
+		if (mfg_off)
+			break ;
+        }
+
+	if ((mfg_off) && (k))
+		mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ;
+
+        return mfg_nic ;
+}
+
+char *
+get_first_string(char **ptrs, int n)
+{
+        int     i ;
+        char    *tmpptr ;
+
+        if ((ptrs == NULL) || (n == 0))
+                return NULL ;
+
+        tmpptr = ptrs[0] ;
+
+        if (n == 1)
+                return tmpptr ;
+
+        for (i = 0 ; i < n ; i++) {
+                if (strcmp(tmpptr, ptrs[i]) > 0)
+                        tmpptr = ptrs[i] ;
+        }
+
+        return tmpptr ;
+}
+
+int
+get_ptrs(char *idata, char **ptrs, int n, char *label)
+{
+        int     i = 0 ;
+        char    *tmp = idata ;
+
+        if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0))
+                return 0 ;
+
+        while  ( (tmp = strstr(tmp, label)) ){
+                tmp += strlen(label) ;
+                /* check for empty name field, and last NULL ptr */
+                if ((i < (n-1)) && (*tmp != ';')) {
+                        ptrs[i++] = tmp ;
+                }
+        }
+
+        ptrs[i] = NULL ;
+
+        return i ;
+}
+
+/*
+ * sort_nic_names
+ *
+ * 	Does not really do sorting. Find the alphabetically lowest
+ *	name among all the nic names found in a nic string.
+ *
+ * Return:
+ *	Nothing
+ *
+ * Side Effects:
+ *
+ *	lb->brd_name gets the new name found
+ */
+
+static void
+sort_nic_names(lboard_t *lb)
+{
+	char 	*nic_str ;
+        char    *ptrs[MAX_NICS_PER_STRING] ;
+        char    name[MAX_NIC_NAME_LEN] ;
+        char    *tmp, *tmp1 ;
+
+	*name = 0 ;
+
+	/* Get the nic pointer from the lb */
+
+	if ((nic_str = get_nic_string(lb)) == NULL)
+		return ;
+
+        tmp = get_first_string(ptrs,
+                        get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ;
+
+        if (tmp == NULL)
+		return ;
+
+        if  ( (tmp1 = strchr(tmp, ';')) ){
+                strncpy(name, tmp, tmp1-tmp) ;
+                name[tmp1-tmp] = 0 ;
+        } else {
+                strncpy(name, tmp, (sizeof(name) -1)) ;
+                name[sizeof(name)-1] = 0 ;
+        }
+
+	strcpy(lb->brd_name, name) ;
+}
+
+
+
+char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345";
+
+/*
+ * Format a module id for printing.
+ */
+void
+format_module_id(char *buffer, moduleid_t m, int fmt)
+{
+	int rack, position;
+	char brickchar;
+
+	rack = MODULE_GET_RACK(m);
+	ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES);
+	brickchar = MODULE_GET_BTCHAR(m);
+	position = MODULE_GET_BPOS(m);
+
+	if (fmt == MODULE_FORMAT_BRIEF) {
+	    /* Brief module number format, eg. 002c15 */
+
+	    /* Decompress the rack number */
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    /* Add the brick type */
+	    *buffer++ = brickchar;
+	}
+	else if (fmt == MODULE_FORMAT_LONG) {
+	    /* Fuller hwgraph format, eg. rack/002/bay/15 */
+
+	    strcpy(buffer, EDGE_LBL_RACK "/");  buffer += strlen(buffer);
+
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    strcpy(buffer, "/" EDGE_LBL_RPOS "/");  buffer += strlen(buffer);
+	}
+
+	/* Add the bay position, using at least two digits */
+	if (position < 10)
+	    *buffer++ = '0';
+	sprintf(buffer, "%d", position);
+
+}
+
+/*
+ * Parse a module id, in either brief or long form.
+ * Returns < 0 on error.
+ * The long form does not include a brick type, so it defaults to 0 (CBrick)
+ */
+int
+parse_module_id(char *buffer)
+{
+	unsigned int	v, rack, bay, type, form;
+	moduleid_t	m;
+	char 		c;
+
+	if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) {
+		form = MODULE_FORMAT_LONG;
+		buffer += strlen(EDGE_LBL_RACK "/");
+
+		/* A long module ID must be exactly 5 non-template chars. */
+		if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5)
+			return -1;
+	}
+	else {
+		form = MODULE_FORMAT_BRIEF;
+
+		/* A brief module id must be exactly 6 characters */
+		if (strlen(buffer) != 6)
+			return -2;
+	}
+
+	/* The rack number must be exactly 3 digits */
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2])))
+		return -3;
+
+	rack = 0;
+	v = *buffer++ - '0';
+	if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+		return -4;
+	RACK_ADD_CLASS(rack, v);
+
+	v = *buffer++ - '0';
+	if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+		return -5;
+	RACK_ADD_GROUP(rack, v);
+
+	v = *buffer++ - '0';
+	/* rack numbers are 1-based */
+	if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+		return -6;
+	RACK_ADD_NUM(rack, v);
+
+	if (form == MODULE_FORMAT_BRIEF) {
+		/* Next should be a module type character.  Accept ucase or lcase. */
+		c = *buffer++;
+		if (!isalpha(c))
+			return -7;
+
+		/* strchr() returns a pointer into brick_types[], or NULL */
+		type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types);
+		if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT)
+			return -8;
+	}
+	else {
+		/* Hardcode the module type, and skip over the boilerplate */
+		type = MODULE_CBRICK;
+
+		if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer)
+			return -9;
+
+		buffer += strlen("/" EDGE_LBL_RPOS "/");
+	}
+		
+	/* The bay number is last.  Make sure it's exactly two digits */
+
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2]))
+		return -10;
+
+	bay = 10 * (buffer[0] - '0') + (buffer[1] - '0');
+
+	if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+		return -11;
+
+	m = RBT_TO_MODULE(rack, bay, type);
+
+	/* avoid sign extending the moduleid_t */
+	return (int)(unsigned short)m;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/klgraph.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/klgraph.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/klgraph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/klgraph.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,866 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * klgraph.c-
+ *      This file specifies the interface between the kernel and the PROM's
+ *      configuration data structures.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/kldir.h>
+#include <asm/sn/gda.h> 
+#include <asm/sn/klconfig.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/hcl_util.h>
+
+// #define KLGRAPH_DEBUG 1
+#ifdef KLGRAPH_DEBUG
+#define GRPRINTF(x)	printk x
+#define CE_GRPANIC	CE_PANIC
+#else
+#define GRPRINTF(x)
+#define CE_GRPANIC	CE_PANIC
+#endif
+
+#include <asm/sn/sn_private.h>
+
+extern char arg_maxnodes[];
+extern u64 klgraph_addr[];
+void mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid);
+
+
+/*
+ * Support for verbose inventory via hardware graph. 
+ * klhwg_invent_alloc allocates the necessary size of inventory information
+ * and fills in the generic information.
+ */
+invent_generic_t *
+klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
+{
+	invent_generic_t *invent;
+
+	invent = kern_malloc(size);
+	if (!invent) return NULL;
+	
+	invent->ig_module = NODE_MODULEID(cnode);
+	invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
+	invent->ig_invclass = class;
+
+	return invent;
+}
+
+/*
+ * Add detailed disabled cpu inventory info to the hardware graph.
+ */
+void
+klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv,
+                               cnodeid_t cnode,
+                               klcpu_t *cpu, slotid_t slot)
+{
+	invent_cpuinfo_t *cpu_invent;
+	diag_inv_t       *diag_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+	klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	/* Diag information on this processor */
+	diag_invent = (diag_inv_t *)
+	klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t));
+
+	if (!diag_invent)
+		return;
+
+
+	/* Disabled CPU */
+	cpu_invent->ic_gen.ig_flag = 0x0;
+	cpu_invent->ic_gen.ig_slot = slot;
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu->cpu_info.physid;
+
+	/* Disabled CPU label */
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+
+	/* Diagval label - stores reason for disable +{virt,phys}id +diagval*/
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL,
+			(arbitrary_info_t) diag_invent);
+
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL,
+			sizeof(diag_inv_t));
+}
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_cpu_invent_info(devfs_handle_t cpuv,
+			cnodeid_t cnode,
+			klcpu_t *cpu)
+{
+	invent_cpuinfo_t *cpu_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+		klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu))
+		cpu_invent->ic_gen.ig_flag = INVENT_ENABLED;
+	else
+		cpu_invent->ic_gen.ig_flag = 0x0;
+
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid);
+
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+}
+
+/* 
+ * Add information about the baseio prom version number
+ * as a part of detailed inventory info in the hwgraph.
+ */
+void
+klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
+{
+	invent_miscinfo_t	*baseio_inventory;
+	unsigned char		version = 0,revision = 0;
+
+	/* Allocate memory for the "detailed inventory" info
+	 * for the baseio
+	 */
+	baseio_inventory = (invent_miscinfo_t *) 
+		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
+	baseio_inventory->im_type = INV_IO6PROM;
+	/* Store the revision info  in the inventory */
+	baseio_inventory->im_version = version;
+	baseio_inventory->im_rev = revision;
+	/* Put the inventory info in the hardware graph */
+	hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) baseio_inventory);
+	/* Make the information available to the user programs
+	 * thru hwgfs.
+	 */
+        hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+char	*hub_rev[] = {
+	"0.0",
+	"1.0",
+	"2.0",
+	"2.1",
+	"2.2",
+	"2.3"
+};
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_hub_invent_info(devfs_handle_t hubv,
+		      cnodeid_t cnode, 
+		      klhub_t *hub)
+{
+	invent_miscinfo_t *hub_invent;
+
+	hub_invent = (invent_miscinfo_t *) 
+	    klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
+	if (!hub_invent)
+	    return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
+	    hub_invent->im_gen.ig_flag = INVENT_ENABLED;
+
+	hub_invent->im_type = INV_HUB;
+	hub_invent->im_rev = hub->hub_info.revision;
+	hub_invent->im_speed = hub->hub_speed;
+	hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) hub_invent);
+        hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
+{
+	devfs_handle_t myhubv;
+	devfs_handle_t hub_mon;
+	int rc;
+	extern struct file_operations shub_mon_fops;
+
+	GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
+	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
+	rc = device_master_set(myhubv, node_vertex);
+	hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
+		0, DEVFS_FL_AUTO_DEVNUM,
+		0, 0,
+		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+		&shub_mon_fops, (void *)(long)cnode);
+}
+
+/* ARGSUSED */
+void
+klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
+{
+        devfs_handle_t my_cpu;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+        if(cpu_id != -1){
+		sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid);
+		(void) hwgraph_path_add(node_vertex, name, &my_cpu);
+
+		mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+		device_master_set(my_cpu, node_vertex);
+
+		klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot);
+		return;
+        }
+}
+
+/* ARGSUSED */
+void
+klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
+{
+        devfs_handle_t my_cpu, cpu_dir;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+
+        sprintf(name, "%s/%d/%c",
+                EDGE_LBL_CPUBUS,
+                0,
+                'a' + cpu->cpu_info.physid);
+
+        GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%p\n", name, node_vertex));
+        (void) hwgraph_path_add(node_vertex, name, &my_cpu);
+        mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+        device_master_set(my_cpu, node_vertex);
+
+        /* Add an alias under the node's CPU directory */
+        if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) {
+                sprintf(name, "%c", 'a' + cpu->cpu_info.physid);
+                (void) hwgraph_edge_add(cpu_dir, my_cpu, name);
+        }
+
+        klhwg_cpu_invent_info(my_cpu, cnode, cpu);
+}
+
+
+void
+klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+	nasid_t hub_nasid;
+	cnodeid_t hub_cnode;
+	int widgetnum;
+	devfs_handle_t xbow_v, hubv;
+	/*REFERENCED*/
+	graph_error_t err;
+
+	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL)
+			return;
+
+	if (KL_CONFIG_DUPLICATE_BOARD(brd))
+	    return;
+
+	GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
+			cnode, nasid));
+
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return;
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
+		    continue;
+
+		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
+		if (hub_nasid == INVALID_NASID) {
+			printk(KERN_WARNING  "hub widget %d, skipping xbow graph\n", widgetnum);
+			continue;
+		}
+
+		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
+
+		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
+			continue;
+		}
+			
+		hubv = cnodeid_to_vertex(hub_cnode);
+
+		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
+                if (err != GRAPH_SUCCESS) {
+                        if (err == GRAPH_DUP)
+                                printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+                                        "working routers and router links!");
+
+                        PRINT_PANIC("klhwg_add_xbow: Failed to add "
+                                "edge: vertex 0x%p to vertex 0x%p,"
+                                "error %d\n",
+                                (void *)hubv, (void *)xbow_v, err);
+                }
+		xswitch_vertex_init(xbow_v); 
+
+		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
+
+		/*
+		 * XXX - This won't work is we ever hook up two hubs
+		 * by crosstown through a crossbow.
+		 */
+		if (hub_nasid != nasid) {
+			NODEPDA(hub_cnode)->xbow_peer = nasid;
+			NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
+				hub_nasid;
+		}
+
+		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
+			hub_nasid, EDGE_LBL_XTALK, hubv));
+	}
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
+{
+	nasid_t nasid;
+	lboard_t *brd;
+	klhub_t *hub;
+	devfs_handle_t node_vertex = NULL;
+	char path_buffer[100];
+	int rv;
+	char *s;
+	int board_disabled = 0;
+	klcpu_t *cpu;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
+                cnode, nasid, brd));
+	ASSERT(brd);
+
+	do {
+		devfs_handle_t cpu_dir;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
+			path_buffer, hwgraph_root));
+		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+		if (rv != GRAPH_SUCCESS)
+			PRINT_PANIC("Node vertex creation failed.  "
+					  "Path == %s",
+				path_buffer);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+		if(hub->hub_info.flags & KLINFO_ENABLE)
+			board_disabled = 0;
+		else
+			board_disabled = 1;
+		
+		if(!board_disabled) {
+			mark_nodevertex_as_node(node_vertex,
+					    cnode + board_disabled * numnodes);
+
+			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
+			NODEPDA(cnode)->hwg_node_name =
+						kmalloc(strlen(s) + 1,
+						GFP_KERNEL);
+			ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
+			strcpy(NODEPDA(cnode)->hwg_node_name, s);
+
+			hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
+
+			/* Set up node board's slot */
+			NODEPDA(cnode)->slotdesc = brd->brd_slot;
+
+			/* Set up the module we're in */
+			NODEPDA(cnode)->geoid = brd->brd_geoid;
+			NODEPDA(cnode)->module = module_lookup(geo_module(brd->brd_geoid));
+		}
+
+		/* Get the first CPU structure */
+		cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
+
+		/*
+		* If there's at least 1 CPU, add a "cpu" directory to represent
+		* the collection of all CPUs attached to this node.
+		*/
+		if (cpu) {
+			graph_error_t rv;
+
+			rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir);
+			if (rv != GRAPH_SUCCESS)
+				panic("klhwg_add_node: Cannot create CPU directory\n");
+		}
+
+		/* Add each CPU */
+		while (cpu) {
+			cpuid_t cpu_id;
+			cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid);
+			if (cpu_enabled(cpu_id))
+				klhwg_add_cpu(node_vertex, cnode, cpu);
+			else
+				klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
+
+			cpu = (klcpu_t *)
+				find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
+		} /* while */
+
+		if(!board_disabled)
+			klhwg_add_hub(node_vertex, hub, cnode);
+		
+		brd = KLCF_NEXT(brd);
+		if (brd)
+			brd = find_lboard(brd, KLTYPE_SNIA);
+		else
+			break;
+	} while(brd);
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_all_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	devfs_handle_t node_vertex;
+	char path_buffer[100];
+	int rv;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			/* No routers stored in this node's memory */
+			continue;
+
+		do {
+			ASSERT(brd);
+			GRPRINTF(("Router board struct is %p\n", brd));
+
+			/* Don't add duplicate boards. */
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+
+			GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_geoid));
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("Router path is %s\n", path_buffer));
+
+			/* Add the router */
+			GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
+				path_buffer, hwgraph_root));
+			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+			if (rv != GRAPH_SUCCESS)
+				PRINT_PANIC("Router vertex creation "
+						  "failed.  Path == %s",
+					path_buffer);
+
+			GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
+					brd));
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd),
+			 KLTYPE_ROUTER)) );
+
+		GRPRINTF(("klhwg_add_all_routers: Done.\n"));
+	}
+
+}
+
+/* ARGSUSED */
+void
+klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
+			 cnodeid_t cnode, nasid_t nasid)
+{
+	klrou_t *router;
+	char path_buffer[50];
+	char dest_path[50];
+	devfs_handle_t router_hndl;
+	devfs_handle_t dest_hndl;
+	int rc;
+	int port;
+	lboard_t *dest_brd;
+
+	GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
+			cnode));
+
+	/* Don't add duplicate boards. */
+	if (brd->brd_flags & DUPLICATE_BOARD) {
+		GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
+			brd, cnode));
+		return;
+	}
+
+	/* Generate a hardware graph path for this board. */
+	board_to_path(brd, path_buffer);
+
+	rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
+
+	if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
+			return;
+
+	if (rc != GRAPH_SUCCESS)
+		printk(KERN_WARNING  "Can't find router: %s", path_buffer);
+
+	/* We don't know what to do with multiple router components */
+	if (brd->brd_numcompts != 1) {
+		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
+			brd->brd_numcompts);
+		return;
+	}
+
+
+	/* Convert component 0 to klrou_t ptr */
+	router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
+					      brd->brd_compts[0]);
+
+	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+		/* See if the port's active */
+		if (router->rou_port[port].port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
+				 port));
+			continue;
+		}
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) 
+		    == INVALID_CNODEID) {
+			continue;
+		}
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				router->rou_port[port].port_nasid,
+				router->rou_port[port].port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find router: %s", dest_path);
+		}
+		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
+			  path_buffer, port, dest_path));
+
+		sprintf(dest_path, "%d", port);
+
+		rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
+
+		if (rc == GRAPH_DUP) {
+			GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
+				  port, router->rou_port[port].port_nasid,
+				  path_buffer, dest_path));
+			continue;
+		}
+
+		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
+			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+		
+	}
+}
+
+
+void
+klhwg_connect_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+
+			nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+			klhwg_connect_one_router(hwgraph_root, brd,
+						 cnode, nasid);
+
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+}
+
+
+
+void
+klhwg_connect_hubs(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	klhub_t *hub;
+	lboard_t *dest_brd;
+	devfs_handle_t hub_hndl;
+	devfs_handle_t dest_hndl;
+	char path_buffer[50];
+	char dest_path[50];
+	graph_error_t rc;
+	int port;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
+			cnode));
+
+		brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+		ASSERT(brd);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+
+		for (port = 1; port <= MAX_NI_PORTS; port++) {
+			/* See if the port's active */
+			if (hub->hub_port[port].port_nasid == INVALID_NASID) {
+				GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
+				continue;
+			}
+
+			if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port[port].port_nasid) == INVALID_CNODEID)
+				continue;
+
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
+			rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
+
+			if (rc != GRAPH_SUCCESS)
+				printk(KERN_WARNING  "Can't find hub: %s", path_buffer);
+
+			dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+					hub->hub_port[port].port_nasid,
+					hub->hub_port[port].port_offset);
+
+			/* Generate a hardware graph path for this board. */
+			board_to_path(dest_brd, dest_path);
+
+			rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+			if (rc != GRAPH_SUCCESS) {
+				if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+					continue;
+				PRINT_PANIC("Can't find board: %s", dest_path);
+			} else {
+				char buf[1024];
+		
+
+				GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
+			  	path_buffer, dest_path));
+
+				rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl);
+				sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT);
+				rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl);
+				sprintf(buf,"%d",port);
+				rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf);
+
+				if (rc != GRAPH_SUCCESS)
+					PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
+					path_buffer, dest_path, (void *)dest_hndl, rc);
+
+			}
+		}
+	}
+}
+
+/* Store the pci/vme disabled board information as extended administrative
+ * hints which can later be used by the drivers using the device/driver
+ * admin interface. 
+ */
+void
+klhwg_device_disable_hints_add(void)
+{
+	cnodeid_t	cnode; 		/* node we are looking at */
+	nasid_t		nasid;		/* nasid of the node */
+	lboard_t	*board;		/* board we are looking at */
+	int		comp_index;	/* component index */
+	klinfo_t	*component;	/* component in the board we are
+					 * looking at 
+					 */
+	char		device_name[MAXDEVNAME];
+	
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		/* Check out all the board info stored  on a node */
+		while(board) {
+			/* No need to look at duplicate boards or non-io 
+			 * boards
+			 */
+			if (KL_CONFIG_DUPLICATE_BOARD(board) ||
+			    KLCLASS(board->brd_type) != KLCLASS_IO) {
+				board = KLCF_NEXT(board);
+				continue;
+			}
+			/* Check out all the components of a board */
+			for (comp_index = 0; 
+			     comp_index < KLCF_NUM_COMPS(board);
+			     comp_index++) {
+				component = KLCF_COMP(board,comp_index);
+				/* If the component is enabled move on to
+				 * the next component
+				 */
+				if (KLCONFIG_INFO_ENABLED(component))
+					continue;
+				/* NOTE : Since the prom only supports
+				 * the disabling of pci devices the following
+				 * piece of code makes sense. 
+				 * Make sure that this assumption is valid
+				 */
+				/* This component is disabled. Store this
+				 * hint in the extended device admin table
+				 */
+				/* Get the canonical name of the pci device */
+				device_component_canonical_name_get(board,
+							    component,
+							    device_name);
+#ifdef DEBUG
+				printf("%s DISABLED\n",device_name);
+#endif				
+			}
+			/* go to the next board info stored on this 
+			 * node 
+			 */
+			board = KLCF_NEXT(board);
+		}
+	}
+}
+
+void
+klhwg_add_all_modules(devfs_handle_t hwgraph_root)
+{
+	cmoduleid_t	cm;
+	char		name[128];
+	devfs_handle_t	vhdl;
+	devfs_handle_t  module_vhdl;
+	int		rc;
+	char		buffer[16];
+
+	/* Add devices under each module */
+
+	for (cm = 0; cm < nummodules; cm++) {
+		/* Use module as module vertex fastinfo */
+
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
+		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
+
+		rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl);
+		ASSERT(rc == GRAPH_SUCCESS);
+		rc = rc;
+
+		hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]);
+
+		/* Add system controller */
+		sprintf(name,
+			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
+			buffer);
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
+		rc = rc;
+
+		hwgraph_info_add_LBL(vhdl,
+				     INFO_LBL_ELSC,
+				     (arbitrary_info_t) (__psint_t) 1);
+
+	}
+}
+
+void
+klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
+{
+	cnodeid_t	cnode;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_node(hwgraph_root, cnode, NULL);
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
+	}
+
+	/*
+	 * As for router hardware inventory information, we set this
+	 * up in router.c. 
+	 */
+	
+	klhwg_add_all_routers(hwgraph_root);
+	klhwg_connect_routers(hwgraph_root);
+	klhwg_connect_hubs(hwgraph_root);
+
+	/* Go through the entire system's klconfig
+	 * to figure out which pci components have been disabled
+	 */
+	klhwg_device_disable_hints_add();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/l1.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/l1.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/l1.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/l1.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,239 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/* In general, this file is organized in a hierarchy from lower-level
+ * to higher-level layers, as follows:
+ *
+ *	UART routines
+ *	Bedrock/L1 "PPP-like" protocol implementation
+ *	System controller "message" interface (allows multiplexing
+ *		of various kinds of requests and responses with
+ *		console I/O)
+ *	Console interface:
+ *	  "l1_cons", the glue that allows the L1 to act
+ *		as the system console for the stdio libraries
+ *
+ * Routines making use of the system controller "message"-style interface
+ * can be found in l1_command.c.
+ */
+
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/uart16550.h>
+#include <asm/sn/simulator.h>
+
+
+#define UART_BAUD_RATE          57600
+
+int 
+get_L1_baud(void)
+{
+    return UART_BAUD_RATE;
+}
+
+
+
+/* Return the current interrupt level */
+int
+l1_get_intr_value( void )
+{
+	return(0);
+}
+
+/* Disconnect the callup functions - throw away interrupts */
+
+void
+l1_unconnect_intr(void)
+{
+}
+
+/* Set up uart interrupt handling for this node's uart */
+
+void
+l1_connect_intr(void *rx_notify, void *tx_notify)
+{
+#if 0
+	// Will need code here for sn2 - something like this
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid());
+	intr_connect_level(console_nodepda->node_first_cpu,
+                                SGI_UART_VECTOR, INTPEND0_MAXMASK,
+                                dummy_intr_func);
+	request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8),
+                                intr_func, SA_INTERRUPT | SA_SHIRQ,
+                                "l1_protocol_driver", (void *)sc);
+#endif
+}
+
+
+/* These are functions to use from serial_in/out when in protocol
+ * mode to send and receive uart control regs. These are external
+ * interfaces into the protocol driver.
+ */
+
+void
+l1_control_out(int offset, int value)
+{
+	/* quietly ignore unless simulator */
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		if ( master_node_bedrock_address != (u64)0 ) {
+			writeb(value, (unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		}
+		return;
+	}
+}
+
+/* Console input exported interface. Return a register value.  */
+
+int
+l1_control_in_polled(int offset)
+{
+	static int l1_control_in_local(int);
+
+	return(l1_control_in_local(offset));
+}
+
+int
+l1_control_in(int offset)
+{
+	static int l1_control_in_local(int);
+
+	return(l1_control_in_local(offset));
+}
+
+static int
+l1_control_in_local(int offset)
+{
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		ret = readb((unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		return(ret);
+	}		
+	if ( offset == REG_LSR ) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if ( !sal_call_status && input ) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+	return(ret);
+}
+
+/*
+ * Console input exported interface. Return a character (if one is available)
+ */
+
+int
+l1_serial_in_polled(void)
+{
+	static int l1_serial_in_local(void);
+
+	return(l1_serial_in_local());
+}
+
+int
+l1_serial_in(void)
+{
+	static int l1_serial_in_local(void);
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+	}	
+	return(l1_serial_in_local());
+}
+
+static int
+l1_serial_in_local(void)
+{
+	int ch;
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+	}		
+
+	if ( !(ia64_sn_console_getc(&ch)) )
+		return(ch);
+	else
+		return(0);
+}
+
+/* Console output exported interface. Write message to the console.  */
+
+int
+l1_serial_out( char *str, int len )
+{
+	int counter = len;
+
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+	/* Need to setup SAL calls so the PROM calls will work */
+	{
+		static int inited;
+		void early_sn_setup(void);
+		if(!inited) {
+			inited=1;
+			early_sn_setup();
+		}
+	}
+#endif
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		void early_sn_setup(void);
+		if (!master_node_bedrock_address)
+			early_sn_setup();
+		if ( master_node_bedrock_address != (u64)0 ) {
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+			/* This is an easy way to pre-pend the output to know whether the output
+			 * was done via sal or directly */
+			writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+#endif	/* FLAG_DIRECT_CONSOLE_WRITES */
+			while ( counter > 0 ) {
+				writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				counter--;
+				str++;
+			}
+		}
+		return(len);
+	}
+
+	/* Attempt to write things out thru the sal */
+	if ( ia64_sn_console_putb(str, len) )
+		return(0);
+	return((counter <= 0) ? 0 : (len - counter));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/l1_command.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/l1_command.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/l1_command.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/l1_command.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,195 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */ 
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/sn_sal.h>
+#include <linux/ctype.h>
+
+#define ELSC_TIMEOUT	1000000		/* ELSC response timeout (usec) */
+#define LOCK_TIMEOUT	5000000		/* Hub lock timeout (usec) */
+
+#define hub_cpu_get()	0
+
+#define LBYTE(caddr)	(*(char *) caddr)
+
+extern char *bcopy(const char * src, char * dest, int count);
+
+#define LDEBUG		0
+
+/*
+ * ELSC data is in NVRAM page 7 at the following offsets.
+ */
+
+#define NVRAM_MAGIC_AD	0x700		/* magic number used for init */
+#define NVRAM_PASS_WD	0x701		/* password (4 bytes in length) */
+#define NVRAM_DBG1	0x705		/* virtual XOR debug switches */
+#define NVRAM_DBG2	0x706		/* physical XOR debug switches */
+#define NVRAM_CFG	0x707		/* ELSC Configuration info */
+#define NVRAM_MODULE	0x708		/* system module number */
+#define NVRAM_BIST_FLG	0x709		/* BIST flags (2 bits per nodeboard) */
+#define NVRAM_PARTITION 0x70a		/* module's partition id */
+#define	NVRAM_DOMAIN	0x70b		/* module's domain id */
+#define	NVRAM_CLUSTER	0x70c		/* module's cluster id */
+#define	NVRAM_CELL	0x70d		/* module's cellid */
+
+#define NVRAM_MAGIC_NO	0x37		/* value of magic number */
+#define NVRAM_SIZE	16		/* 16 bytes in nvram */
+
+
+/* elsc_display_line writes up to 12 characters to either the top or bottom
+ * line of the L1 display.  line points to a buffer containing the message
+ * to be displayed.  The zero-based line number is specified by lnum (so
+ * lnum == 0 specifies the top line and lnum == 1 specifies the bottom).
+ * Lines longer than 12 characters, or line numbers not less than
+ * L1_DISPLAY_LINES, cause elsc_display_line to return an error.
+ */
+int elsc_display_line(nasid_t nasid, char *line, int lnum)
+{
+    return 0;
+}
+
+/*
+ * iobrick routines
+ */
+
+/* iobrick_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+
+
+int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+	int result = 0;
+
+	if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) )
+		return( ELSC_ERROR_CMD_SEND );
+
+	*rack = (result & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+	*bay = (result & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+	*brick_type = (result & L1_ADDR_TYPE_MASK) >> L1_ADDR_TYPE_SHFT;
+	*brick_type = toupper(*brick_type);
+
+	return 0;
+}
+
+
+int iobrick_module_get(nasid_t nasid)
+{
+    uint rnum, rack, bay, brick_type, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = iobrick_rack_bay_type_get(nasid, &rnum, &bay, &brick_type)) < 0)
+        return ret;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+        return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;           
+    t = rnum / 100;             /* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;              /* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;              /* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    switch( brick_type ) {
+      case 'I': 
+	brick_type = MODULE_IBRICK; break;
+      case 'P':
+	brick_type = MODULE_PBRICK; break;
+      case 'X':
+	brick_type = MODULE_XBRICK; break;
+    }
+
+    ret = RBT_TO_MODULE(rack, bay, brick_type);
+
+    return ret;
+}
+
+/*
+ * iobrick_module_get_nasid() returns a module_id which has the brick
+ * type encoded in bits 15-12, but this is not the true brick type...
+ * The module_id returned by iobrick_module_get_nasid() is modified
+ * to make a PEBRICKs & PXBRICKs look like a PBRICK.  So this routine
+ * iobrick_type_get_nasid() returns the true unmodified brick type.
+ */
+int
+iobrick_type_get_nasid(nasid_t nasid)
+{
+    uint rack, bay, type;
+    int t, ret;
+    extern char brick_types[];
+
+    if ((ret = iobrick_rack_bay_type_get(nasid, &rack, &bay, &type)) < 0) {
+        return ret;
+    }
+
+    /* convert brick_type to lower case */
+    if ((type >= 'A') && (type <= 'Z'))
+        type = type - 'A' + 'a';
+
+    /* convert to a module.h brick type */
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+        if( brick_types[t] == type )
+            return t;
+    }
+
+    return -1;    /* unknown brick */
+}
+
+int iobrick_module_get_nasid(nasid_t nasid)
+{
+    int io_moduleid;
+
+#ifdef PIC_LATER
+    uint rack, bay;
+
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+
+        io_moduleid = peer_iobrick_module_get(sc, rack, bay);
+    }
+#endif	/* PIC_LATER */
+    io_moduleid = iobrick_module_get(nasid);
+    return io_moduleid;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_init.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_SN_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_SN_init.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,160 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/snconfig.h>
+
+extern int numcpus;
+extern char arg_maxnodes[];
+extern cpuid_t master_procid;
+
+extern int hasmetarouter;
+
+int		maxcpus;
+cpumask_t	boot_cpumask;
+hubreg_t	region_mask = 0;
+
+
+extern xwidgetnum_t hub_widget_id(nasid_t);
+
+extern int valid_icache_reasons;	/* Reasons to flush the icache */
+extern int valid_dcache_reasons;	/* Reasons to flush the dcache */
+extern u_char miniroot;
+extern volatile int	need_utlbmiss_patch;
+extern void iograph_early_init(void);
+
+nasid_t master_nasid = INVALID_NASID;		/* This is the partition master nasid */
+nasid_t master_baseio_nasid = INVALID_NASID;	/* This is the master base I/O nasid */
+
+
+/*
+ * mlreset(void)
+ * 	very early machine reset - at this point NO interrupts have been
+ * 	enabled; nor is memory, tlb, p0, etc setup.
+ *
+ * 	slave is zero when mlreset is called for the master processor and
+ *	is nonzero thereafter.
+ */
+
+
+void
+mlreset(int slave)
+{
+	/*
+	 * We are the master cpu and node.
+	 */ 
+	master_nasid = get_nasid();
+	set_master_bridge_base();
+
+	/* We're the master processor */
+	master_procid = smp_processor_id();
+	master_nasid = cpuid_to_nasid(master_procid);
+
+	/*
+	 * master_nasid we get back better be same as one from
+	 * get_nasid()
+	 */
+	ASSERT_ALWAYS(master_nasid == get_nasid());
+
+	/* early initialization of iograph */
+	iograph_early_init();
+
+	/* Initialize Hub Pseudodriver Management */
+	hubdev_init();
+}
+
+
+/* XXX - Move the meat of this to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the nodepda.
+ */
+void init_platform_nodepda(nodepda_t *npda, cnodeid_t node)
+{
+	hubinfo_t hubinfo;
+
+	extern void router_map_init(nodepda_t *);
+	extern void router_queue_init(nodepda_t *,cnodeid_t);
+	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
+
+	/* Allocate per-node platform-dependent data */
+	hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s));
+
+	npda->pdinfo = (void *)hubinfo;
+	hubinfo->h_nodepda = npda;
+	hubinfo->h_cnodeid = node;
+	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
+
+	spin_lock_init(&hubinfo->h_crblock);
+
+	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
+	npda->xbow_peer = INVALID_NASID;
+
+	/* 
+	 * Initialize the linked list of
+	 * router info pointers to the dependent routers
+	 */
+	npda->npda_rip_first = NULL;
+
+	/*
+	 * npda_rip_last always points to the place
+	 * where the next element is to be inserted
+	 * into the list 
+	 */
+	npda->npda_rip_last = &npda->npda_rip_first;
+	npda->geoid.any.type = GEO_TYPE_INVALID;
+
+	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
+}
+
+/* XXX - Move the interrupt stuff to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the processor pda.
+ * Must be done _after_ init_platform_nodepda().
+ * If we need a lock here, something else is wrong!
+ */
+void init_platform_pda(cpuid_t cpu)
+{
+}
+
+void
+update_node_information(cnodeid_t cnodeid)
+{
+	nodepda_t *npda = NODEPDA(cnodeid);
+	nodepda_router_info_t *npda_rip;
+	
+	/* Go through the list of router info 
+	 * structures and copy some frequently
+	 * accessed info from the info hanging
+	 * off the corresponding router vertices
+	 */
+	npda_rip = npda->npda_rip_first;
+	while(npda_rip) {
+		if (npda_rip->router_infop) {
+			npda_rip->router_portmask = 
+				npda_rip->router_infop->ri_portmask;
+			npda_rip->router_slot = 
+				npda_rip->router_infop->ri_slotnum;
+		} else {
+			/* No router, no ports. */
+			npda_rip->router_portmask = 0;
+		}
+		npda_rip = npda_rip->router_next;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_intr.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_SN_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_SN_intr.c	2003-05-22 22:06:27.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/sn/pci/pcibr_private.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sn/sn2/shubio.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
 
@@ -44,6 +45,26 @@
 extern nasid_t master_nasid;
 
 //  Initialize some shub registers for interrupts, both IO and error.
+//  
+
+#ifdef BRINGUP2
+static long vec1_opt, ii0_opt;
+static int __init set_vec1_opt(char *str)
+{
+        vec1_opt = 1;
+        return 1;
+}
+
+static int __init set_ii0_opt(char *str)
+{
+        ii0_opt = 1;
+        return 1;
+}
+
+__setup("vec1", set_vec1_opt);
+__setup("ii0", set_ii0_opt);
+#endif
+
 
 void
 intr_init_vecblk( nodepda_t *npda,
@@ -51,24 +72,15 @@
 		int sn)
 {
 	int 			nasid = cnodeid_to_nasid(node);
-	nasid_t			console_nasid;
 	sh_ii_int0_config_u_t	ii_int_config;
 	cpuid_t			cpu;
 	cpuid_t			cpu0, cpu1;
 	nodepda_t		*lnodepda;
 	sh_ii_int0_enable_u_t	ii_int_enable;
-	sh_local_int0_config_u_t	local_int_config;
-	sh_local_int0_enable_u_t	local_int_enable;
-	sh_fsb_system_agent_config_u_t	fsb_system_agent;
 	sh_int_node_id_config_u_t	node_id_config;
-	int is_console;
+	extern void sn_init_cpei_timer(void);
+	static int timer_added = 0;
 
-	console_nasid = get_console_nasid();
-	if (console_nasid < 0) {
-		console_nasid = master_nasid;
-	}
-
-	is_console = nasid == console_nasid;
 
 	if (is_headless_node(node) ) {
 		int cnode;
@@ -95,13 +107,15 @@
 	}
 
 	// Get the physical id's of the cpu's on this node.
-	cpu0 = id_eid_to_cpu_physical_id(nasid, 0);
-	cpu1 = id_eid_to_cpu_physical_id(nasid, 1);
+	cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0);
+	cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2);
 
 	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0);
 	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0);
 
+
 	// The II_INT_CONFIG register for cpu 0.
+	ii_int_config.sh_ii_int0_config_regval = 0;
 	ii_int_config.sh_ii_int0_config_s.type = 0;
 	ii_int_config.sh_ii_int0_config_s.agt = 0;
 	ii_int_config.sh_ii_int0_config_s.pid = cpu0;
@@ -110,7 +124,9 @@
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG),
 		ii_int_config.sh_ii_int0_config_regval);
 
+
 	// The II_INT_CONFIG register for cpu 1.
+	ii_int_config.sh_ii_int0_config_regval = 0;
 	ii_int_config.sh_ii_int0_config_s.type = 0;
 	ii_int_config.sh_ii_int0_config_s.agt = 0;
 	ii_int_config.sh_ii_int0_config_s.pid = cpu1;
@@ -119,101 +135,28 @@
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG),
 		ii_int_config.sh_ii_int0_config_regval);
 
+
 	// Enable interrupts for II_INT0 and 1.
+	ii_int_enable.sh_ii_int0_enable_regval = 0;
 	ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1;
+#if defined(BUS_INT_WAR) && defined(CONFIG_SHUB_1_0_SPECIFIC)
+	/* Dont enable any ints from II. We will poll for interrupts. */
+	ii_int_enable.sh_ii_int0_enable_s.ii_enable = 0;
+
+	/* Enable IPIs. We use them ONLY for send INITs to hung cpus */
+	*(volatile long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT_ENABLE) = 1;
+#endif
 
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE),
 		ii_int_enable.sh_ii_int0_enable_regval);
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE),
 		ii_int_enable.sh_ii_int0_enable_regval);
 
-	// init error regs
-	// LOCAL_INT0 is for the UART only.
-
-	local_int_config.sh_local_int0_config_s.type = 0;
-	local_int_config.sh_local_int0_config_s.agt = 0;
-	local_int_config.sh_local_int0_config_s.pid = cpu;
-	local_int_config.sh_local_int0_config_s.base = 0;
-	local_int_config.sh_local_int0_config_s.idx = SGI_UART_VECTOR;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	// LOCAL_INT1 is for all hardware errors.
-	// It will send a BERR, which will result in an MCA.
-	local_int_config.sh_local_int0_config_s.idx = 0;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	// Clear the LOCAL_INT_ENABLE register.
-	local_int_enable.sh_local_int0_enable_regval = 0;
-
-	if (is_console) {
-		// Enable the UART interrupt.  Only applies to the console nasid.
-		local_int_enable.sh_local_int0_enable_s.uart_int = 1;
-
-		HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_ENABLE),
-			local_int_enable.sh_local_int0_enable_regval);
-	}
-
-	// Enable all the error interrupts.
-	local_int_enable.sh_local_int0_enable_s.uart_int = 0;
-	local_int_enable.sh_local_int0_enable_s.pi_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.lb_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.ii_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.pi_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.system_shutdown_int = 1;
-	local_int_enable.sh_local_int0_enable_s.l1_nmi_int = 1;
-	local_int_enable.sh_local_int0_enable_s.stop_clock = 1;
-
-
-	// Send BERR, rather than an interrupt, for shub errors.
-	local_int_config.sh_local_int0_config_s.agt = 1;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	// Make sure BERR is enabled.
-	fsb_system_agent.sh_fsb_system_agent_config_regval = 
-		HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG) );
-	fsb_system_agent.sh_fsb_system_agent_config_s.berr_assert_en = 1;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG),
-		fsb_system_agent.sh_fsb_system_agent_config_regval);
-
-	// Set LOCAL_INT2 to field CEs
-
-	local_int_enable.sh_local_int0_enable_regval = 0;
-
-	local_int_config.sh_local_int0_config_s.agt = 0;
-	local_int_config.sh_local_int0_config_s.idx = SGI_SHUB_ERROR_VECTOR;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	local_int_enable.sh_local_int0_enable_s.pi_ce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_ce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_ce_int = 1;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	// Make sure all the rest of the LOCAL_INT regs are disabled.
-	local_int_enable.sh_local_int0_enable_regval = 0;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT3_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT4_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
 
+	if (!timer_added) { // can only init the timer once.
+		timer_added = 1;
+		sn_init_cpei_timer();
+	}
 }
 
 // (Un)Reserve an irq on this cpu.
@@ -225,12 +168,17 @@
 {
 	int i;
 	irqpda_t	*irqs = irqpdaindr[cpu];
+	static int	nextvec=IA64_SN2_FIRST_DEVICE_VECTOR;
 
 	if (reserve) {
 		if (bit < 0) {
-			for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {
+			for (i = nextvec; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {
 				if (irqs->irq_flags[i] == 0) {
 					bit = i;
+#ifdef BRINGUP2
+					if (vec1_opt)
+						nextvec = i+1;
+#endif
 					break;
 				}
 			}
@@ -343,6 +291,10 @@
 		if (min_count > intrs) {
 			min_count = intrs;
 			best_cpu = cpu;
+#ifdef BRINGUP2
+			if (ii0_opt)
+				break;
+#endif
 		}
 	}
 	return best_cpu;
@@ -393,31 +345,40 @@
 		int *resp_bit)
 {
 	cpuid_t		cpuid;
-	cnodeid_t	candidate = -1;
+	cpuid_t		candidate = CPU_NONE;
+	cnodeid_t	candidate_node;
 	devfs_handle_t	pconn_vhdl;
 	pcibr_soft_t	pcibr_soft;
+	int 		bit;
 
 /* SN2 + pcibr addressing limitation */
 /* Due to this limitation, all interrupts from a given bridge must go to the name node.*/
+/* The interrupt must also be targetted for the same processor. */
 /* This limitation does not exist on PIC. */
+/* But, the processor limitation will stay.  The limitation will be similar to */
+/* the bedrock/xbridge limit regarding PI's */
 
 	if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) &&
 		( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) {
 			if (pcibr_soft->bsi_err_intr) {
-				candidate = cpuid_to_cnodeid( ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid);
+				candidate =  ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
 			}
 	}
 
-	if (candidate >= 0) {
-		// The node was chosen already when we assigned the error interrupt.
-		cpuid = intr_bit_reserve_test(CPU_NONE,
-						0,
-						candidate,
-						req_bit,
-						0,
-						owner_dev,
-						name,
-						resp_bit);
+
+	if (candidate != CPU_NONE) {
+		// The cpu was chosen already when we assigned the error interrupt.
+		bit = intr_reserve_level(candidate, 
+					req_bit, 
+					resflags, 
+					owner_dev, 
+					name);
+		if (bit < 0) {
+			cpuid = CPU_NONE;
+		} else {
+			cpuid = candidate;
+			*resp_bit = bit;
+		}
 	} else {
 		// Need to choose one.  Try the controlling c-brick first.
 		cpuid = intr_bit_reserve_test(CPU_NONE,
@@ -434,10 +395,9 @@
 		return cpuid;
 	}
 
-	if (candidate >= 0) {
-		printk("Cannot target interrupt to target node (%d).\n",candidate);
-		return CPU_NONE;
-	} else {
+	if (candidate  != CPU_NONE) {
+		printk("Cannot target interrupt to target node (%ld).\n",candidate);
+		return CPU_NONE; } else {
 		printk("Cannot target interrupt to closest node (%d) 0x%p\n",
 			master_node_get(dev), (void *)owner_dev);
 	}
@@ -448,11 +408,11 @@
 	{
 		static cnodeid_t last_node = -1;
 		if (last_node >= numnodes) last_node = 0;
-		for (candidate = last_node + 1; candidate != last_node; candidate++) {
-			if (candidate == numnodes) candidate = 0;
+		for (candidate_node = last_node + 1; candidate_node != last_node; candidate_node++) {
+			if (candidate_node == numnodes) candidate_node = 0;
 			cpuid = intr_bit_reserve_test(CPU_NONE,
 							0,
-							candidate,
+							candidate_node,
 							req_bit,
 							0,
 							owner_dev,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_iograph.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_iograph.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_iograph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/ml_iograph.c	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,1395 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+
+/* #define IOGRAPH_DEBUG */
+#ifdef IOGRAPH_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* IOGRAPH_DEBUG */
+
+/* #define PROBE_TEST */
+
+/* At most 2 hubs can be connected to an xswitch */
+#define NUM_XSWITCH_VOLUNTEER 2
+
+extern unsigned char Is_pic_on_this_nasid[512];
+
+/*
+ * Track which hubs have volunteered to manage devices hanging off of
+ * a Crosstalk Switch (e.g. xbow).  This structure is allocated,
+ * initialized, and hung off the xswitch vertex early on when the
+ * xswitch vertex is created.
+ */
+typedef struct xswitch_vol_s {
+	mutex_t xswitch_volunteer_mutex;
+	int		xswitch_volunteer_count;
+	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
+} *xswitch_vol_t;
+
+void
+xswitch_vertex_init(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+	extern void * snia_kmem_zalloc(size_t size, int flag);
+
+	xvolinfo = snia_kmem_zalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
+	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
+	rc = hwgraph_info_add_LBL(xswitch, 
+			INFO_LBL_XSWITCH_VOL,
+			(arbitrary_info_t)xvolinfo);
+	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
+}
+
+
+/*
+ * When assignment of hubs to widgets is complete, we no longer need the
+ * xswitch volunteer structure hanging around.  Destroy it.
+ */
+static void
+xswitch_volunteer_delete(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+	extern void snia_kmem_free(void *ptr, size_t size);
+
+	rc = hwgraph_info_remove_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL,
+				(arbitrary_info_t *)&xvolinfo);
+	snia_kmem_free(xvolinfo, sizeof(struct xswitch_vol_s));
+}
+/*
+ * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
+ */
+/* ARGSUSED */
+static void
+volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
+{
+	xswitch_vol_t xvolinfo = NULL;
+	devfs_handle_t hubv;
+	hubinfo_t hubinfo;
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    if (!is_headless_node_vertex(master))
+		    printk(KERN_WARNING
+			"volunteer for widgets: vertex 0x%p has no info label",
+			(void *)xswitch);
+	    return;
+	}
+
+	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
+	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
+	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
+	xvolinfo->xswitch_volunteer_count++;
+
+	/*
+	 * if dual ported, make the lowest widgetid always be 
+	 * xswitch_volunteer[0].
+	 */
+	if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		hubinfo_get(hubv, &hubinfo);
+		if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
+			xvolinfo->xswitch_volunteer[0] = 
+						xvolinfo->xswitch_volunteer[1];
+			xvolinfo->xswitch_volunteer[1] = hubv;
+		}
+	}
+	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
+}
+
+extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
+
+/*
+ * Assign all the xwidgets hanging off the specified xswitch to the
+ * Crosstalk masters that have volunteered for xswitch duty.
+ */
+/* ARGSUSED */
+static void
+assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
+{
+	xswitch_info_t xswitch_info;
+	xswitch_vol_t xvolinfo = NULL;
+	xwidgetnum_t widgetnum;
+	int num_volunteer;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+	extern int iobrick_type_get_nasid(nasid_t);
+
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	
+	xswitch_info = xswitch_info_get(xswitch);
+	ASSERT(xswitch_info != NULL);
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    if (!is_headless_node_vertex(hubv))
+		    printk(KERN_WARNING
+			"assign_widgets_to_volunteers:vertex 0x%p has "
+			" no info label",
+			(void *)xswitch);
+	    return;
+	}
+
+	num_volunteer = xvolinfo->xswitch_volunteer_count;
+	ASSERT(num_volunteer > 0);
+
+	/* Assign master hub for xswitch itself.  */
+	if (HUB_WIDGET_ID_MIN > 0) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
+	}
+
+	/*
+	 * TBD: Use administrative information to alter assignment of
+	 * widgets to hubs.
+	 */
+	for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		int i;
+
+		/*
+		 * Ignore disabled/empty ports.
+		 */
+		if (!xbow_port_io_enabled(nasid, widgetnum)) 
+		    continue;
+
+		/*
+		 * If this is the master IO board, assign it to the same 
+		 * hub that owned it in the prom.
+		 */
+		if (is_master_baseio_nasid_widget(nasid, widgetnum)) {
+			extern nasid_t get_master_baseio_nasid(void);
+			for (i=0; i<num_volunteer; i++) {
+				hubv = xvolinfo->xswitch_volunteer[i];
+				hubinfo_get(hubv, &hubinfo);
+				nasid = hubinfo->h_nasid;
+				if (nasid == get_master_baseio_nasid())
+					goto do_assignment;
+			}
+			PRINT_PANIC("Nasid == %d, console nasid == %d",
+				nasid, get_master_baseio_nasid());
+		}
+
+		/*
+		 * Assuming that we're dual-hosted and that PCI cards 
+		 * are naturally placed left-to-right, alternate PCI 
+		 * buses across both Cbricks.   For Pbricks, and Ibricks,
+                 * io_brick_map_widget() returns the PCI bus number
+                 * associated with the given brick type and widget number.
+                 * For Xbricks, it returns the XIO slot number.
+		 */
+
+		i = 0;
+		if (num_volunteer > 1) {
+                        int	       bt;
+
+                       	bt = iobrick_type_get_nasid(nasid);
+                        if (bt >= 0) {
+				/*
+				 * PXBRICK has two busses per widget so this
+				 * algorithm wouldn't work (all busses would
+				 * be assigned to one volunteer). Change the
+				 * bricktype to PBRICK whose mapping is setup
+				 * suchthat 2 of the PICs will be assigned to
+				 * one volunteer and the other one will be
+				 * assigned to the other volunteer.
+				 */
+				if (bt == MODULE_PXBRICK) 
+					bt = MODULE_PBRICK;
+
+			        i = io_brick_map_widget(bt, widgetnum) & 1;
+                        }
+                }
+
+		hubv = xvolinfo->xswitch_volunteer[i];
+
+do_assignment:
+		/*
+		 * At this point, we want to make hubv the master of widgetnum.
+		 */
+		xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
+	}
+
+	xswitch_volunteer_delete(xswitch);
+}
+
+/*
+ * Early iograph initialization.  Called by master CPU in mlreset().
+ * Useful for including iograph.o in kernel.o.
+ */
+void
+iograph_early_init(void)
+{
+/*
+ * Need new way to get this information ..
+ */
+	cnodeid_t cnode;
+	nasid_t nasid;
+	lboard_t *board;
+	
+	/*
+	 * Init. the board-to-hwgraph link early, so FRU analyzer
+	 * doesn't trip on leftover values if we panic early on.
+	 */
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		DBG("iograph_early_init: Found board 0x%p\n", board);
+
+		/* Check out all the board info stored on a node */
+		while(board) {
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+			board = KLCF_NEXT(board);
+			DBG("iograph_early_init: Found board 0x%p\n", board);
+		}
+	}
+
+	hubio_init();
+}
+
+/*
+ * Let boot processor know that we're done initializing our node's IO
+ * and then exit.
+ */
+/* ARGSUSED */
+static void
+io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
+{
+	/* Let boot processor know that we're done. */
+}
+
+/* 
+ * Probe to see if this hub's xtalk link is active.  If so,
+ * return the Crosstalk Identification of the widget that we talk to.  
+ * This is called before any of the Crosstalk infrastructure for 
+ * this hub is set up.  It's usually called on the node that we're
+ * probing, but not always.
+ *
+ * TBD: Prom code should actually do this work, and pass through 
+ * hwid for our use.
+ */
+static void
+early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
+{
+	hubreg_t llp_csr_reg;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+
+	llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
+	/* 
+	 * If link is up, read the widget's part number.
+	 * A direct connect widget must respond to widgetnum=0.
+	 */
+	if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
+		/* TBD: Put hub into "indirect" mode */
+		/*
+		 * We're able to read from a widget because our hub's 
+		 * WIDGET_ID was set up earlier.
+		 */
+		widgetreg_t widget_id = *(volatile widgetreg_t *)
+			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
+
+		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
+		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
+
+		hwid->part_num = XWIDGET_PART_NUM(widget_id);
+		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
+
+		/* TBD: link reset */
+	} else {
+
+		hwid->part_num = XWIDGET_PART_NUM_NONE;
+		hwid->rev_num = XWIDGET_REV_NUM_NONE;
+		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
+	}
+}
+
+/* Add inventory information to the widget vertex 
+ * Right now (module,slot,revision) is being
+ * added as inventory information.
+ */
+static void
+xwidget_inventory_add(devfs_handle_t 		widgetv,
+		      lboard_t 			*board,
+		      struct xwidget_hwid_s 	hwid)
+{
+	if (!board)
+		return;
+	/* Donot add inventory information for the baseio
+	 * on a speedo with an xbox. It has already been
+	 * taken care of in SN00_vmc.
+	 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
+	 */
+	device_inventory_add(widgetv,INV_IOBD,board->brd_type,
+			     geo_module(board->brd_geoid),
+			     SLOTNUM_GETSLOT(board->brd_slot),
+			     hwid.rev_num);
+}
+
+/*
+ * io_xswitch_widget_init
+ *	
+ */
+
+void
+io_xswitch_widget_init(devfs_handle_t  	xswitchv,
+		       devfs_handle_t	hubv,
+		       xwidgetnum_t	widgetnum,
+		       async_attach_t	aa)
+{
+	xswitch_info_t		xswitch_info;
+	xwidgetnum_t		hub_widgetid;
+	devfs_handle_t		widgetv;
+	cnodeid_t		cnode;
+	widgetreg_t		widget_id;
+	nasid_t			nasid, peer_nasid;
+	struct xwidget_hwid_s 	hwid;
+	hubinfo_t		hubinfo;
+	/*REFERENCED*/
+	int			rc;
+	char 			pathname[128];
+	lboard_t		*board = NULL;
+	char			buffer[16];
+	char			bt;
+	moduleid_t		io_module;
+	slotid_t get_widget_slotnum(int xbow, int widget);
+	
+	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
+
+	/*
+	 * Verify that xswitchv is indeed an attached xswitch.
+	 */
+	xswitch_info = xswitch_info_get(xswitchv);
+	ASSERT(xswitch_info != NULL);
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+	hub_widgetid = hubinfo->h_widgetid;
+
+	/*
+	 * Check that the widget is an io widget and is enabled
+	 * on this nasid or the `peer' nasid.  The peer nasid
+	 * is the other hub/bedrock connected to the xbow.
+	 */
+	peer_nasid = NODEPDA(cnode)->xbow_peer;
+	if (peer_nasid == INVALID_NASID)
+		/* If I don't have a peer, use myself. */
+		peer_nasid = nasid;
+	if (!xbow_port_io_enabled(nasid, widgetnum) &&
+	    !xbow_port_io_enabled(peer_nasid, widgetnum)) {
+		return;
+	}
+
+	if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
+		char			name[4];
+		lboard_t dummy;
+
+		/*
+		 * If the current hub is not supposed to be the master 
+		 * for this widgetnum, then skip this widget.
+		 */
+		if (xswitch_info_master_assignment_get(xswitch_info,
+						       widgetnum) != hubv) {
+			return;
+		}
+
+		board = find_lboard_class(
+				(lboard_t *)KL_CONFIG_INFO(nasid),
+				KLCLASS_IOBRICK);
+		if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) {
+		    	board = find_lboard_class(
+					(lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer),
+						KLCLASS_IOBRICK);
+		}
+
+		if (board) {
+			DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+		} else {
+			DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
+			board = &dummy;
+		}
+
+
+		/* Copy over the nodes' geoid info */
+		{
+			lboard_t *brd;
+
+			brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+			if ( brd != (lboard_t *)0 ) {
+				board->brd_geoid = brd->brd_geoid;
+			}
+		}
+
+		/*
+ 		 * Make sure we really want to say xbrick, pbrick,
+		 * etc. rather than XIO, graphics, etc.
+ 		 */
+
+		memset(buffer, 0, 16);
+		format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
+		sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%cbrick" "/%s/%d",
+			buffer,
+			geo_slab(board->brd_geoid),
+			(board->brd_type == KLTYPE_IBRICK) ? 'I' :
+			(board->brd_type == KLTYPE_PBRICK) ? 'P' :
+			(board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
+			EDGE_LBL_XTALK, widgetnum);
+		
+		DBG("io_xswitch_widget_init: path= %s\n", pathname);
+		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+		
+		ASSERT(rc == GRAPH_SUCCESS);
+
+		/* This is needed to let the user programs to map the
+		 * module,slot numbers to the corresponding widget numbers
+		 * on the crossbow.
+		 */
+		device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+		sprintf(name, "%d", widgetnum);
+		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
+		rc = hwgraph_edge_add(xswitchv, widgetv, name);
+		
+		/*
+		 * crosstalk switch code tracks which
+		 * widget is attached to each link.
+		 */
+		xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
+		
+		/*
+		 * Peek at the widget to get its crosstalk part and
+		 * mfgr numbers, then present it to the generic xtalk
+		 * bus provider to have its driver attach routine
+		 * called (or not).
+		 */
+		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
+		hwid.part_num = XWIDGET_PART_NUM(widget_id);
+		hwid.rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
+		/* Store some inventory information about
+		 * the xwidget in the hardware graph.
+		 */
+		xwidget_inventory_add(widgetv,board,hwid);
+
+		(void)xwidget_register(&hwid, widgetv, widgetnum,
+				       hubv, hub_widgetid,
+				       aa);
+
+		ia64_sn_sysctl_iobrick_module_get(nasid, &io_module);
+
+		if (io_module >= 0) {
+			char			buffer[16];
+			devfs_handle_t		to, from;
+
+			memset(buffer, 0, 16);
+			format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
+
+			bt = toupper(MODULE_GET_BTCHAR(io_module));
+			/* Add a helper vertex so xbow monitoring
+			* can identify the brick type. It's simply
+			* an edge from the widget 0 vertex to the
+			*  brick vertex.
+			*/
+
+			sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/"
+				EDGE_LBL_SLAB "/%d/"
+				EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/"
+				"0",
+				buffer, geo_slab(board->brd_geoid));
+			from = hwgraph_path_to_vertex(pathname);
+			ASSERT_ALWAYS(from);
+			sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/"
+				EDGE_LBL_SLAB "/%d/"
+				"%cbrick",
+				buffer, geo_slab(board->brd_geoid), bt);
+
+			to = hwgraph_path_to_vertex(pathname);
+			ASSERT_ALWAYS(to);
+			rc = hwgraph_edge_add(from, to,
+				EDGE_LBL_INTERCONNECT);
+			if (rc == -EEXIST)
+				goto link_done;
+			if (rc != GRAPH_SUCCESS) {
+				printk("%s: Unable to establish link"
+					" for xbmon.", pathname);
+			}
+link_done:
+		}
+
+#ifdef	SN0_USE_BTE
+		bte_bpush_war(cnode, (void *)board);
+#endif
+	}
+}
+
+
+static void
+io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
+{
+	xwidgetnum_t		widgetnum;
+	async_attach_t          aa;
+
+	aa = async_attach_new();
+	
+	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
+	     widgetnum++) {
+		io_xswitch_widget_init(xswitchv,
+				       cnodeid_to_vertex(cnode),
+				       widgetnum, aa);
+	}
+	/* 
+	 * Wait for parallel attach threads, if any, to complete.
+	 */
+	async_attach_waitall(aa);
+	async_attach_free(aa);
+}
+
+/*
+ * For each PCI bridge connected to the xswitch, add a link from the
+ * board's klconfig info to the bridge's hwgraph vertex.  This lets
+ * the FRU analyzer find the bridge without traversing the hardware
+ * graph and risking hangs.
+ */
+static void
+io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
+{
+	xwidgetnum_t		widgetnum;
+	char 			pathname[128];
+	devfs_handle_t		vhdl;
+	nasid_t			nasid, peer_nasid;
+	lboard_t		*board;
+
+
+
+	/* And its connected hub's nasids */
+	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
+	peer_nasid = NODEPDA(cnodeid)->xbow_peer;
+
+	/* 
+	 * Look for paths matching "<widgetnum>/pci" under xswitchv.
+	 * For every widget, init. its lboard's hwgraph link.  If the
+	 * board has a PCI bridge, point the link to it.
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
+		 widgetnum++) {
+		sprintf(pathname, "%d", widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
+		    GRAPH_SUCCESS)
+			continue;
+
+		board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
+				NODEPDA(cnodeid)->geoid);
+		if (board == NULL && peer_nasid != INVALID_NASID) {
+			/*
+			 * Try to find the board on our peer
+			 */
+			board = find_lboard_module(
+				(lboard_t *)KL_CONFIG_INFO(peer_nasid),
+				NODEPDA(cnodeid)->geoid);
+		}
+		if (board == NULL) {
+			printk(KERN_WARNING  "Could not find PROM info for vertex 0x%p, "
+				"FRU analyzer may fail",
+				(void *)vhdl);
+			return;
+		}
+
+		if ( Is_pic_on_this_nasid[nasid] ) {
+			/* Check both buses */
+			sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum);
+			if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+				board->brd_graph_link = vhdl;
+			else {
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum);
+				if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+					board->brd_graph_link = vhdl;
+				else
+					board->brd_graph_link = GRAPH_VERTEX_NONE;
+			}
+		}
+		else {
+			sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+			if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+				board->brd_graph_link = vhdl;
+			else
+				board->brd_graph_link = GRAPH_VERTEX_NONE;
+		}
+	}
+}
+
+/*
+ * Initialize all I/O on the specified node.
+ */
+static void
+io_init_node(cnodeid_t cnodeid)
+{
+	/*REFERENCED*/
+	devfs_handle_t hubv, switchv, widgetv;
+	struct xwidget_hwid_s hwid;
+	hubinfo_t hubinfo;
+	int is_xswitch;
+	nodepda_t	*npdap;
+	struct semaphore *peer_sema = 0;
+	uint32_t	widget_partnum;
+	nodepda_router_info_t *npda_rip;
+	cpu_cookie_t	c = 0;
+	extern int hubdev_docallouts(devfs_handle_t);
+
+	npdap = NODEPDA(cnodeid);
+
+	/*
+	 * Get the "top" vertex for this node's hardware
+	 * graph; it will carry the per-hub hub-specific
+	 * data, and act as the crosstalk provider master.
+	 * It's canonical path is probably something of the
+	 * form /hw/module/%M/slot/%d/node
+	 */
+	hubv = cnodeid_to_vertex(cnodeid);
+	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
+
+	ASSERT(hubv != GRAPH_VERTEX_NONE);
+
+	hubdev_docallouts(hubv);
+
+	/*
+	 * Set up the dependent routers if we have any.
+	 */
+	npda_rip = npdap->npda_rip_first;
+
+	while(npda_rip) {
+		/* If the router info has not been initialized
+		 * then we need to do the router initialization
+		 */
+		if (!npda_rip->router_infop) {
+			router_init(cnodeid,0,npda_rip);
+		}
+		npda_rip = npda_rip->router_next;
+	}
+
+	/*
+	 * Read mfg info on this hub
+	 */
+
+	/* 
+	 * If nothing connected to this hub's xtalk port, we're done.
+	 */
+	early_probe_for_widget(hubv, &hwid);
+	if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
+#ifdef PROBE_TEST
+		if ((cnodeid == 1) || (cnodeid == 2)) {
+			int index;
+
+			for (index = 0; index < 600; index++)
+				DBG("Interfering with device probing!!!\n");
+		}
+#endif
+		/* io_init_done takes cpu cookie as 2nd argument 
+		 * to do a restorenoderun for the setnoderun done 
+		 * at the start of this thread 
+		 */
+		
+		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
+		return;
+		/* NOTREACHED */
+	}
+
+	/* 
+	 * attach our hub_provider information to hubv,
+	 * so we can use it as a crosstalk provider "master"
+	 * vertex.
+	 */
+	xtalk_provider_register(hubv, &hub_provider);
+	xtalk_provider_startup(hubv);
+
+	/*
+	 * Create a vertex to represent the crosstalk bus
+	 * attached to this hub, and a vertex to be used
+	 * as the connect point for whatever is out there
+	 * on the other side of our crosstalk connection.
+	 *
+	 * Crosstalk Switch drivers "climb up" from their
+	 * connection point to try and take over the switch
+	 * point.
+	 *
+	 * Of course, the edges and verticies may already
+	 * exist, in which case our net effect is just to
+	 * associate the "xtalk_" driver with the connection
+	 * point for the device.
+	 */
+
+	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
+
+	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
+
+	ASSERT(switchv != GRAPH_VERTEX_NONE);
+
+	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
+
+	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
+
+	/*
+	 * We need to find the widget id and update the basew_id field
+	 * accordingly. In particular, SN00 has direct connected bridge,
+	 * and hence widget id is Not 0.
+	 */
+
+	widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+
+	if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
+				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
+
+	} else if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == XXBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
+		/* 
+		 * Xbow control register does not have the widget ID field.
+		 * So, hard code the widget ID to be zero.
+		 */
+		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
+		npdap->basew_id = 0;
+
+	} else {
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
+
+		/*NOTREACHED*/
+	}
+	{
+		char widname[10];
+		sprintf(widname, "%x", npdap->basew_id);
+		(void)hwgraph_path_add(switchv, widname, &widgetv);
+		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
+		ASSERT(widgetv != GRAPH_VERTEX_NONE);
+	}
+	
+	nodepda->basew_xc = widgetv;
+
+	is_xswitch = xwidget_hwid_is_xswitch(&hwid);
+
+	/* 
+	 * Try to become the master of the widget.  If this is an xswitch
+	 * with multiple hubs connected, only one will succeed.  Mastership
+	 * of an xswitch is used only when touching registers on that xswitch.
+	 * The slave xwidgets connected to the xswitch can be owned by various
+	 * masters.
+	 */
+	if (device_master_set(widgetv, hubv) == 0) {
+
+		/* Only one hub (thread) per Crosstalk device or switch makes
+		 * it to here.
+		 */
+
+		/* 
+		 * Initialize whatever xwidget is hanging off our hub.
+		 * Whatever it is, it's accessible through widgetnum 0.
+		 */
+		hubinfo_get(hubv, &hubinfo);
+
+		(void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
+
+		if (!is_xswitch) {
+			/* io_init_done takes cpu cookie as 2nd argument 
+			 * to do a restorenoderun for the setnoderun done 
+			 * at the start of this thread 
+			 */
+			io_init_done(cnodeid,c);
+			/* NOTREACHED */
+		}
+
+		/* 
+		 * Special handling for Crosstalk Switches (e.g. xbow).
+		 * We need to do things in roughly the following order:
+		 *	1) Initialize xswitch hardware (done above)
+		 *	2) Determine which hubs are available to be widget masters
+		 *	3) Discover which links are active from the xswitch
+		 *	4) Assign xwidgets hanging off the xswitch to hubs
+		 *	5) Initialize all xwidgets on the xswitch
+		 */
+
+		volunteer_for_widgets(switchv, hubv);
+
+		/* If there's someone else on this crossbow, recognize him */
+		if (npdap->xbow_peer != INVALID_NASID) {
+			nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
+			peer_sema = &peer_npdap->xbow_sema;
+			volunteer_for_widgets(switchv, peer_npdap->node_vertex);
+		}
+
+		assign_widgets_to_volunteers(switchv, hubv);
+
+		/* Signal that we're done */
+		if (peer_sema) {
+			mutex_unlock(peer_sema);
+		}
+		
+	}
+	else {
+	    /* Wait 'til master is done assigning widgets. */
+	    mutex_lock(&npdap->xbow_sema);
+	}
+
+#ifdef PROBE_TEST
+	if ((cnodeid == 1) || (cnodeid == 2)) {
+		int index;
+
+		for (index = 0; index < 500; index++)
+			DBG("Interfering with device probing!!!\n");
+	}
+#endif
+	/* Now both nodes can safely inititialize widgets */
+	io_init_xswitch_widgets(switchv, cnodeid);
+	io_link_xswitch_widgets(switchv, cnodeid);
+
+	/* io_init_done takes cpu cookie as 2nd argument 
+	 * to do a restorenoderun for the setnoderun done 
+	 * at the start of this thread 
+	 */
+	io_init_done(cnodeid,c);
+
+	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
+}
+
+
+#define IOINIT_STKSZ	(16 * 1024)
+
+#define __DEVSTR1 	"/../.master/"
+#define __DEVSTR2 	"/target/"
+#define __DEVSTR3 	"/lun/0/disk/partition/"
+#define	__DEVSTR4	"/../ef"
+
+/*
+ * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
+ */
+#define NUM_BASE_IO_SCSI_CTLR 6
+/*
+ * This tells ioconfig where it can start numbering scsi controllers.
+ * Below this base number, platform-specific handles the numbering.
+ * XXX Irix legacy..controller numbering should be part of devfsd's job
+ */
+int num_base_io_scsi_ctlr = 2; /* used by syssgi */
+devfs_handle_t		base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
+static devfs_handle_t	baseio_enet_vhdl,baseio_console_vhdl;
+
+/*
+ * Put the logical controller number information in the 
+ * scsi controller vertices for each scsi controller that
+ * is in a "fixed position".
+ */
+static void
+scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
+{
+	{
+		int i;
+
+		num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
+
+		/* Initialize base_io_scsi_ctlr_vhdl array */
+		for (i=0; i<num_base_io_scsi_ctlr; i++)
+			base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
+	}
+	{
+	/*
+	 * May want to consider changing the SN0 code, above, to work more like
+	 * the way this works.
+	 */
+	devfs_handle_t base_ibrick_xbridge_vhdl;
+	devfs_handle_t base_ibrick_xtalk_widget_vhdl;
+	devfs_handle_t scsi_ctlr_vhdl;
+	int i;
+	graph_error_t rv;
+
+	/*
+	 * This is a table of "well-known" SCSI controllers and their well-known
+	 * controller numbers.  The names in the table start from the base IBrick's
+	 * Xbridge vertex, so the first component is the xtalk widget number.
+	 */
+	static struct {
+		char	*base_ibrick_scsi_path;
+		int	controller_number;
+	} hardwired_scsi_controllers[] = {
+		{"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
+		{"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
+		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
+		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
+		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
+		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
+		{NULL, -1} /* must be last */
+	};
+
+	base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
+
+	base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
+	hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
+
+	/*
+	 * Iterate through the list of well-known SCSI controllers.
+	 * For each controller found, set it's controller number according
+	 * to the table.
+	 */
+	for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
+		rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
+			hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
+
+		if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
+			continue;
+
+		ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
+		base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
+		device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
+		hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
+	}
+
+	hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
+	}
+}
+
+
+#include <asm/sn/ioerror_handling.h>
+devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
+
+/* Define the system critical vertices and connect them through
+ * a canonical parent-child relationships for easy traversal
+ * during io error handling.
+ */
+static void
+sys_critical_graph_init(void)
+{
+	devfs_handle_t		bridge_vhdl,master_node_vhdl;
+	devfs_handle_t  		xbow_vhdl = GRAPH_VERTEX_NONE;
+	extern devfs_handle_t	hwgraph_root;
+	devfs_handle_t		pci_slot_conn;
+	int			slot;
+	devfs_handle_t		baseio_console_conn;
+
+	DBG("sys_critical_graph_init: FIXME.\n");
+	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
+
+	if (baseio_console_conn == NULL) {
+		return;
+	}
+
+	/* Get the vertex handle for the baseio bridge */
+	bridge_vhdl = device_master_get(baseio_console_conn);
+
+	/* Get the master node of the baseio card */
+	master_node_vhdl = cnodeid_to_vertex(
+				master_node_get(baseio_console_vhdl));
+	
+	/* Add the "root->node" part of the system critical graph */
+
+	sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
+
+	/* Check if we have a crossbow */
+	if (hwgraph_traverse(master_node_vhdl,
+			     EDGE_LBL_XTALK"/0",
+			     &xbow_vhdl) == GRAPH_SUCCESS) {
+		/* We have a crossbow.Add "node->xbow" part of the system 
+		 * critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
+		
+		/* Add "xbow->baseio bridge" of the system critical graph */
+		sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
+
+		hwgraph_vertex_unref(xbow_vhdl);
+	} else 
+		/* We donot have a crossbow. Add "node->baseio_bridge"
+		 * part of the system critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
+
+	/* Add all the populated PCI slot vertices to the system critical
+	 * graph with the bridge vertex as the parent.
+	 */
+	for (slot = 0 ; slot < 8; slot++) {
+		char	slot_edge[10];
+
+		sprintf(slot_edge,"%d",slot);
+		if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
+		    != GRAPH_SUCCESS)
+			continue;
+		sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	hwgraph_vertex_unref(bridge_vhdl);
+
+	/* Add the "ioc3 pci connection point  -> console ioc3" part 
+	 * of the system critical graph
+	 */
+
+	if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_console_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "ethernet pci connection point  -> base ethernet" part of 
+	 * the system  critical graph
+	 */
+	if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_enet_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "scsi controller pci connection point  -> base scsi 
+	 * controller" part of the system critical graph
+	 */
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[0]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[1]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	hwgraph_vertex_unref(baseio_console_conn);
+
+}
+
+static void
+baseio_ctlr_num_set(void)
+{
+	char 			name[MAXDEVNAME];
+	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
+	devfs_handle_t		ioc3_console_vhdl_get(void);
+
+
+	DBG("baseio_ctlr_num_set; FIXME\n");
+	console_vhdl = ioc3_console_vhdl_get();
+	if (console_vhdl == GRAPH_VERTEX_NONE)
+		return;
+	/* Useful for setting up the system critical graph */
+	baseio_console_vhdl = console_vhdl;
+
+	vertex_to_name(console_vhdl,name,MAXDEVNAME);
+
+	strcat(name,__DEVSTR1);
+	pci_vhdl =  hwgraph_path_to_vertex(name);
+	scsi_ctlr_nums_add(pci_vhdl);
+	/* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(pci_vhdl);
+
+	vertex_to_name(console_vhdl, name, MAXDEVNAME);
+	strcat(name, __DEVSTR4);
+	enet_vhdl = hwgraph_path_to_vertex(name);
+
+	/* Useful for setting up the system critical graph */
+	baseio_enet_vhdl = enet_vhdl;
+
+	device_controller_num_set(enet_vhdl, 0);
+	/* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(enet_vhdl);
+}
+/* #endif */
+
+/*
+ * Initialize all I/O devices.  Starting closest to nodes, probe and
+ * initialize outward.
+ */
+void
+init_all_devices(void)
+{
+	/* Governor on init threads..bump up when safe 
+	 * (beware many devfs races) 
+	 */
+	cnodeid_t cnodeid, active;
+
+	active = 0;
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
+                DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
+                io_init_node(cnodeid);
+
+		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
+	}
+
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
+		/*
+	 	 * Update information generated by IO init.
+		 */
+		update_node_information(cnodeid);
+
+	baseio_ctlr_num_set();
+	/* Setup the system critical graph (which is a subgraph of the
+	 * main hwgraph). This information is useful during io error
+	 * handling.
+	 */
+	sys_critical_graph_init();
+
+#if HWG_PRINT
+	hwgraph_print();
+#endif
+
+}
+
+#define toint(x) ((int)(x) - (int)('0'))
+
+void
+devnamefromarcs(char *devnm)
+{
+	int 			val;
+	char 			tmpnm[MAXDEVNAME];
+	char 			*tmp1, *tmp2;
+	
+	val = strncmp(devnm, "dks", 3);
+	if (val != 0) 
+		return;
+	tmp1 = devnm + 3;
+	if (!isdigit(*tmp1))
+		return;
+
+	val = 0;
+	while (isdigit(*tmp1)) {
+		val = 10*val+toint(*tmp1);
+		tmp1++;
+	}
+
+	if(*tmp1 != 'd')
+		return;
+	else
+		tmp1++;
+
+	if ((val < 0) || (val >= num_base_io_scsi_ctlr)) {
+		int i;
+		int viable_found = 0;
+
+		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
+		DBG("prom \"root\" variables of the form dksXdXsX.\n");
+		DBG("To use another disk you must use the full hardware graph path\n\n");
+		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
+		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
+			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
+				DBG("%d ", i);
+				viable_found=1;
+			}
+		}
+		if (viable_found)
+			DBG("\n");
+		else
+			DBG("none found!\n");
+
+		DELAY(15000000);
+		//prom_reboot();
+		panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
+		/* NOTREACHED */
+	}
+		
+	ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
+	vertex_to_name(base_io_scsi_ctlr_vhdl[val],
+		       tmpnm,
+		       MAXDEVNAME);
+	tmp2 = 	tmpnm + strlen(tmpnm);
+	strcpy(tmp2, __DEVSTR2);
+	tmp2 += strlen(__DEVSTR2);
+	while (*tmp1 != 's') {
+		if((*tmp2++ = *tmp1++) == '\0')
+			return;
+	}	
+	tmp1++;
+	strcpy(tmp2, __DEVSTR3);
+	tmp2 += strlen(__DEVSTR3);
+	while ( (*tmp2++ = *tmp1++) )
+		;
+	tmp2--;
+	*tmp2++ = '/';
+	strcpy(tmp2, EDGE_LBL_BLOCK);
+	strcpy(devnm,tmpnm);
+}
+
+static
+struct io_brick_map_s io_brick_tab[] = {
+
+/* Ibrick widget number to PCI bus number map */
+ {      MODULE_IBRICK,                          /* Ibrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        0,                                      /* 0xc            */
+        0,                                      /* 0xd            */
+        2,                                      /* 0xe            */
+        1                                       /* 0xf            */
+     }
+ },
+
+/* Pbrick widget number to PCI bus number map */
+ {      MODULE_PBRICK,                          /* Pbrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        2,                                      /* 0x8            */
+        1,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        5,                                      /* 0xc            */
+        6,                                      /* 0xd            */
+        4,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* PXbrick widget number to PCI bus number map */
+ {      MODULE_PXBRICK,                         /* PXbrick type   */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        1,                                      /* 0xc            */
+        5,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* Xbrick widget to XIO slot map */
+ {      MODULE_XBRICK,                          /* Xbrick type    */ 
+    /*  XIO Slot #                                 Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        1,                                      /* 0x8            */
+        3,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        2,                                      /* 0xc            */
+        4,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        0                                       /* 0xf            */
+    }
+ }
+};
+
+/*
+ * Use the brick's type to map a widget number to a meaningful int
+ */
+int
+io_brick_map_widget(int brick_type, int widget_num)
+{
+        int num_bricks, i;
+
+        /* Calculate number of bricks in table */
+        num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
+
+        /* Look for brick prefix in table */
+        for (i = 0; i < num_bricks; i++) {
+               if (brick_type == io_brick_tab[i].ibm_type)
+                       return(io_brick_tab[i].ibm_map_wid[widget_num]);
+        }
+
+        return 0;
+
+}
+
+/*
+ * Use the device's vertex to map the device's widget to a meaningful int
+ */
+int
+io_path_map_widget(devfs_handle_t vertex)
+{
+        char hw_path_name[MAXDEVNAME];
+        char *wp, *bp, *sp = NULL;
+        int  widget_num;
+	long atoi(char *);
+	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
+
+
+        /* Get the full path name of the vertex */
+        if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
+                                                     MAXDEVNAME))
+                return 0;
+
+        /* Find the widget number in the path name */
+        wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
+        if (wp == NULL)
+                return 0;
+        widget_num = atoi(wp+7);
+        if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
+                return 0;
+
+        /* Find "brick" in the path name */
+        bp = strstr(hw_path_name, "brick");
+        if (bp == NULL)
+                return 0;
+
+        /* Find preceding slash */
+        sp = bp;
+        while (sp > hw_path_name) {
+                sp--;
+                if (*sp == '/')
+                        break;
+        }
+
+        /* Invalid if no preceding slash */
+        if (!sp)
+                return 0;
+
+        /* Bump slash pointer to "brick" prefix */
+        sp++;
+        /*
+         * Verify "brick" prefix length;  valid exaples:
+         * 'I' from "/Ibrick"
+         * 'P' from "/Pbrick"
+         * 'X' from "/Xbrick"
+         */
+         if ((bp - sp) != 1)
+                return 0;
+
+        return (io_brick_map_widget((int)*sp, widget_num));
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/module.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/module.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/module.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/module.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,280 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn1/hubdev.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/sn_cpuid.h>
+
+
+/* #define LDEBUG	1  */
+
+#ifdef LDEBUG
+#define DPRINTF		printk
+#define printf		printk
+#else
+#define DPRINTF(x...)
+#endif
+
+module_t	       *modules[MODULE_MAX];
+int			nummodules;
+
+#define SN00_SERIAL_FUDGE	0x3b1af409d513c2
+#define SN0_SERIAL_FUDGE	0x6e
+
+void
+encode_int_serial(uint64_t src,uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    val = src + SN00_SERIAL_FUDGE;
+
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)dest)[i] =
+	    ((char*)&val)[sizeof(long long)/2 +
+			 ((i%2) ? ((i/2 * -1) - 1) : (i/2))];
+    }
+}
+
+
+void
+decode_int_serial(uint64_t src, uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)&val)[sizeof(long long)/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
+	    ((char*)&src)[i];
+    }
+
+    *dest = val - SN00_SERIAL_FUDGE;
+}
+
+
+void
+encode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+
+	dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+void
+decode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+	dest[MAX_SERIAL_NUM_SIZE/2 +
+	    ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+
+module_t *module_lookup(moduleid_t id)
+{
+    int			i;
+
+    for (i = 0; i < nummodules; i++)
+	if (modules[i]->id == id) {
+	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
+	    return modules[i];
+	}
+
+    return NULL;
+}
+
+/*
+ * module_add_node
+ *
+ *   The first time a new module number is seen, a module structure is
+ *   inserted into the module list in order sorted by module number
+ *   and the structure is initialized.
+ *
+ *   The node number is added to the list of nodes in the module.
+ */
+
+module_t *module_add_node(geoid_t geoid, cnodeid_t cnodeid)
+{
+    module_t	       *m;
+    int			i;
+    char		buffer[16];
+    moduleid_t		moduleid;
+
+    memset(buffer, 0, 16);
+    moduleid = geo_module(geoid);
+    format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF);
+    DPRINTF("module_add_node: moduleid=%s node=%d\n", buffer, cnodeid);
+
+    if ((m = module_lookup(moduleid)) == 0) {
+	m = kmalloc(sizeof (module_t), GFP_KERNEL);
+	memset(m, 0 , sizeof(module_t));
+	ASSERT_ALWAYS(m);
+
+	m->id = moduleid;
+	spin_lock_init(&m->lock);
+
+	mutex_init_locked(&m->thdcnt);
+
+	/* Insert in sorted order by module number */
+
+	for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--)
+	    modules[i] = modules[i - 1];
+
+	modules[i] = m;
+	nummodules++;
+    }
+
+    m->nodes[m->nodecnt] = cnodeid;
+    m->geoid[m->nodecnt] = geoid;
+    m->nodecnt++;
+
+    DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
+
+    return m;
+}
+
+int module_probe_snum(module_t *m, nasid_t nasid)
+{
+    lboard_t	       *board;
+    klmod_serial_num_t *comp;
+    char * bcopy(const char * src, char * dest, int count);
+    char serial_number[16];
+
+    /*
+     * record brick serial number
+     */
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+    {
+#if	LDEBUG
+	printf ("module_probe_snum: no IP35 board found!\n");
+#endif
+	return 0;
+    }
+
+    board_serial_number_get( board, serial_number );
+    if( serial_number[0] != '\0' ) {
+	encode_str_serial( serial_number, m->snum.snum_str );
+	m->snum_valid = 1;
+    }
+#if	LDEBUG
+    else {
+	printf("module_probe_snum: brick serial number is null!\n");
+    }
+    printf("module_probe_snum: brick serial number == %s\n", serial_number);
+#endif /* DEBUG */
+
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
+			KLTYPE_IOBRICK_XBOW);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+	return 0;
+
+    comp = GET_SNUM_COMP(board);
+
+    if (comp) {
+#if LDEBUG
+	    int i;
+
+	    printf("********found module with id %x and string", m->id);
+
+	    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
+		printf(" %x ", comp->snum.snum_str[i]);
+
+	    printf("\n");	/* Fudged string is not ASCII */
+#endif
+
+	    if (comp->snum.snum_str[0] != '\0') {
+		bcopy(comp->snum.snum_str,
+		      m->sys_snum,
+		      MAX_SERIAL_NUM_SIZE);
+		m->sys_snum_valid = 1;
+	    }
+    }
+
+    if (m->sys_snum_valid)
+	return 1;
+    else {
+	DPRINTF("Invalid serial number for module %d, "
+		"possible missing or invalid NIC.", m->id);
+	return 0;
+    }
+}
+
+void
+io_module_init(void)
+{
+    cnodeid_t		node;
+    lboard_t	       *board;
+    nasid_t		nasid;
+    int			nserial;
+    module_t	       *m;
+
+    DPRINTF("*******module_init\n");
+
+    nserial = 0;
+
+    for (node = 0; node < numnodes; node++) {
+	nasid = COMPACT_TO_NASID_NODEID(node);
+
+	board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	ASSERT(board);
+
+	m = module_add_node(board->brd_geoid, node);
+
+	if (! m->snum_valid && module_probe_snum(m, nasid))
+	    nserial++;
+    }
+
+    DPRINTF("********found total of %d serial numbers in the system\n",
+	    nserial);
+
+    if (nserial == 0)
+	printk(KERN_WARNING  "io_module_init: No serial number found.\n");
+}
+
+int
+get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info)
+{
+    if (cmod < 0 || cmod >= nummodules)
+	return -EINVAL;
+
+    mod_info->mod_num = modules[cmod]->id;
+
+    ia64_sn_sys_serial_get(mod_info->serial_str);
+    
+    mod_info->serial_num = ia64_sn_partition_serial_get();
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pci_bus_cvlink.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pci_bus_cvlink.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pci_bus_cvlink.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pci_bus_cvlink.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,811 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <asm/sn/types.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/iograph.h>
+#include <asm/param.h>
+#include <asm/sn/pio.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_cpuid.h>
+
+extern int bridge_rev_b_data_check_disable;
+
+devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];
+nasid_t busnum_to_nid[MAX_PCI_XWIDGET];
+void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];
+unsigned char num_bridges;
+static int done_probing = 0;
+
+static int pci_bus_map_create(devfs_handle_t xtalk);
+devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);
+
+extern unsigned char Is_pic_on_this_nasid[512];
+
+extern void sn_init_irq_desc(void);
+
+
+/*
+ * For the given device, initialize whether it is a PIC device.
+ */
+static void
+set_isPIC(struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+
+	device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);;
+}
+
+/*
+ * pci_bus_cvlink_init() - To be called once during initialization before 
+ *	SGI IO Infrastructure init is called.
+ */
+void
+pci_bus_cvlink_init(void)
+{
+
+	extern void ioconfig_bus_init(void);
+
+	memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
+	memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET);
+
+	memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET);
+
+	num_bridges = 0;
+
+	// ioconfig_bus_init();
+}
+
+/*
+ * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated 
+ *	pci bus vertex from the SGI IO Infrastructure.
+ */
+devfs_handle_t
+pci_bus_to_vertex(unsigned char busnum)
+{
+
+	devfs_handle_t	pci_bus = NULL;
+
+
+	/*
+	 * First get the xwidget vertex.
+	 */
+	pci_bus = busnum_to_pcibr_vhdl[busnum];
+	return(pci_bus);
+}
+
+/*
+ * devfn_to_vertex() - returns the vertex of the device given the bus, slot, 
+ *	and function numbers.
+ */
+devfs_handle_t
+devfn_to_vertex(unsigned char busnum, unsigned int devfn)
+{
+
+	int slot = 0;
+	int func = 0;
+	char	name[16];
+	devfs_handle_t  pci_bus = NULL;
+	devfs_handle_t	device_vertex = (devfs_handle_t)NULL;
+
+	/*
+	 * Go get the pci bus vertex.
+	 */
+	pci_bus = pci_bus_to_vertex(busnum);
+	if (!pci_bus) {
+		/*
+		 * During probing, the Linux pci code invents non existant
+		 * bus numbers and pci_dev structures and tries to access
+		 * them to determine existance. Don't crib during probing.
+		 */
+		if (done_probing)
+			printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum);
+		return(NULL);
+	}
+
+
+	/*
+	 * Go get the slot&function vertex.
+	 * Should call pciio_slot_func_to_name() when ready.
+	 */
+	slot = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+
+	/*
+	 * For a NON Multi-function card the name of the device looks like:
+	 * ../pci/1, ../pci/2 ..
+	 */
+	if (func == 0) {
+        	sprintf(name, "%d", slot);
+		if (hwgraph_traverse(pci_bus, name, &device_vertex) == 
+			GRAPH_SUCCESS) {
+			if (device_vertex) {
+				return(device_vertex);
+			}
+		}
+	}
+			
+	/*
+	 * This maybe a multifunction card.  It's names look like:
+	 * ../pci/1a, ../pci/1b, etc.
+	 */
+	sprintf(name, "%d%c", slot, 'a'+func);
+	if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) {
+		if (!device_vertex) {
+			return(NULL);
+		}
+	}
+
+	return(device_vertex);
+}
+
+/*
+ * For the given device, initialize the addresses for both the Device(x) Flush 
+ * Write Buffer register and the Xbow Flush Register for the port the PCI bus 
+ * is connected.
+ */
+static void
+set_flush_addresses(struct pci_dev *device_dev, 
+	struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+    	bridge_t               *bridge = pcibr_soft->bs_base;
+	nasid_t			nasid;
+
+	/*
+	 * Get the nasid from the bridge.
+	 */
+	nasid = NASID_GET(device_sysdata->dma_buf_sync);
+	if (IS_PIC_DEVICE(device_dev)) {
+		device_sysdata->dma_buf_sync = (volatile unsigned int *)
+			&bridge->b_wr_req_buf[pciio_slot].reg;
+		device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+			XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(nasid, 0),
+			pcibr_soft->bs_xid);
+	} else {
+		/*
+		 * Accessing Xbridge and Xbow register when SHUB swapoper is on!.
+		 */
+		device_sysdata->dma_buf_sync = (volatile unsigned int *)
+			((uint64_t)&(bridge->b_wr_req_buf[pciio_slot].reg)^4);
+		device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+			((uint64_t)(XBOW_PRIO_LINKREGS_PTR(
+			NODE_SWIN_BASE(nasid, 0), pcibr_soft->bs_xid)) ^ 4);
+	}
+
+#ifdef DEBUG
+	printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", 
+		device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync);
+
+printk("set_flush_addresses: dma_buf_sync\n");
+	while((volatile unsigned int )*device_sysdata->dma_buf_sync);
+printk("set_flush_addresses: xbow_buf_sync\n");
+	while((volatile unsigned int )*device_sysdata->xbow_buf_sync);
+#endif
+
+}
+
+/*
+ * Most drivers currently do not properly tell the arch specific pci dma
+ * interfaces whether they can handle A64. Here is where we privately
+ * keep track of this.
+ */
+static void __init
+set_sn_pci64(struct pci_dev *dev)
+{
+	unsigned short vendor = dev->vendor;
+	unsigned short device = dev->device;
+
+	if (vendor == PCI_VENDOR_ID_QLOGIC) {
+		if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) ||
+				(device == PCI_DEVICE_ID_QLOGIC_ISP2200)) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+	if (vendor == PCI_VENDOR_ID_SGI) {
+		if (device == PCI_DEVICE_ID_SGI_IOC3) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+}
+
+/*
+ * sn_pci_fixup() - This routine is called when platform_pci_fixup() is 
+ *	invoked at the end of pcibios_init() to link the Linux pci 
+ *	infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c
+ *
+ *	Other platform specific fixup can also be done here.
+ */
+void
+sn_pci_fixup(int arg)
+{
+	struct list_head *ln;
+	struct pci_bus *pci_bus = NULL;
+	struct pci_dev *device_dev = NULL;
+	struct sn_widget_sysdata *widget_sysdata;
+	struct sn_device_sysdata *device_sysdata;
+	pciio_intr_t intr_handle;
+	int cpuid, bit;
+	devfs_handle_t device_vertex;
+	pciio_intr_line_t lines;
+	extern void sn_pci_find_bios(void);
+	extern int numnodes;
+	int cnode;
+	extern void io_sh_swapper(int, int);
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+			io_sh_swapper((cnodeid_to_nasid(cnode)), 0);
+	}
+
+	if (arg == 0) {
+#ifdef CONFIG_PROC_FS
+		extern void register_sn_partition_id(void);
+		extern void register_sn_serial_numbers(void);
+#endif
+
+		sn_init_irq_desc();
+		sn_pci_find_bios();
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int);
+			intr_init_vecblk(NODEPDA(cnode), cnode, 0);
+		} 
+
+		/*
+		 * When we return to generic Linux, Swapper is always on ..
+		 */
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+				io_sh_swapper((cnodeid_to_nasid(cnode)), 1);
+		}
+#ifdef CONFIG_PROC_FS
+		register_sn_partition_id();
+		register_sn_serial_numbers();
+#endif
+		return;
+	}
+
+
+	done_probing = 1;
+
+	/*
+	 * Initialize the pci bus vertex in the pci_bus struct.
+	 */
+	for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+		pci_bus = pci_bus_b(ln);
+		widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), 
+					GFP_KERNEL);
+		widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number);
+		pci_bus->sysdata = (void *)widget_sysdata;
+	}
+
+	/*
+ 	 * set the root start and end so that drivers calling check_region()
+	 * won't see a conflict
+	 */
+	ioport_resource.start  = 0xc000000000000000;
+	ioport_resource.end =    0xcfffffffffffffff;
+
+	/*
+	 * Set the root start and end for Mem Resource.
+	 */
+	iomem_resource.start = 0;
+	iomem_resource.end = 0xffffffffffffffff;
+
+	/*
+	 * Initialize the device vertex in the pci_dev struct.
+	 */
+	pci_for_each_dev(device_dev) {
+		unsigned int irq;
+		int idx;
+		u16 cmd;
+		devfs_handle_t vhdl;
+		unsigned long size;
+		extern int bit_pos_to_irq(int);
+
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+				device_dev->device == PCI_DEVICE_ID_SGI_IOC3) {
+			extern void pci_fixup_ioc3(struct pci_dev *d);
+			pci_fixup_ioc3(device_dev);
+		}
+
+		/* Set the device vertex */
+
+		device_sysdata = kmalloc(sizeof(struct sn_device_sysdata),
+					GFP_KERNEL);
+		device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn);
+		device_sysdata->isa64 = 0;
+		/*
+		 * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush 
+		 * register addresses.
+		 */
+		(void) set_flush_addresses(device_dev, device_sysdata);
+
+		device_dev->sysdata = (void *) device_sysdata;
+		set_sn_pci64(device_dev);
+		set_isPIC(device_sysdata);
+
+		pci_read_config_word(device_dev, PCI_COMMAND, &cmd);
+
+		/*
+		 * Set the resources address correctly.  The assumption here 
+		 * is that the addresses in the resource structure has been
+		 * read from the card and it was set in the card by our
+		 * Infrastructure ..
+		 */
+		vhdl = device_sysdata->vhdl;
+		for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
+			size = 0;
+			size = device_dev->resource[idx].end -
+				device_dev->resource[idx].start;
+			if (size) {
+				device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+				device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET;
+			}
+			else
+				continue;
+
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].start + size;
+#ifdef BRINGUP2
+			printk("Device Vendor 0x%x, resource[%d] PIO Address = 0x%lx\n", device_dev->vendor, idx, (long)device_dev->resource[idx].start);
+#endif
+
+			if (device_dev->resource[idx].flags & IORESOURCE_IO)
+				cmd |= PCI_COMMAND_IO;
+
+			if (device_dev->resource[idx].flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+		/*
+		 * Now handle the ROM resource ..
+		 */
+#if 0
+	/*
+	 * Software WAR for a Software BUG.
+	 * This is only temporary.
+	 * See PV 872791
+	 */
+		size = device_dev->resource[PCI_ROM_RESOURCE].end -
+			device_dev->resource[PCI_ROM_RESOURCE].start;
+
+		if (size) {
+			device_dev->resource[PCI_ROM_RESOURCE].start =
+			(unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, 
+				size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+			device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET;
+			device_dev->resource[PCI_ROM_RESOURCE].end =
+			device_dev->resource[PCI_ROM_RESOURCE].start + size;
+		}
+#endif
+
+		/*
+		 * Update the Command Word on the Card.
+		 */
+		cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */
+					   /* bit gets dropped .. no harm */
+		pci_write_config_word(device_dev, PCI_COMMAND, cmd);
+
+		pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines);
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+			device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+				lines = 1;
+		}
+ 
+		device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata;
+		device_vertex = device_sysdata->vhdl;
+ 
+		intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex);
+
+		bit = intr_handle->pi_irq;
+		cpuid = intr_handle->pi_cpu;
+		irq = bit;
+		irq = irq + (cpuid << 8);
+		pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0);
+		device_dev->irq = irq;
+#ifdef ajmtestintr
+		{
+			int slot = PCI_SLOT(device_dev->devfn);
+			static int timer_set = 0;
+			pcibr_intr_t	pcibr_intr = (pcibr_intr_t)intr_handle;
+			pcibr_soft_t	pcibr_soft = pcibr_intr->bi_soft;
+			extern void intr_test_handle_intr(int, void*, struct pt_regs *);
+
+			if (!timer_set) {
+				intr_test_set_timer();
+				timer_set = 1;
+			}
+			intr_test_register_irq(irq, pcibr_soft, slot);
+			request_irq(irq, intr_test_handle_intr,0,NULL, NULL);
+		}
+#endif
+
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+			io_sh_swapper((cnodeid_to_nasid(cnode)), 1);
+	}
+}
+
+/*
+ * linux_bus_cvlink() Creates a link between the Linux PCI Bus number 
+ *	to the actual hardware component that it represents:
+ *	/dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci
+ */
+void
+linux_bus_cvlink(void)
+{
+	char name[8];
+	int index;
+	
+	for (index=0; index < MAX_PCI_XWIDGET; index++) {
+		if (!busnum_to_pcibr_vhdl[index])
+			continue;
+
+		sprintf(name, "%d", index);
+		(void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], 
+				name);
+	}
+}
+
+/*
+ * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job.
+ *
+ *	Linux PCI Bus numbers are assigned from lowest module_id numbers
+ *	(rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to 
+ *	HUB_WIDGET_ID_MIN:
+ *		widgetnum 15 gets lower Bus Number than widgetnum 14 etc.
+ *
+ *	Given 2 modules 001c01 and 001c02 we get the following mappings:
+ *		001c01, widgetnum 15 = Bus number 0
+ *		001c01, widgetnum 14 = Bus number 1
+ *		001c02, widgetnum 15 = Bus number 3
+ *		001c02, widgetnum 14 = Bus number 4
+ *		etc.
+ *
+ * The rational for starting Bus Number 0 with Widget number 15 is because 
+ * the system boot disks are always connected via Widget 15 Slot 0 of the 
+ * I-brick.  Linux creates /dev/sd* devices(naming) strating from Bus Number 0 
+ * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest 
+ * module id(Master Cnode) of the system.
+ *	
+ */
+static int 
+pci_bus_map_create(devfs_handle_t xtalk)
+{
+
+	devfs_handle_t master_node_vertex = NULL;
+	devfs_handle_t xwidget = NULL;
+	devfs_handle_t pci_bus = NULL;
+	hubinfo_t hubinfo = NULL;
+	xwidgetnum_t widgetnum;
+	char pathname[128];
+	graph_error_t rv;
+	int bus;
+
+	/*
+	 * Loop throught this vertex and get the Xwidgets ..
+	 */
+
+
+	/* PCI devices */
+
+	for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) {
+
+#if  0
+        {
+                int pos;
+                char dname[256];
+                pos = devfs_generate_path(xtalk, dname, 256);
+                printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+        }
+#endif
+
+		sprintf(pathname, "%d", widgetnum);
+		xwidget = NULL;
+		
+		/*
+		 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+		 *	     /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device
+		 */
+		rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+		if ( (rv != GRAPH_SUCCESS) ) {
+			if (!xwidget) {
+				continue;
+}
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		pci_bus = NULL;
+		if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+			if (!pci_bus) {
+				continue;
+}
+
+		/*
+		 * Assign the correct bus number and also the nasid of this 
+		 * pci Xwidget.
+		 * 
+		 * Should not be any race here ...
+		 */
+		num_bridges++;
+		busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+
+		/*
+		 * Get the master node and from there get the NASID.
+		 */
+		master_node_vertex = device_master_get(xwidget);
+		if (!master_node_vertex) {
+			printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+		}
+	
+		hubinfo_get(master_node_vertex, &hubinfo);
+		if (!hubinfo) {
+			printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+			return(1);
+		} else {
+			busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+		}
+
+		/*
+		 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+		 */
+		busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+		if (!busnum_to_atedmamaps[num_bridges - 1])
+			printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+
+		memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+
+	}
+
+	/*
+	 * PCIX devices
+	 * We number busses differently for PCI-X devices.
+	 * We start from Lowest Widget on up ..
+	 */
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+
+		/* Do both buses */
+		for ( bus = 0; bus < 2; bus++ ) {
+			sprintf(pathname, "%d", widgetnum);
+			xwidget = NULL;
+			
+			/*
+			 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+			 *	     /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus
+			 *	     /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device
+			 */
+			rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+			if ( (rv != GRAPH_SUCCESS) ) {
+				if (!xwidget) {
+					continue;
+				}
+			}
+	
+			if ( bus == 0 )
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum);
+			else
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum);
+			pci_bus = NULL;
+			if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+				if (!pci_bus) {
+					continue;
+				}
+	
+			/*
+			 * Assign the correct bus number and also the nasid of this 
+			 * pci Xwidget.
+			 * 
+			 * Should not be any race here ...
+			 */
+			num_bridges++;
+			busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+	
+			/*
+			 * Get the master node and from there get the NASID.
+			 */
+			master_node_vertex = device_master_get(xwidget);
+			if (!master_node_vertex) {
+				printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+			}
+		
+			hubinfo_get(master_node_vertex, &hubinfo);
+			if (!hubinfo) {
+				printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+				return(1);
+			} else {
+				busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+			}
+	
+			/*
+			 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+			 */
+			busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+				sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+			if (!busnum_to_atedmamaps[num_bridges - 1])
+				printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+	
+			memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+				sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+		}
+	}
+
+        return(0);
+}
+
+/*
+ * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure   
+ *      initialization has completed to set up the mappings between Xbridge
+ *      and logical pci bus numbers.  We also set up the NASID for each of these
+ *      xbridges.
+ *
+ *      Must be called before pci_init() is invoked.
+ */
+int
+pci_bus_to_hcl_cvlink(void) 
+{
+
+	devfs_handle_t devfs_hdl = NULL;
+	devfs_handle_t xtalk = NULL;
+	int rv = 0;
+	char name[256];
+	char tmp_name[256];
+	int master_iobrick;
+	slabid_t master_slab;
+	int i, ii;
+	extern nasid_t master_baseio_nasid;
+	extern nasid_t get_master_baseio_nasid(void);
+
+	/*
+	 * Iterate throught each xtalk links in the system ..
+	 * /hw/module/001c01/slab/0/node/xtalk/ 8|9|10|11|12|13|14|15 
+	 *
+	 * /hw/module/001c01/slab/0/node/xtalk/15 -> /hw/module/001c01/slab/0/Ibrick/xtalk/15
+	 *
+	 * What if it is not pci?
+	 */
+	devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module");
+
+	/*
+	 * To provide consistent(not persistent) device naming, we need to start 
+	 * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 
+	 * with an attached I-Brick.  Find the master_iobrick.
+	 */
+	master_baseio_nasid = get_master_baseio_nasid();
+	master_iobrick = -1;
+	master_slab = -1;
+	if ( master_baseio_nasid >= 0 ) {
+		/* Valid nasid, need the slab ID */
+		for (i = 0; i < nummodules; i++) {
+			extern int iobrick_module_get_nasid(nasid_t);
+			moduleid_t iobrick_id; 
+			nasid_t nasid = -1;
+			int n = 0;
+			for ( n = 0; n < modules[i]->nodecnt; n++ ) {
+				nasid = cnodeid_to_nasid(modules[i]->nodes[n]);
+				iobrick_id = iobrick_module_get_nasid(nasid);
+				if (iobrick_id > 0) { /* Valid module id */
+					if ( master_baseio_nasid == nasid ) {
+						master_iobrick = i;
+						master_slab = geo_slab(modules[i]->geoid[n]);
+						printk("pci_bus_to_hcl_cvlink: Found Master Base IO Brick type %d Master Base I/O nasid %d Master Cbrick Index %d Slab %d\n", MODULE_GET_BTYPE(iobrick_id), master_baseio_nasid, master_iobrick, master_slab);
+						break;
+					}
+				}
+			}
+			if (master_slab >= 0)
+				break;
+		}
+	}
+	else {
+		/* Not sure which nasid it is - call failed, so make a guess */
+		for (i = 0; i < nummodules; i++) {
+			extern int iobrick_module_get_nasid(nasid_t);
+			moduleid_t iobrick_id; 
+			nasid_t nasid = -1;
+			int n = 0;
+			for ( n = 0; n < modules[i]->nodecnt; n++ ) {
+				nasid = cnodeid_to_nasid(modules[i]->nodes[n]);
+				iobrick_id = iobrick_module_get_nasid(nasid);
+				if (iobrick_id > 0) { /* Valid module id */
+					if ( (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) || 
+					   		(MODULE_GET_BTYPE(iobrick_id) == MODULE_PXBRICK) ||
+				   			(MODULE_GET_BTYPE(iobrick_id) == MODULE_PBRICK) ) {
+						master_iobrick = i;
+						master_baseio_nasid = nasid;
+						master_slab = geo_slab(modules[i]->geoid[n]);
+						printk("pci_bus_to_hcl_cvlink: Found Master Base IO Brick type %d Master Cbrick Index %d Slab %d\n", MODULE_GET_BTYPE(iobrick_id), master_iobrick, master_slab);
+						break;
+					}
+				}
+			}
+			if (master_iobrick >= 0)
+				break;
+		}
+	}
+
+	if (master_iobrick == -1) {
+		panic("Unable to find the Master BaseIO PCI/PCIX Bus\n");
+	}
+
+	/*
+	 * The master_iobrick gets bus 0 and 1.
+	 */
+	if (master_iobrick >= 0) {
+		memset(name, 0, 256);
+		memset(tmp_name, 0, 256);
+		format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF);
+		sprintf(tmp_name, "/slab/%d/node/xtalk", master_slab);
+		strcat(name, tmp_name);
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+		
+	/*
+	 * Now go do the rest of the modules, starting from the C-Brick with the lowest 
+	 * module id, remembering to skip the master_iobrick, which was done above.
+	 */
+	for (i = 0; i < nummodules ; i++) {
+		for ( ii = 0; ii < MAX_SLABS; ii++ ) {
+			if ((i == master_iobrick) && (master_slab == ii))
+				continue; /* Did the master_iobrick/slab already. */
+			memset(name, 0, 256);
+			memset(tmp_name, 0, 256);
+			format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF);
+			sprintf(tmp_name, "/slab/%d/node/xtalk", ii);
+			strcat(name, tmp_name);
+			xtalk = NULL;
+			rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+			pci_bus_map_create(xtalk);
+		}
+	}
+
+	/*
+	 * Create the Linux PCI bus number vertex link.
+	 */
+	(void)linux_bus_cvlink();
+
+	return(0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/Makefile linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,23 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn2 io pcibr routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+ifdef CONFIG_IA64_SGI_SN2
+EXTRA_CFLAGS    += -DSHUB_SWAP_WAR
+endif
+
+O_TARGET := pcibr.o
+
+obj-$(CONFIG_IA64_SGI_SN2)	+= pcibr_dvr.o pcibr_ate.o pcibr_config.o \
+                                   pcibr_dvr.o pcibr_hints.o \
+				   pcibr_intr.o pcibr_rrb.o pcibr_slot.o \
+				   pcibr_error.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2003-05-22 22:06:39.000000000 +0000
@@ -44,24 +44,6 @@
 #endif
 
 
-#ifdef LATER
-#if (PCIBR_FREEZE_TIME) || PCIBR_ATE_DEBUG
-LOCAL struct reg_desc   ate_bits[] =
-{
-    {0xFFFF000000000000ull, -48, "RMF", "%x"},
-    {~(IOPGSIZE - 1) &			/* may trim off some low bits */
-     0x0000FFFFFFFFF000ull, 0, "XIO", "%x"},
-    {0x0000000000000F00ull, -8, "port", "%x"},
-    {0x0000000000000010ull, 0, "Barrier"},
-    {0x0000000000000008ull, 0, "Prefetch"},
-    {0x0000000000000004ull, 0, "Precise"},
-    {0x0000000000000002ull, 0, "Coherent"},
-    {0x0000000000000001ull, 0, "Valid"},
-    {0}
-};
-#endif
-#endif	/* LATER */
-
 #ifndef LOCAL
 #define LOCAL           static
 #endif
@@ -79,7 +61,7 @@
 	   			unsigned *freeze_time_ptr,
 #endif
 	   			unsigned *cmd_regs);
-void 	  ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
+void 	  ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
 void ate_thaw(pcibr_dmamap_t pcibr_dmamap,
 	 			int ate_index,
 #if PCIBR_FREEZE_TIME
@@ -119,26 +101,73 @@
     int                     i, j;
     bridgereg_t             old_enable, new_enable;
     int                     s;
+    int			    this_is_pic = is_pic(bridge);
 
     /* Probe SSRAM to determine its size. */
-    old_enable = bridge->b_int_enable;
-    new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
-    bridge->b_int_enable = new_enable;
+    if ( this_is_pic ) {
+	old_enable = bridge->b_int_enable;
+	new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+	bridge->b_int_enable = new_enable;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable));
+		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+		BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable;
+	}
+	else {
+		old_enable = bridge->b_int_enable;
+		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+		bridge->b_int_enable = new_enable;
+	}
+    }
 
     for (i = 1; i < ATE_NUM_SIZES; i++) {
 	/* Try writing a value */
-	bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	if ( this_is_pic ) {
+		bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge)))
+			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE);
+		else
+			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	}
 
 	/* Guard against wrap */
 	for (j = 1; j < i; j++)
 	    bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0;
 
 	/* See if value was written */
-	if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
-	    largest_working_size = i;
+	if ( this_is_pic ) {
+		if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
+				largest_working_size = i;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE))
+					largest_working_size = i;
+			else {
+				if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
+					largest_working_size = i;
+			}
+		}
+	}
+    }
+    if ( this_is_pic ) {
+	bridge->b_int_enable = old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable;
+		BRIDGE_REG_GET32((&bridge->b_wid_tflush));   /* wait until Bridge PIO complete */
+	}
+	else {
+		bridge->b_int_enable = old_enable;
+		bridge->b_wid_tflush;               /* wait until Bridge PIO complete */
+	}
     }
-    bridge->b_int_enable = old_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 
     /*
      * ensure that we write and read without any interruption.
@@ -146,20 +175,41 @@
      */
 
     s = splhi();
-    bridge->b_wid_control = (bridge->b_wid_control
-	& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
-	| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
-    bridge->b_wid_control;		/* inval addr bug war */
+    if ( this_is_pic ) {
+	bridge->b_wid_control = (bridge->b_wid_control
+			& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+			| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
+	bridge->b_wid_control;		/* inval addr bug war */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&(bridge->b_wid_control))) = 
+				__swab32((BRIDGE_REG_GET32((&bridge->b_wid_control))
+					& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+					| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size));
+		BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */
+	}
+	else {
+		bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+				| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
+		bridge->b_wid_control;              /* inval addr bug war */
+	}
+    }
     splx(s);
 
     num_entries = ATE_NUM_ENTRIES(largest_working_size);
 
-#if PCIBR_ATE_DEBUG
-    if (num_entries)
-	printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries);
-    else
-	printk("bridge at 0x%x: no external ATE RAM found\n", bridge);
-#endif
+    if (pcibr_debug_mask & PCIBR_DEBUG_ATE) {
+	if (num_entries) {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
+			"bridge at 0x%x: clearing %d external ATEs\n",
+			bridge, num_entries));
+	} else {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
+			"bridge at 0x%x: no external ATE RAM found\n",
+			bridge));
+	}
+    }
 
     /* Initialize external mapping entries */
     for (entry = 0; entry < num_entries; entry++)
@@ -339,7 +389,8 @@
 #endif
 
     cmd_lwa = 0;
-    for (slot = 0; slot < 8; ++slot)
+    for (slot = pcibr_soft->bs_min_slot; 
+		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
 	if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 	    cmd_reg = pcibr_soft->
 		bs_slot[slot].
@@ -366,28 +417,54 @@
 	    cmd_lwa[0];
 
 	    /* Flush all the write buffers in the bridge */
-	    for (slot = 0; slot < 8; ++slot)
+	    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 		    if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 			    /* Flush the write buffer associated with this
 			     * PCI device which might be using dma map RAM.
 			     */
-			    bridge->b_wr_req_buf[slot].reg;
+			if ( is_pic(bridge) ) {
+				bridge->b_wr_req_buf[slot].reg;
+			}
+			else {
+				if (io_get_sh_swapper(NASID_GET(bridge)) ) {
+					BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg));
+				}
+				else
+					bridge->b_wr_req_buf[slot].reg;
+			}
 		    }
+	    }
     }
     return s;
 }
 
-#define	ATE_WRITE()    ate_write(ate_ptr, ate_count, ate)
-
 void
-ate_write(bridge_ate_p ate_ptr,
+ate_write(pcibr_soft_t pcibr_soft,
+	  bridge_ate_p ate_ptr,
 	  int ate_count,
 	  bridge_ate_t ate)
 {
-    while (ate_count-- > 0) {
-	*ate_ptr++ = ate;
-	ate += IOPGSIZE;
-    }
+	if (IS_PIC_SOFT(pcibr_soft) ) {
+    		while (ate_count-- > 0) {
+			*ate_ptr++ = ate;
+			ate += IOPGSIZE;
+		}
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(ate_ptr))) {
+    			while (ate_count-- > 0) {
+				*ate_ptr++ = __swab64(ate);
+				ate += IOPGSIZE;
+			}
+		}
+		else {
+    			while (ate_count-- > 0) {
+				*ate_ptr++ = ate;
+				ate += IOPGSIZE;
+			}
+		}
+	}
 }
 
 #if PCIBR_FREEZE_TIME
@@ -425,10 +502,24 @@
 	return;
 
     /* restore cmd regs */
-    for (slot = 0; slot < 8; ++slot)
-	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER)
-	    bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;
-
+    for (slot = pcibr_soft->bs_min_slot; 
+		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) {
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = __swab32(cmd_reg);
+			}
+			else {
+//				BUG(); /* Does this really work if called when io_get_sh_swapper = 0? */
+//				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;
+				pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);
+			}
+		}
+	}
+    }
     pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY;
     atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
 
@@ -442,7 +533,7 @@
 	if (max_ate_total < ate_total)
 	    max_ate_total = ate_total;
 	pcibr_unlock(pcibr_soft, s);
-	printk("%s: pci freeze time %d usec for %d ATEs\n"
+	printk( "%s: pci freeze time %d usec for %d ATEs\n"
 		"\tfirst ate: %R\n",
 		pcibr_soft->bs_name,
 		freeze_time * 1000 / 1250,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2003-05-22 22:06:24.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/byteorder/swab.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
@@ -34,14 +35,14 @@
 extern pcibr_info_t      pcibr_info_get(devfs_handle_t);
 
 uint64_t          pcibr_config_get(devfs_handle_t, unsigned, unsigned);
-uint64_t          do_pcibr_config_get(cfg_p, unsigned, unsigned);
+uint64_t          do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
 void              pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);
-void              do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
+void       	  do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t);
+static void	  swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
 
 #ifdef LITTLE_ENDIAN
-#ifdef CONFIG_IA64_SGI_SN1
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
@@ -49,73 +50,218 @@
 #define CB(b,r) (((volatile uint8_t *) b)[((r)^4)])
 #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)])
 #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)])
-#else
-#ifdef CONFIG_IA64_SGI_SN2
-/*
- * On sn-ia sn2 everything is little endian.  No swizzling 
- * or byte swapping of addresses required.
- */
-#define CB(b,r) (((volatile uint8_t *) b)[(r)])
-#define CS(b,r) (((volatile uint16_t *) b)[(r)/2])
-#define CW(b,r) (((volatile uint32_t *) b)[(r)/4])
-#endif
-#endif
+
+#define	CBP(b,r) (((volatile uint8_t *) b)[(r)^3])
+#define	CSP(b,r) (((volatile uint16_t *) b)[((r)/2)^1])
+#define	CWP(b,r) (((volatile uint32_t *) b)[(r)/4])
+
+#define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)])
+#define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)])
+#define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)])
 #else
 #define	CB(b,r)	(((volatile uint8_t *) cfgbase)[(r)^3])
 #define	CS(b,r)	(((volatile uint16_t *) cfgbase)[((r)/2)^1])
 #define	CW(b,r)	(((volatile uint32_t *) cfgbase)[(r)/4])
 #endif
 
+/*
+ * Return a config space address for given slot / func / offset.  Note the
+ * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to
+ * the 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot, 
+					pciio_function_t func, int offset)
+{
+	/*
+	 * Type 1 config space
+	 */
+	if (bus > 0) {
+		bridge->b_pci_cfg = ((bus << 16) | (slot << 11));
+		return &bridge->b_type1_cfg.f[func].l[(offset)];
+	}
+
+	/*
+	 * Type 0 config space
+	 */
+	if (is_pic(bridge))
+		slot++;
+	return &bridge->b_type0_cfg_dev[slot].f[func].l[offset];
+}
+
+/*
+ * Return config space address for given slot / offset.  Note the returned
+ * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the
+ * 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+	return pcibr_func_config_addr(bridge, 0, slot, 0, offset);
+}
+
+/*
+ * Return config space data for given slot / offset
+ */
+unsigned
+pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+	cfg_p  cfg_base;
+	
+	cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+	return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Return config space data for given slot / func / offset
+ */
+unsigned
+pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot, 
+					pciio_function_t func, int offset)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Set config space data for given slot / offset
+ */
+void
+pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot, 
+					int offset, unsigned val)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+	do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+/*
+ * Set config space data for given slot / func / offset
+ */
+void
+pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot, 
+			pciio_function_t func, int offset, unsigned val)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+int pcibr_config_debug = 0;
 
 cfg_p
 pcibr_config_addr(devfs_handle_t conn,
 		  unsigned reg)
 {
     pcibr_info_t            pcibr_info;
+    pciio_bus_t		    pciio_bus;
     pciio_slot_t            pciio_slot;
     pciio_function_t        pciio_func;
     pcibr_soft_t            pcibr_soft;
     bridge_t               *bridge;
     cfg_p                   cfgbase = (cfg_p)0;
+    pciio_info_t	    pciio_info;
 
+    pciio_info = pciio_info_get(conn);
     pcibr_info = pcibr_info_get(conn);
 
-    pciio_slot = pcibr_info->f_slot;
+    /*
+     * Determine the PCI bus/slot/func to generate a config address for.
+     */
+
+    if (pciio_info_type1_get(pciio_info)) {
+	/*
+	 * Conn is a vhdl which uses TYPE 1 addressing explicitly passed 
+	 * in reg.
+	 */
+	pciio_bus = PCI_TYPE1_BUS(reg);
+	pciio_slot = PCI_TYPE1_SLOT(reg);
+	pciio_func = PCI_TYPE1_FUNC(reg);
+
+	ASSERT(pciio_bus != 0);
+#if 0
+    } else if (conn != pciio_info_hostdev_get(pciio_info)) {
+	/*
+	 * Conn is on a subordinate bus, so get bus/slot/func directly from
+	 * its pciio_info_t structure.
+	 */
+	pciio_bus = pciio_info->c_bus;
+	pciio_slot = pciio_info->c_slot;
+	pciio_func = pciio_info->c_func;
+	if (pciio_func == PCIIO_FUNC_NONE) {
+		pciio_func = 0;
+	}
+#endif
+    } else {
+	/*
+	 * Conn is directly connected to the host bus.  PCI bus number is
+	 * hardcoded to 0 (even though it may have a logical bus number != 0)
+	 * and slot/function are derived from the pcibr_info_t associated
+	 * with the device.
+	 */
+	pciio_bus = 0;
+
+    pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
     if (pciio_slot == PCIIO_SLOT_NONE)
 	pciio_slot = PCI_TYPE1_SLOT(reg);
 
     pciio_func = pcibr_info->f_func;
     if (pciio_func == PCIIO_FUNC_NONE)
 	pciio_func = PCI_TYPE1_FUNC(reg);
+    }
 
     pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
 
     bridge = pcibr_soft->bs_base;
 
-    cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l;
+    cfgbase = pcibr_func_config_addr(bridge,
+			pciio_bus, pciio_slot, pciio_func, 0);
 
     return cfgbase;
 }
 
+extern unsigned char Is_pic_on_this_nasid[];
 uint64_t
 pcibr_config_get(devfs_handle_t conn,
 		 unsigned reg,
 		 unsigned size)
 {
-    return do_pcibr_config_get(pcibr_config_addr(conn, reg),
-			       PCI_TYPE1_REG(reg), size);
+    if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+    	return do_pcibr_config_get(0, pcibr_config_addr(conn, reg),
+				PCI_TYPE1_REG(reg), size);
+    else
+    	return do_pcibr_config_get(1, pcibr_config_addr(conn, reg),
+				PCI_TYPE1_REG(reg), size);
 }
 
 uint64_t
 do_pcibr_config_get(
+		       int pic,
 		       cfg_p cfgbase,
 		       unsigned reg,
 		       unsigned size)
 {
     unsigned                value;
 
-    value = CW(cfgbase, reg);
-
+    if ( pic ) {
+	value = CWP(cfgbase, reg);
+    }
+    else {
+	if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) {
+	    /*
+	     * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped!
+	     * Do not swizzle address and byte swap the result.
+	     */
+	    value = SCW(cfgbase, reg);
+	    value = __swab32(value);
+	} else {
+    	    value = CW(cfgbase, reg);
+	}
+    }
     if (reg & 3)
 	value >>= 8 * (reg & 3);
     if (size < 4)
@@ -129,39 +275,103 @@
 		 unsigned size,
 		 uint64_t value)
 {
-    do_pcibr_config_set(pcibr_config_addr(conn, reg),
+    if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+    	do_pcibr_config_set(1, pcibr_config_addr(conn, reg),
+			PCI_TYPE1_REG(reg), size, value);
+    else
+	swap_do_pcibr_config_set(pcibr_config_addr(conn, reg),
 			PCI_TYPE1_REG(reg), size, value);
 }
 
 void
-do_pcibr_config_set(cfg_p cfgbase,
+do_pcibr_config_set(int pic,
+		    cfg_p cfgbase,
 		    unsigned reg,
 		    unsigned size,
 		    uint64_t value)
 {
+	if ( pic ) {
+		switch (size) {
+		case 1:
+			CBP(cfgbase, reg) = value;
+			break;
+		case 2:
+			if (reg & 1) {
+				CBP(cfgbase, reg) = value;
+				CBP(cfgbase, reg + 1) = value >> 8;
+			} else
+				CSP(cfgbase, reg) = value;
+			break;
+		case 3:
+			if (reg & 1) {
+				CBP(cfgbase, reg) = value;
+				CSP(cfgbase, (reg + 1)) = value >> 8;
+			} else {
+				CSP(cfgbase, reg) = value;
+				CBP(cfgbase, reg + 2) = value >> 16;
+			}
+			break;
+		case 4:
+			CWP(cfgbase, reg) = value;
+			break;
+   		}
+	}
+	else {
+		switch (size) {
+		case 1:
+			CB(cfgbase, reg) = value;
+			break;
+		case 2:
+			if (reg & 1) {
+				CB(cfgbase, reg) = value;
+				CB(cfgbase, reg + 1) = value >> 8;
+			} else
+				CS(cfgbase, reg) = value;
+			break;
+		case 3:
+			if (reg & 1) {
+				CB(cfgbase, reg) = value;
+				CS(cfgbase, (reg + 1)) = value >> 8;
+			} else {
+				CS(cfgbase, reg) = value;
+				CB(cfgbase, reg + 2) = value >> 16;
+			}
+			break;
+		case 4:
+			CW(cfgbase, reg) = value;
+			break;
+   		}
+	}
+}
+
+void
+swap_do_pcibr_config_set(cfg_p cfgbase,
+                    unsigned reg,
+                    unsigned size,
+                    uint64_t value)
+{
+
+    uint64_t temp_value = 0;
+
     switch (size) {
     case 1:
-	CB(cfgbase, reg) = value;
-	break;
+        SCB(cfgbase, reg) = value;
+        break;
     case 2:
-	if (reg & 1) {
-	    CB(cfgbase, reg) = value;
-	    CB(cfgbase, reg + 1) = value >> 8;
-	} else
-	    CS(cfgbase, reg) = value;
-	break;
+	temp_value = __swab16(value);
+        if (reg & 1) {
+            SCB(cfgbase, reg) = temp_value;
+            SCB(cfgbase, reg + 1) = temp_value >> 8;
+        } else
+            SCS(cfgbase, reg) = temp_value;
+        break;
     case 3:
-	if (reg & 1) {
-	    CB(cfgbase, reg) = value;
-	    CS(cfgbase, (reg + 1)) = value >> 8;
-	} else {
-	    CS(cfgbase, reg) = value;
-	    CB(cfgbase, reg + 2) = value >> 16;
-	}
-	break;
+	BUG();
+        break;
 
     case 4:
-	CW(cfgbase, reg) = value;
-	break;
+	temp_value = __swab32(value);
+        SCW(cfgbase, reg) = temp_value;
+        break;
     }
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2003-05-22 22:06:41.000000000 +0000
@@ -7,7 +7,6 @@
  * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -40,6 +39,25 @@
 #endif
 
 /*
+ * global variables to toggle the different levels of pcibr debugging.  
+ *   -pcibr_debug_mask is the mask of the different types of debugging
+ *    you want to enable.  See sys/PCI/pcibr_private.h 
+ *   -pcibr_debug_module is the module you want to trace.  By default
+ *    all modules are trace.  For IP35 this value has the format of
+ *    something like "001c10".  For IP27 this value is a node number,
+ *    i.e. "1", "2"...  For IP30 this is undefined and should be set to
+ *    'all'.
+ *   -pcibr_debug_widget is the widget you want to trace.  For IP27
+ *    the widget isn't exposed in the hwpath so use the xio slot num.
+ *    i.e. for 'io2' set pcibr_debug_widget to "2".
+ *   -pcibr_debug_slot is the pci slot you want to trace.
+ */
+uint32_t pcibr_debug_mask = 0x0;	/* 0x00000000 to disable */
+char      *pcibr_debug_module = "all";		/* 'all' for all modules */
+int	   pcibr_debug_widget = -1;		/* '-1' for all widgets  */
+int	   pcibr_debug_slot = -1;		/* '-1' for all slots    */
+
+/*
  * Macros related to the Lucent USS 302/312 usb timeout workaround.  It
  * appears that if the lucent part can get into a retry loop if it sees a
  * DAC on the bus during a pio read retry.  The loop is broken after about
@@ -82,44 +100,6 @@
 	writev: NULL
 };
 
-#ifdef LATER
-
-#if PCIBR_ATE_DEBUG
-static struct reg_values ssram_sizes[] =
-{
-    {BRIDGE_CTRL_SSRAM_512K, "512k"},
-    {BRIDGE_CTRL_SSRAM_128K, "128k"},
-    {BRIDGE_CTRL_SSRAM_64K, "64k"},
-    {BRIDGE_CTRL_SSRAM_1K, "1k"},
-    {0}
-};
-
-static struct reg_desc   control_bits[] =
-{
-    {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"},
-    {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"},
-    {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"},
-    {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"},
-    {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"},
-    {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"},
-    {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"},
-    {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"},
-    {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"},
-    {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"},
-    {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes},
-    {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"},
-    {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"},
-    {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"},
-    {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"},
-    {BRIDGE_CTRL_SYS_END, 0, "SYS_END"},
-
-    {BRIDGE_CTRL_BUS_SPEED_MASK, -4, "BUS_SPEED", "%d"},
-    {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"},
-    {0}
-};
-#endif
-#endif	/* LATER */
-
 /* kbrick widgetnum-to-bus layout */
 int p_busnum[MAX_PORT_NUM] = {                  /* widget#      */
         0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7    */
@@ -132,18 +112,6 @@
         3,                                      /* 0xf          */
 };
 
-/*
- * Additional PIO spaces per slot are
- * recorded in this structure.
- */
-struct pciio_piospace_s {
-    pciio_piospace_t        next;       /* another space for this device */
-    char                    free;       /* 1 if free, 0 if in use               */
-    pciio_space_t           space;      /* Which space is in use                */
-    iopaddr_t               start;      /* Starting address of the PIO space    */
-    size_t                  count;      /* size of PIO space                    */
-};
-
 #if PCIBR_SOFT_LIST
 pcibr_list_p            pcibr_list = 0;
 #endif
@@ -152,15 +120,15 @@
 extern int              hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags);
 extern long             atoi(register char *p);
 extern cnodeid_t        nodevertex_to_cnodeid(devfs_handle_t vhdl);
-extern void             *swap_ptr(void **loc, void *new);
 extern char             *dev_to_name(devfs_handle_t dev, char *buf, uint buflen);
 extern struct map       *atemapalloc(uint64_t);
 extern void             atefree(struct map *, size_t, uint64_t);
 extern void             atemapfree(struct map *);
 extern pciio_dmamap_t   get_free_pciio_dmamap(devfs_handle_t);
 extern void		free_pciio_dmamap(pcibr_dmamap_t);
+extern void		xwidget_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
 
-#define	ATE_WRITE()    ate_write(ate_ptr, ate_count, ate)
+#define	ATE_WRITE()    ate_write(pcibr_soft, ate_ptr, ate_count, ate)
 #if PCIBR_FREEZE_TIME
 #define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs)
 #else
@@ -173,7 +141,6 @@
 #define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s)
 #endif
 
-
 /* =====================================================================
  *    Function Table of Contents
  *
@@ -183,58 +150,54 @@
  *      perhaps bust this file into smaller chunks.
  */
 
-extern void              do_pcibr_rrb_clear(bridge_t *, int);
-extern void              do_pcibr_rrb_flush(bridge_t *, int);
-extern int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t);
-extern int               do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t);
-extern int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int);
-extern int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int);
-
-extern void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int);
+extern int		 do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t);
+extern void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);
 
 extern int  		 pcibr_wrb_flush(devfs_handle_t);
 extern int               pcibr_rrb_alloc(devfs_handle_t, int *, int *);
-extern int               pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *);
-extern int               pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int);
 extern void              pcibr_rrb_flush(devfs_handle_t);
 
 static int                pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t);
 void                     pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t);
 
-extern void              pcibr_clearwidint(bridge_t *);
 extern void              pcibr_setwidint(xtalk_intr_t);
+extern void              pcibr_clearwidint(bridge_t *);
+
+extern iopaddr_t         pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t,
+                                              pciio_space_t, int, int, int);
 
 void                     pcibr_init(void);
 int                      pcibr_attach(devfs_handle_t);
+int			 pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t,
+				       int, pcibr_soft_t *);
 int			 pcibr_detach(devfs_handle_t);
 int                      pcibr_open(devfs_handle_t *, int, int, cred_t *);
 int                      pcibr_close(devfs_handle_t, int, int, cred_t *);
 int                      pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
 int                      pcibr_unmap(devfs_handle_t, vhandl_t *);
 int                      pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
-
-void                     pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
-
+int			 pcibr_pcix_rbars_calc(pcibr_soft_t);
 extern int               pcibr_init_ext_ate_ram(bridge_t *);
 extern int               pcibr_ate_alloc(pcibr_soft_t, int);
 extern void              pcibr_ate_free(pcibr_soft_t, int, int);
+extern int 		 pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl);
 
-extern unsigned          ate_freeze(pcibr_dmamap_t pcibr_dmamap,
+extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap,
 #if PCIBR_FREEZE_TIME
 	   		 unsigned *freeze_time_ptr,
 #endif
-						unsigned *cmd_regs);
-extern void              ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
-extern void              ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index,
+	   		 unsigned *cmd_regs);
+extern void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
+extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index,
 #if PCIBR_FREEZE_TIME
-	 				bridge_ate_t ate,
-	 				int ate_total,
-	 				unsigned freeze_time_start,
+	 		bridge_ate_t ate,
+	 		int ate_total,
+	 		unsigned freeze_time_start,
 #endif
-	 				unsigned *cmd_regs,
-	 				unsigned s);
+	 		unsigned *cmd_regs,
+	 		unsigned s);
 
-pcibr_info_t             pcibr_info_get(devfs_handle_t);
+pcibr_info_t      pcibr_info_get(devfs_handle_t);
 
 static iopaddr_t         pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);
 
@@ -264,23 +227,23 @@
 void                    pcibr_dmalist_drain(devfs_handle_t, alenlist_t);
 iopaddr_t               pcibr_dmamap_pciaddr_get(pcibr_dmamap_t);
 
-extern unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);
+extern unsigned		pcibr_intr_bits(pciio_info_t info, 
+					pciio_intr_line_t lines, int nslots);
 extern pcibr_intr_t     pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
 extern void             pcibr_intr_free(pcibr_intr_t);
 extern void             pcibr_setpciint(xtalk_intr_t);
-extern int              pcibr_intr_connect(pcibr_intr_t);
+extern int              pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
 extern void             pcibr_intr_disconnect(pcibr_intr_t);
 
 extern devfs_handle_t     pcibr_intr_cpu_get(pcibr_intr_t);
-extern void             pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
 extern void             pcibr_intr_func(intr_arg_t);
 
 extern void             print_bridge_errcmd(uint32_t, char *);
 
 extern void             pcibr_error_dump(pcibr_soft_t);
-extern uint32_t         pcibr_errintr_group(uint32_t);
+extern uint32_t       pcibr_errintr_group(uint32_t);
 extern void	        pcibr_pioerr_check(pcibr_soft_t);
-extern void             pcibr_error_intr_handler(intr_arg_t);
+extern void             pcibr_error_intr_handler(int, void *, struct pt_regs *);
 
 extern int              pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *);
 extern void             pcibr_error_cleanup(pcibr_soft_t, int);
@@ -289,8 +252,7 @@
 extern int              pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);
 extern int              pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);
 extern int              pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *);
-extern int              pcibr_error_devenable(devfs_handle_t, int);
-
+extern int              pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *);
 void                    pcibr_provider_startup(devfs_handle_t);
 void                    pcibr_provider_shutdown(devfs_handle_t);
 
@@ -303,7 +265,6 @@
 extern cfg_p            pcibr_config_addr(devfs_handle_t, unsigned);
 extern uint64_t         pcibr_config_get(devfs_handle_t, unsigned, unsigned);
 extern void             pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);
-extern void             do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
 
 extern pcibr_hints_t    pcibr_hints_get(devfs_handle_t, int);
 extern void             pcibr_hints_fix_rrbs(devfs_handle_t);
@@ -313,38 +274,31 @@
 extern void             pcibr_hints_handsoff(devfs_handle_t);
 extern void             pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t);
 
-#ifdef BRIDGE_B_DATACORR_WAR
-extern int              ql_bridge_rev_b_war(devfs_handle_t);
-extern int              bridge_rev_b_data_check_disable;
-char                   *rev_b_datacorr_warning =
-"***************************** WARNING! ******************************\n";
-char                   *rev_b_datacorr_mesg =
-"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n";
-#endif
-
 extern int		pcibr_slot_reset(devfs_handle_t,pciio_slot_t);
 extern int		pcibr_slot_info_init(devfs_handle_t,pciio_slot_t);
 extern int		pcibr_slot_info_free(devfs_handle_t,pciio_slot_t);
+extern int	        pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t,
+                                               pcibr_slot_info_resp_t);
+extern void       	pcibr_slot_func_info_return(pcibr_info_h, int,
+                                                    pcibr_slot_func_info_resp_t);
 extern int		pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t);
+extern int		pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t);
 extern int		pcibr_slot_device_init(devfs_handle_t, pciio_slot_t);
 extern int		pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t);
-extern int		pcibr_slot_call_device_attach(devfs_handle_t, pciio_slot_t, int);
-extern int		pcibr_slot_call_device_detach(devfs_handle_t, pciio_slot_t, int);
-extern int              pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, char *, int *);
-extern int              pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int);
+extern int		pcibr_slot_call_device_attach(devfs_handle_t,
+						      pciio_slot_t, int);
+extern int		pcibr_slot_call_device_detach(devfs_handle_t,
+						      pciio_slot_t, int);
+extern int              pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, 
+                                                      char *, int *);
+extern int              pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int,
+                                                      char *, int *);
 extern int 		pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t);
 
-#ifdef LATER
-extern int		pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
-extern int		pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
-extern int		pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
-#endif
-
 extern int		pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t);
 extern int		pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t);
 
 
-
 /* =====================================================================
  *    Device(x) register management
  */
@@ -377,7 +331,7 @@
     bridgereg_t             xmask;
 
     xmask = mask;
-    if (pcibr_soft->bs_xbridge) {
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
     	if (mask == BRIDGE_DEV_PMU_BITS)
 		xmask = XBRIDGE_DEV_PMU_BITS;
 	if (mask == BRIDGE_DEV_D64_BITS)
@@ -464,10 +418,10 @@
 	new &= ~BRIDGE_DEV_WRGA_BITS;
 
     if (flags & PCIIO_BYTE_STREAM)
-	new |= (pcibr_soft->bs_xbridge) ? 
+	new |= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? 
 			BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS;
     if (flags & PCIIO_WORD_VALUES)
-	new &= (pcibr_soft->bs_xbridge) ? 
+	new &= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? 
 			~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS;
 
     /* Provider-specific flags
@@ -492,13 +446,28 @@
     if (flags & PCIBR_NO64BIT)
 	new &= ~BRIDGE_DEV_DEV_SIZE;
 
+    /*
+     * PIC BRINGUP WAR (PV# 855271):
+     * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit
+     * device.  The bit is only intended for 64-bit devices and, on
+     * PIC, can cause problems for 32-bit devices.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && mask == BRIDGE_DEV_D64_BITS &&
+                                PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) {
+        if (flags & PCIBR_VCHAN1) {
+                new |= BRIDGE_DEV_VIRTUAL_EN;
+                xmask |= BRIDGE_DEV_VIRTUAL_EN;
+        }
+    }
+
+
     chg = old ^ new;				/* what are we changing, */
     chg &= xmask;				/* of the interesting bits */
 
     if (chg) {
 
 	badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0;
-	if (pcibr_soft->bs_xbridge) {
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0;
 		badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0;
 	} else {
@@ -517,7 +486,7 @@
 	     * the new stream at all.
 	     */
             if ( (fix = bad & (BRIDGE_DEV_PRECISE |
-                             BRIDGE_DEV_BARRIER)) ){
+                             BRIDGE_DEV_BARRIER)) ) {
 		bad &= ~fix;
 		/* don't change these bits if
 		 * they are already set in "old"
@@ -546,8 +515,10 @@
 	     */
 	    if (bad) {
 		pcibr_unlock(pcibr_soft, s);
-#if (DEBUG && PCIBR_DEV_DEBUG)
-		printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits);
+#ifdef PIC_LATER
+		PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,
+			    "pcibr_try_set_device: mod blocked by %x\n",
+			    bad, device_bits));
 #endif
 		return bad;
 	    }
@@ -571,14 +542,31 @@
 	pcibr_unlock(pcibr_soft, s);
 	return 0;
     }
-    bridge->b_device[slot].reg = new;
-    slotp->bss_device = new;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	bridge->b_device[slot].reg = new;
+	slotp->bss_device = new;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_device[slot].reg)) = __swab32(new);
+		slotp->bss_device = new;
+		BRIDGE_REG_GET32((&bridge->b_wid_tflush));  /* wait until Bridge PIO complete */
+	} else {
+		bridge->b_device[slot].reg = new;
+		slotp->bss_device = new;
+		bridge->b_wid_tflush;               /* wait until Bridge PIO complete */
+	}
+    }
     pcibr_unlock(pcibr_soft, s);
-#if DEBUG && PCIBR_DEV_DEBUG
-    printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg);
-#endif
 
+#ifdef PIC_LATER
+    PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,
+		"pcibr_try_set_device: Device(%d): %x\n",
+		slot, new, device_bits));
+#else
+    printk("pcibr_try_set_device: Device(%d): %x\n", slot, new);
+#endif
     return 0;
 }
 
@@ -616,7 +604,17 @@
     volatile uint32_t     wrf;
     s = pcibr_lock(pcibr_soft);
     bridge = pcibr_soft->bs_base;
-    wrf = bridge->b_wr_req_buf[slot].reg;
+
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	wrf = bridge->b_wr_req_buf[slot].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		wrf = BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg));
+	} else {
+		wrf = bridge->b_wr_req_buf[slot].reg;
+	}
+    }
     pcibr_unlock(pcibr_soft, s);
 }
 
@@ -637,9 +635,7 @@
 void
 pcibr_init(void)
 {
-#if DEBUG && ATTACH_DEBUG
-    printk("pcibr_init\n");
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pcibr_init()\n"));
 
     xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM,
 			    XBRIDGE_WIDGET_MFGR_NUM,
@@ -700,7 +696,7 @@
      * XXX- deprecate this in favor of using the
      * real flash driver ...
      */
-    if (!error &&
+    if (IS_BRIDGE_SOFT(pcibr_soft) && !error &&
 	((off == BRIDGE_EXTERNAL_FLASH) ||
 	 (len > BRIDGE_EXTERNAL_FLASH))) {
 	int                     s;
@@ -710,11 +706,16 @@
 	 * The read following the write is required for the Bridge war
 	 */
 	s = splhi();
-	bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN;
-	bridge->b_wid_control;		/* inval addr bug war */
+
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_wid_control)) |= __swab32(BRIDGE_CTRL_FLASH_WR_EN);
+		BRIDGE_REG_GET32((&bridge->b_wid_control));          /* inval addr bug war */
+	} else {
+		bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN;
+		bridge->b_wid_control;          /* inval addr bug war */
+	}
 	splx(s);
     }
-
     return error;
 }
 
@@ -728,21 +729,53 @@
 
     hwgraph_vertex_unref(pcibr_vhdl);
 
-    /*
-     * If flashprom write was enabled, disable it, as
-     * this is the last unmap.
-     */
-    if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) {
-	int                     s;
-
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
 	/*
-	 * ensure that we write and read without any interruption.
-	 * The read following the write is required for the Bridge war
+	 * If flashprom write was enabled, disable it, as
+	 * this is the last unmap.
 	 */
-	s = splhi();
-	bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
-	bridge->b_wid_control;		/* inval addr bug war */
-	splx(s);
+	if (IS_BRIDGE_SOFT(pcibr_soft) && 
+			(bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN)) {
+		int                     s;
+
+		/*
+		 * ensure that we write and read without any interruption.
+		 * The read following the write is required for the Bridge war
+		 */
+		s = splhi();
+		bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
+		bridge->b_wid_control;		/* inval addr bug war */
+		splx(s);
+	}
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		if (BRIDGE_REG_GET32((&bridge->b_wid_control)) & BRIDGE_CTRL_FLASH_WR_EN) {
+			int                     s;
+
+			/*
+			 * ensure that we write and read without any interruption.
+			 * The read following the write is required for the Bridge war
+			 */
+			s = splhi();
+			BRIDGE_REG_SET32((&bridge->b_wid_control)) &= __swab32((unsigned int)~BRIDGE_CTRL_FLASH_WR_EN);
+			BRIDGE_REG_GET32((&bridge->b_wid_control));          /* inval addr bug war */
+			splx(s);
+		} else {
+			if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) {
+				int                     s;
+
+				/*
+				 * ensure that we write and read without any interruption.
+				 * The read following the write is required for the Bridge war
+				 */
+				s = splhi();
+				bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
+				bridge->b_wid_control;          /* inval addr bug war */
+				splx(s);
+    			}
+		}
+	}
     }
     return 0;
 }
@@ -768,7 +801,7 @@
     while (tdev != GRAPH_VERTEX_NONE) {
 	pciio_info = pciio_info_chk(tdev);
 	if (pciio_info) {
-	    slot = pciio_info_slot_get(pciio_info);
+	    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 	    break;
 	}
 	hwgraph_vertex_unref(tdev);
@@ -788,167 +821,7 @@
 	    struct cred *cr,
 	    int *rvalp)
 {
-    devfs_handle_t            pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev);
-#ifdef LATER
-    pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-#endif
-    int                     error = 0;
-
-    hwgraph_vertex_unref(pcibr_vhdl);
-
-    switch (cmd) {
-#ifdef LATER
-    case GIOCSETBW:
-	{
-	    grio_ioctl_info_t       info;
-	    pciio_slot_t            slot = 0;
-
-	    if (!cap_able((uint64_t)CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-	    if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
-		error = EFAULT;
-		break;
-	    }
-#ifdef GRIO_DEBUG
-	    printk("pcibr:: prev_vhdl: %d reqbw: %lld\n",
-		    info.prev_vhdl, info.reqbw);
-#endif				/* GRIO_DEBUG */
-
-	    if ((slot = pcibr_device_slot_get(info.prev_vhdl)) ==
-		PCIIO_SLOT_NONE) {
-		error = EIO;
-		break;
-	    }
-	    if (info.reqbw)
-		pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH);
-	    break;
-	}
-
-    case GIOCRELEASEBW:
-	{
-	    grio_ioctl_info_t       info;
-	    pciio_slot_t            slot = 0;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-	    if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
-		error = EFAULT;
-		break;
-	    }
-#ifdef GRIO_DEBUG
-	    printk("pcibr:: prev_vhdl: %d reqbw: %lld\n",
-		    info.prev_vhdl, info.reqbw);
-#endif				/* GRIO_DEBUG */
-
-	    if ((slot = pcibr_device_slot_get(info.prev_vhdl)) ==
-		PCIIO_SLOT_NONE) {
-		error = EIO;
-		break;
-	    }
-	    if (info.reqbw)
-		pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW);
-	    break;
-	}
-
-    case PCIBR_SLOT_STARTUP:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-	    error = pcibr_slot_startup(pcibr_vhdl, &req);
-	    break;
-	}
-    case PCIBR_SLOT_SHUTDOWN:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-	    error = pcibr_slot_shutdown(pcibr_vhdl, &req);
-	    break;
-	}
-    case PCIBR_SLOT_QUERY:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-            error = pcibr_slot_query(pcibr_vhdl, &req);
-	    break;
-	}
-#endif	/* LATER */
-    default:
-	break;
-
-    }
-
-    return error;
-}
-
-void
-pcibr_freeblock_sub(iopaddr_t *free_basep,
-		    iopaddr_t *free_lastp,
-		    iopaddr_t base,
-		    size_t size)
-{
-    iopaddr_t               free_base = *free_basep;
-    iopaddr_t               free_last = *free_lastp;
-    iopaddr_t               last = base + size - 1;
-
-    if ((last < free_base) || (base > free_last));	/* free block outside arena */
-
-    else if ((base <= free_base) && (last >= free_last))
-	/* free block contains entire arena */
-	*free_basep = *free_lastp = 0;
-
-    else if (base <= free_base)
-	/* free block is head of arena */
-	*free_basep = last + 1;
-
-    else if (last >= free_last)
-	/* free block is tail of arena */
-	*free_lastp = base - 1;
-
-    /*
-     * We are left with two regions: the free area
-     * in the arena "below" the block, and the free
-     * area in the arena "above" the block. Keep
-     * the one that is bigger.
-     */
-
-    else if ((base - free_base) > (free_last - last))
-	*free_lastp = base - 1;		/* keep lower chunk */
-    else
-	*free_basep = last + 1;		/* keep upper chunk */
+    return 0;
 }
 
 pcibr_info_t
@@ -971,16 +844,22 @@
 
     func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc;
 
+    /*
+     * Create a pciio_info_s for this device.  pciio_device_info_new()
+     * will set the c_slot (which is suppose to represent the external
+     * slot (i.e the slot number silk screened on the back of the I/O
+     * brick)).  So for PIC we need to adjust this "internal slot" num
+     * passed into us, into it's external representation.  See comment
+     * for the PCIBR_DEVICE_TO_SLOT macro for more information.
+     */
     NEW(pcibr_info);
+    pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl,
+			  PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+			  rfunc, vendor, device);
+    pcibr_info->f_dev = slot;
 
-    pciio_device_info_new(&pcibr_info->f_c,
-			  pcibr_soft->bs_vhdl,
-			  slot, rfunc,
-			  vendor, device);
-
-/* pfg - this is new ..... */
     /* Set PCI bus number */
-    pcibr_info->f_bus = io_path_map_widget(pcibr_soft->bs_vhdl);
+    pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl);
 
     if (slot != PCIIO_SLOT_NONE) {
 
@@ -1016,30 +895,6 @@
 }
 
 
-/* FIXME:  for now this is needed by both pcibr.c and
- * pcibr_slot.c.  Need to find a better way, the least
- * of which would be to move it to pcibr_private.h
- */
-
-/*
- * PCI_ADDR_SPACE_LIMITS_STORE
- *	Sets the current values of
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_STORE()			\
-    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\
-    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\
-    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\
-    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\
-    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\
-    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
-
-
 /*
  * pcibr_device_unregister
  *	This frees up any hardware resources reserved for this PCI device
@@ -1062,7 +917,7 @@
     pciio_info = pciio_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge = pcibr_soft->bs_base;
@@ -1077,27 +932,24 @@
      * If the RRB configuration for this slot has changed, set it 
      * back to the boot-time default
      */
-    if (pcibr_soft->bs_rrb_valid_dflt[slot] >= 0) {
+    if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) {
 
         s = pcibr_lock(pcibr_soft);
 
-        /* Free the rrbs allocated to this slot */
-        error_call = do_pcibr_rrb_free(bridge, slot, 
-		                       pcibr_soft->bs_rrb_valid[slot] +
-		                       pcibr_soft->bs_rrb_valid[slot + 
-                                       PCIBR_RRB_SLOT_VIRTUAL]);
-
-        if (error_call)
-            error = ERANGE;
-   
-         pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] +
-                                        pcibr_soft->bs_rrb_valid[slot] +
-                                        pcibr_soft->bs_rrb_valid[slot +
-                                        PCIBR_RRB_SLOT_VIRTUAL];
-
-        count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot];
-        count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot +
-                                                     PCIBR_RRB_SLOT_VIRTUAL];
+	/* PIC NOTE: If this is a BRIDGE, VCHAN2 & VCHAN3 will be zero so
+	 * no need to conditionalize this (ie. "if (IS_PIC_SOFT())" ).
+	 */
+        pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN0] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN1] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN2] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN3];
+
+        /* Free the rrbs allocated to this slot, both the normal & virtual */
+	do_pcibr_rrb_free_all(pcibr_soft, bridge, slot);
+
+        count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0];
+        count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1];
 
         pcibr_unlock(pcibr_soft, s);
 
@@ -1147,12 +999,14 @@
     pcibr_info = pcibr_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
+#ifdef PIC_LATER
     /* This may be a loadable driver so lock out any pciconfig actions */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     pcibr_info->f_att_det_error = error;
 
@@ -1164,9 +1018,10 @@
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
     }
         
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
 }
 
 /*
@@ -1195,12 +1050,14 @@
     pcibr_info = pcibr_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
+#ifdef PIC_LATER
     /* This may be a loadable driver so lock out any pciconfig actions */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     pcibr_info->f_att_det_error = error;
 
@@ -1211,10 +1068,11 @@
     } else {
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
     }
-        
+
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
 }
 
 /* 
@@ -1226,7 +1084,7 @@
  * depends on hwgraph separator == '/'
  */
 int
-pcibr_bus_cnvlink(devfs_handle_t f_c, int slot)
+pcibr_bus_cnvlink(devfs_handle_t f_c)
 {
         char dst[MAXDEVNAME];
 	char *dp = dst;
@@ -1236,16 +1094,7 @@
 	devfs_handle_t nvtx, svtx;
 	int rv;
 
-#if DEBUG
-	printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", 
-		slot, f_c);
-	{
-		int pos;
-		char dname[256];
-		pos = devfs_generate_path(f_c, dname, 256);
-		printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
-	}
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n"));
 
 	if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME))
 		return 0;
@@ -1261,7 +1110,7 @@
 		return 0;
 
 	/* remove "/pci/direct" from path */
-	cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct");
+	cp = strstr(dst, "/" EDGE_LBL_PCI "/" EDGE_LBL_DIRECT);
 	if (cp == NULL)
 		return 0;
 	*cp = (char)NULL;
@@ -1275,7 +1124,8 @@
 	/* dst example now == /hw/module/001c02/Pbrick */
 
 	/* get the bus number */
-        strcat(dst, "/bus");
+        strcat(dst, "/");
+        strcat(dst, EDGE_LBL_BUS);
         sprintf(pcibus, "%d", p_busnum[widgetnum]);
 
 	/* link to bus to widget */
@@ -1300,75 +1150,74 @@
     /* REFERENCED */
     graph_error_t           rc;
     devfs_handle_t            pcibr_vhdl;
+    bridge_t               *bridge;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n"));
+
+    bridge = (bridge_t *)
+	xtalk_piotrans_addr(xconn_vhdl, NULL,
+			    0, sizeof(bridge_t), 0);
+    /*
+     * Create the vertex for the PCI bus, which we
+     * will also use to hold the pcibr_soft and
+     * which will be the "master" vertex for all the
+     * pciio connection points we will hang off it.
+     * This needs to happen before we call nic_bridge_vertex_info
+     * as we are some of the *_vmc functions need access to the edges.
+     *
+     * Opening this vertex will provide access to
+     * the Bridge registers themselves.
+     */
+    rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl);
+    ASSERT(rc == GRAPH_SUCCESS);
+
+    pciio_provider_register(pcibr_vhdl, &pcibr_provider);
+    pciio_provider_startup(pcibr_vhdl);
+
+    return pcibr_attach2(xconn_vhdl, bridge, pcibr_vhdl, 0, NULL);
+}
+
+
+/*ARGSUSED */
+int
+pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, 
+	      devfs_handle_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp)
+{
+    /* REFERENCED */
     devfs_handle_t            ctlr_vhdl;
-    bridge_t               *bridge = NULL;
     bridgereg_t             id;
     int                     rev;
     pcibr_soft_t            pcibr_soft;
     pcibr_info_t            pcibr_info;
     xwidget_info_t          info;
     xtalk_intr_t            xtalk_intr;
-    device_desc_t           dev_desc = (device_desc_t)0;
     int                     slot;
     int                     ibit;
     devfs_handle_t            noslot_conn;
     char                    devnm[MAXDEVNAME], *s;
     pcibr_hints_t           pcibr_hints;
-    bridgereg_t             b_int_enable;
+    uint64_t              int_enable;
+    bridgereg_t             int_enable_32;
+    picreg_t                int_enable_64;
     unsigned                rrb_fixed = 0;
 
-    iopaddr_t               pci_io_fb, pci_io_fl;
-    iopaddr_t               pci_lo_fb, pci_lo_fl;
-    iopaddr_t               pci_hi_fb, pci_hi_fl;
-
     int                     spl_level;
-#ifdef LATER
-    char		    *nicinfo = (char *)0;
-#endif
 
 #if PCI_FBBE
     int                     fast_back_to_back_enable;
 #endif
-    l1sc_t		    *scp;
     nasid_t		    nasid;
+    int	                    iobrick_type_get_nasid(nasid_t nasid);
+    int                     iobrick_module_get_nasid(nasid_t nasid);
+    extern unsigned char    Is_pic_on_this_nasid[512];
 
-    async_attach_t          aa = NULL;
-
-    aa = async_attach_get_info(xconn_vhdl);
 
-#if DEBUG && ATTACH_DEBUG
-    printk("pcibr_attach: xconn_vhdl=  %p\n", xconn_vhdl);
-    {
-	int pos;
-	char dname[256];
-	pos = devfs_generate_path(xconn_vhdl, dname, 256);
-	printk("%s : path= %s \n", __FUNCTION__, &dname[pos]);
-    }
-#endif
-
-    /* Setup the PRB for the bridge in CONVEYOR BELT
-     * mode. PRBs are setup in default FIRE-AND-FORGET
-     * mode during the initialization.
-     */
-    hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR);
+    async_attach_t          aa = NULL;
 
-    bridge = (bridge_t *)
-	xtalk_piotrans_addr(xconn_vhdl, NULL,
-			    0, sizeof(bridge_t), 0);
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+	        "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum));
 
-    /*
-     * Create the vertex for the PCI bus, which we
-     * will also use to hold the pcibr_soft and
-     * which will be the "master" vertex for all the
-     * pciio connection points we will hang off it.
-     * This needs to happen before we call nic_bridge_vertex_info
-     * as we are some of the *_vmc functions need access to the edges.
-     *
-     * Opening this vertex will provide access to
-     * the Bridge registers themselves.
-     */
-    rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl);
-    ASSERT(rc == GRAPH_SUCCESS);
+    aa = async_attach_get_info(xconn_vhdl);
 
     ctlr_vhdl = NULL;
     ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER,
@@ -1380,15 +1229,6 @@
     ASSERT(ctlr_vhdl != NULL);
 
     /*
-     * decode the nic, and hang its stuff off our
-     * connection point where other drivers can get
-     * at it.
-     */
-#ifdef LATER
-    nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic);
-#endif
-
-    /*
      * Get the hint structure; if some NIC callback
      * marked this vertex as "hands-off" then we
      * just return here, before doing anything else.
@@ -1408,26 +1248,63 @@
      * fields, and hook it up to our vertex.
      */
     NEW(pcibr_soft);
+    if (ret_softp)
+	*ret_softp = pcibr_soft;
     BZERO(pcibr_soft, sizeof *pcibr_soft);
     pcibr_soft_set(pcibr_vhdl, pcibr_soft);
-
     pcibr_soft->bs_conn = xconn_vhdl;
     pcibr_soft->bs_vhdl = pcibr_vhdl;
     pcibr_soft->bs_base = bridge;
     pcibr_soft->bs_rev_num = rev;
-    pcibr_soft->bs_intr_bits = pcibr_intr_bits;
+    pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits;
+
+    pcibr_soft->bs_min_slot = 0;		/* lowest possible slot# */
+    pcibr_soft->bs_max_slot = 7;		/* highest possible slot# */
+    pcibr_soft->bs_busnum = busnum;
     if (is_xbridge(bridge)) {
-	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
-	pcibr_soft->bs_xbridge = 1;
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_XBRIDGE;
+    } else if (is_pic(bridge)) {
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC;
     } else {
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_BRIDGE;
+    }
+    switch(pcibr_soft->bs_bridge_type) {
+    case PCIBR_BRIDGETYPE_BRIDGE:
 	pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES;
-	pcibr_soft->bs_xbridge = 0;
+	pcibr_soft->bs_bridge_mode = 0;	/* speed is not available in bridge */
+	break;
+    case PCIBR_BRIDGETYPE_PIC:
+        pcibr_soft->bs_min_slot = 0;
+	pcibr_soft->bs_max_slot = 3;
+	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
+	pcibr_soft->bs_bridge_mode = 
+	   (((bridge->p_wid_stat_64 & PIC_STAT_PCIX_SPEED) >> 33) |
+	    ((bridge->p_wid_stat_64 & PIC_STAT_PCIX_ACTIVE) >> 33));
+
+	/* We have to clear PIC's write request buffer to avoid parity
+	 * errors.  See PV#854845.
+	 */
+	{
+	int i;
+
+	for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) {
+		bridge->p_wr_req_lower[i] = 0;
+		bridge->p_wr_req_upper[i] = 0;
+		bridge->p_wr_req_parity[i] = 0;
+	}
+	}
+
+	break;
+    case PCIBR_BRIDGETYPE_XBRIDGE:
+	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
+	pcibr_soft->bs_bridge_mode = 
+	   ((bridge->b_wid_control & BRIDGE_CTRL_PCI_SPEED) >> 3);
+	break;
     }
 
-    nasid = NASID_GET(bridge);
-    scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
-    pcibr_soft->bs_l1sc = scp;
-    pcibr_soft->bs_moduleid = iobrick_module_get(scp);
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		"pcibr_attach2: pcibr_soft=0x%x, mode=0x%x\n",
+                pcibr_soft, pcibr_soft->bs_bridge_mode));
     pcibr_soft->bsi_err_intr = 0;
 
     /* Bridges up through REV C
@@ -1439,6 +1316,9 @@
 	pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES;
     }
 #if PCIBR_SOFT_LIST
+    /*
+     * link all the pcibr_soft structs
+     */
     {
 	pcibr_list_p            self;
 
@@ -1446,9 +1326,9 @@
 	self->bl_soft = pcibr_soft;
 	self->bl_vhdl = pcibr_vhdl;
 	self->bl_next = pcibr_list;
-	self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self);
+	pcibr_list = self;
     }
-#endif
+#endif /* PCIBR_SOFT_LIST */
 
     /*
      * get the name of this bridge vertex and keep the info. Use this
@@ -1458,45 +1338,114 @@
     pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
     strcpy(pcibr_soft->bs_name, s);
 
-#if SHOW_REVS || DEBUG
-#if !DEBUG
-    if (kdebug)
-#endif
-	printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n",
-		is_xbridge(bridge) ? "X" : "",
-		(rev == BRIDGE_PART_REV_A) ? "A" :
-		(rev == BRIDGE_PART_REV_B) ? "B" :
-		(rev == BRIDGE_PART_REV_C) ? "C" :
-		(rev == BRIDGE_PART_REV_D) ? "D" :
-		(rev == XBRIDGE_PART_REV_A) ? "A" :
-		(rev == XBRIDGE_PART_REV_B) ? "B" :
-		"unknown",
-		rev, pcibr_soft->bs_name);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		"pcibr_attach2: %s ASIC: rev %s (code=0x%x)\n",
+		IS_XBRIDGE_SOFT(pcibr_soft) ? "XBridge" :
+			IS_PIC_SOFT(pcibr_soft) ? "PIC" : "Bridge", 
+		(rev == BRIDGE_PART_REV_A) ? "A" : 
+                (rev == BRIDGE_PART_REV_B) ? "B" :
+                (rev == BRIDGE_PART_REV_C) ? "C" :
+                (rev == BRIDGE_PART_REV_D) ? "D" :
+                (rev == XBRIDGE_PART_REV_A) ? "A" :
+                (rev == XBRIDGE_PART_REV_B) ? "B" :
+                (IS_PIC_PART_REV_A(rev)) ? "A" : 
+                "unknown", rev, pcibr_soft->bs_name));
 
     info = xwidget_info_get(xconn_vhdl);
     pcibr_soft->bs_xid = xwidget_info_id_get(info);
     pcibr_soft->bs_master = xwidget_info_master_get(info);
     pcibr_soft->bs_mxid = xwidget_info_masterid_get(info);
 
+    pcibr_soft->bs_first_slot = pcibr_soft->bs_min_slot;
+    pcibr_soft->bs_last_slot = pcibr_soft->bs_max_slot;
     /*
-     * Init bridge lock.
+     * Bridge can only reset slots 0, 1, 2, and 3.  Ibrick internal
+     * slots 4, 5, 6, and 7 must be reset as a group, so do not
+     * reset them.
      */
-    spin_lock_init(&pcibr_soft->bs_lock);
+    pcibr_soft->bs_last_reset = 3;
+
+    nasid = NASID_GET(bridge);
+
+    /* set whether it is a PIC or not */
+    Is_pic_on_this_nasid[nasid] = (IS_PIC_SOFT(pcibr_soft)) ? 1 : 0;
+
+
+    if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0)
+	printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl,
+				(unsigned int)pcibr_soft->bs_bricktype);
+
+    pcibr_soft->bs_moduleid = iobrick_module_get_nasid(nasid);
+
+    if (pcibr_soft->bs_bricktype > 0) {
+	switch (pcibr_soft->bs_bricktype) {
+	case MODULE_PXBRICK:
+	    pcibr_soft->bs_first_slot = 0;
+	    pcibr_soft->bs_last_slot = 1;
+	    pcibr_soft->bs_last_reset = 1;
+	    break;
+	case MODULE_PEBRICK:
+	case MODULE_PBRICK:
+            pcibr_soft->bs_first_slot = 1;
+            pcibr_soft->bs_last_slot = 2;
+            pcibr_soft->bs_last_reset = 2;
+            break;
+
+        case MODULE_IBRICK:
+	    /*
+	     * Here's the current baseio layout for SN1 style systems:
+	     *
+	     *    0    1    2    3    4    5    6    7		slot#
+	     *
+	     *    x    scsi x    x    ioc3 usb  x    x  	O300 Ibrick
+	     *
+             * x == never occupied
+             * E == external (add-in) slot
+	     *
+	     */
+            pcibr_soft->bs_first_slot = 1;	/* Ibrick first slot == 1 */
+            if (pcibr_soft->bs_xid == 0xe) { 
+                pcibr_soft->bs_last_slot = 2;
+                pcibr_soft->bs_last_reset = 2;
+            } else {
+		pcibr_soft->bs_last_slot = 6;
+	    }
+            break;
+	default:
+	    break;
+        }
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		    "pcibr_attach2: %cbrick, slots %d-%d\n",
+		    MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid),
+		    pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot));
+    }
 
     /*
+     * Initialize bridge and bus locks
+     */
+    spin_lock_init(&pcibr_soft->bs_lock);
+#ifdef PIC_LATER
+    mrinit(pcibr_soft->bs_bus_lock, "bus_lock");
+#endif
+    /*
      * If we have one, process the hints structure.
      */
     if (pcibr_hints) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl,
+                    "pcibr_attach2: pcibr_hints=0x%x\n", pcibr_hints));
+
 	rrb_fixed = pcibr_hints->ph_rrb_fixed;
 
 	pcibr_soft->bs_rrb_fixed = rrb_fixed;
 
-	if (pcibr_hints->ph_intr_bits)
+	if (pcibr_hints->ph_intr_bits) {
 	    pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits;
+	}
 
-	for (slot = 0; slot < 8; ++slot) {
-	    int                     hslot = pcibr_hints->ph_host_slot[slot] - 1;
+	for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	    int hslot = pcibr_hints->ph_host_slot[slot] - 1;
 
 	    if (hslot < 0) {
 		pcibr_soft->bs_slot[slot].host_slot = slot;
@@ -1507,13 +1456,16 @@
 	}
     }
     /*
-     * set up initial values for state fields
+     * Set-up initial values for state fields
      */
-    for (slot = 0; slot < 8; ++slot) {
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 	pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE;
+	pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0;
 	pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET;
 	pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET;
 	pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0);
+	pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1;
     }
 
     for (ibit = 0; ibit < 8; ++ibit) {
@@ -1522,15 +1474,31 @@
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = 
 							&(bridge->b_int_status);
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0;
     }
 
     /*
+     * connect up our error handler.  PIC has 2 busses (thus resulting in 2
+     * pcibr_soft structs under 1 widget), so only register a xwidget error
+     * handler for PIC's bus0.  NOTE: for PIC pcibr_error_handler_wrapper()
+     * is a wrapper routine we register that will call the real error handler
+     * pcibr_error_handler() with the correct pcibr_soft struct.
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	if (busnum == 0) {
+	    xwidget_error_register(xconn_vhdl, pcibr_error_handler_wrapper, pcibr_soft);
+	}
+    } else {
+	xwidget_error_register(xconn_vhdl, pcibr_error_handler, pcibr_soft);
+    }
+
+    /*
      * Initialize various Bridge registers.
      */
-
+  
     /*
      * On pre-Rev.D bridges, set the PCI_RETRY_CNT
      * to zero to avoid dropping stores. (#475347)
@@ -1543,12 +1511,43 @@
      */
     bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR);
 
+    /* Initialize some PIC specific registers. */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	picreg_t pic_ctrl_reg = bridge->p_wid_control_64;
+
+	/* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */
+	pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK;
+	pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum);
+	pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK;
+	pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK;
+
+	pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP;
+	pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER;
+
+	/* enable parity checking on PICs internal RAM */
+	pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP;
+	pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE;
+	/* PIC BRINGUP WAR (PV# 862253): dont enable write request
+	 * parity checking.
+	 */
+	if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) {
+	    pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ;
+	}
+
+	bridge->p_wid_control_64 = pic_ctrl_reg;
+    }
+
     /*
      * Until otherwise set up,
      * assume all interrupts are
-     * from slot 7.
+     * from slot 7(Bridge/Xbridge) or 3(PIC).
+     * XXX. Not sure why we're doing this, made change for PIC
+     * just to avoid setting reserved bits.
      */
-    bridge->b_int_device = (uint32_t) 0xffffffff;
+    if (IS_PIC_SOFT(pcibr_soft))
+	bridge->b_int_device = (uint32_t) 0x006db6db;
+    else
+	bridge->b_int_device = (uint32_t) 0xffffffff;
 
     {
 	bridgereg_t             dirmap;
@@ -1560,6 +1559,11 @@
 	int                     entry;
 	cnodeid_t		cnodeid;
 	nasid_t			nasid;
+#ifdef PIC_LATER
+	char		       *node_val;
+	devfs_handle_t		node_vhdl;
+	char			vname[MAXDEVNAME];
+#endif
 
 	/* Set the Bridge's 32-bit PCI to XTalk
 	 * Direct Map register to the most useful
@@ -1578,6 +1582,30 @@
 	 */
 
 	cnodeid = 0;  /* default node id */
+	/*
+	 * Determine the base address node id to be used for all 32-bit
+	 * Direct Mapping I/O. The default is node 0, but this can be changed
+	 * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE
+	 * attribute in the irix.sm config file. A device driver can obtain
+	 * this node value via a call to pcibr_get_dmatrans_node().
+	 */
+#ifdef PIC_LATER
+// This probably needs to be addressed - pfg
+	node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE);
+	if (node_val != NULL) {
+	    node_vhdl = hwgraph_path_to_vertex(node_val);
+	    if (node_vhdl != GRAPH_VERTEX_NONE) {
+		cnodeid = nodevertex_to_cnodeid(node_vhdl);
+	    }
+	    if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) {
+		cnodeid = 0;
+		vertex_to_name(pcibr_vhdl, vname, sizeof(vname));
+		printk(KERN_WARNING "Invalid hwgraph node path specified:\n"
+			"    DEVICE_ADMIN: %s %s=%s\n",
+			vname, ADMIN_LBL_DMATRANS_NODE, node_val);
+	    }
+	}
+#endif	/* PIC_LATER */
 	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
 	paddr = NODE_OFFSET(nasid) + 0;
 
@@ -1619,9 +1647,17 @@
 	 */
 	spl_level = splhi();
 #if IOPGSIZE == 4096
-	bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            bridge->p_wid_control_64 &= ~BRIDGE_CTRL_PAGE_SIZE;
+        } else {
+            bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;
+        }
 #elif IOPGSIZE == 16384
-	bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE;
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            bridge->p_wid_control_64 |= BRIDGE_CTRL_PAGE_SIZE;
+        } else {
+            bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE;
+        }
 #else
 	<<<Unable to deal with IOPGSIZE >>>;
 #endif
@@ -1652,7 +1688,8 @@
 	 * recomparing against BRIDGE_INTERNAL_ATES every
 	 * time.
 	 */
-	if (is_xbridge(bridge))
+
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
 		num_entries = 0;
 	else
 		num_entries = pcibr_init_ext_ate_ram(bridge);
@@ -1662,9 +1699,6 @@
 	 */
 	pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size);
 	pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size);
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size);
-#endif
 
 	if (num_entries > pcibr_soft->bs_int_ate_size) {
 #if PCIBR_ATE_NOTBOTH			/* for debug -- forces us to use external ates */
@@ -1674,11 +1708,12 @@
 	    pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries);
 	    pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size,
 			   num_entries - pcibr_soft->bs_int_ate_size);
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_attach: %d EXTERNAL ATEs\n",
-		    num_entries - pcibr_soft->bs_int_ate_size);
-#endif
 	}
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl,
+		    "pcibr_attach2: %d ATEs, %d internal & %d external\n",
+		    num_entries ? num_entries : pcibr_soft->bs_int_ate_size,
+		    pcibr_soft->bs_int_ate_size,
+		    num_entries ? num_entries-pcibr_soft->bs_int_ate_size : 0));
     }
 
     {
@@ -1727,7 +1762,7 @@
      * knows to do this.
      */
 
-    xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl);
+    xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl);
     ASSERT(xtalk_intr != NULL);
 
     pcibr_soft->bsi_err_intr = xtalk_intr;
@@ -1740,17 +1775,124 @@
      */
     pcibr_clearwidint(bridge);
 
-    xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge);
+    xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler,
+		(intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge);
+
+#ifdef BUS_INT_WAR_NOT_YET
+    request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid,
+			((hub_intr_t)xtalk_intr)->i_bit),
+				(intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error",
+					(intr_arg_t) pcibr_soft);
+#endif
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl,
+		"pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n",
+		bridge->b_wid_int_upper, bridge->b_wid_int_lower));
 
     /*
      * now we can start handling error interrupts;
      * enable all of them.
      * NOTE: some PCI ints may already be enabled.
      */
-    b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS;
+    /* We read the INT_ENABLE register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS;
+        int_enable = (uint64_t)int_enable_64;
+    } else {
+	int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff);
+	int_enable = ((uint64_t)int_enable_32 & 0xffffffff);
+    }
+#ifdef BUS_INT_WAR_NOT_YET
+    {
+	extern void sn_add_polled_interrupt(int irq, int interval);
+
+        sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid,
+				((hub_intr_t)xtalk_intr)->i_bit), 20000);
+    }
+#endif
+
+
+#if BRIDGE_ERROR_INTR_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {
+	/*
+	 * We commonly get master timeouts when talking to ql.
+	 * We also see RESP_XTALK_ERROR and LLP_TX_RETRY interrupts.
+	 * Insure that these are all disabled for now.
+	 */
+	int_enable &= ~(BRIDGE_IMR_PCI_MST_TIMEOUT |
+			BRIDGE_ISR_RESP_XTLK_ERR |
+			BRIDGE_ISR_LLP_TX_RETRY);
+    }
+    if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) {
+	int_enable &= ~BRIDGE_ISR_BAD_XRESP_PKT;
+    }
+#endif				/* BRIDGE_ERROR_INTR_WAR */
+
+#ifdef QL_SCSI_CTRL_WAR			/* for IP30 only */
+    /* Really a QL rev A issue, but all newer hearts have newer QLs.
+     * Forces all IO6/MSCSI to be new.
+     */
+    if (heart_rev() == HEART_REV_A)
+	int_enable &= ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+#endif
+
+#ifdef BRIDGE1_TIMEOUT_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {
+	/*
+	 * Turn off these interrupts.  They can't be trusted in bridge 1
+	 */
+	int_enable &= ~(BRIDGE_IMR_XREAD_REQ_TIMEOUT |
+			BRIDGE_IMR_UNEXP_RESP);
+    }
+#endif
+
+#ifdef BRIDGE_B_DATACORR_WAR
+
+    /* WAR panic for Rev B silent data corruption.
+     * PIOERR turned off here because there is a problem
+     * with not re-arming it in pcibr_error_intr_handler.
+     * We don't get LLP error interrupts if we don't
+     * re-arm PIOERR interrupts! Just disable them here
+     */
 
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) {
+	int_enable |= BRIDGE_IMR_LLP_REC_CBERR;
+	int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR;
 
-    bridge->b_int_enable = b_int_enable;
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		    "Turning on LLP_REC_CBERR for Rev B Bridge.\n"));
+    }
+#endif
+
+    /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are
+     * locked out to be freed up sooner (by timing out) so that the
+     * read tnums are never completely used up.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) {
+        int_enable &= ~PIC_ISR_PCIX_REQ_TOUT;
+        int_enable &= ~BRIDGE_ISR_XREAD_REQ_TIMEOUT;
+
+        bridge->b_wid_req_timeout = 0x750;
+    }
+
+    /*
+     * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use
+     * RRB0, RRB8, RRB1, and RRB9.  Assign them to DEVICE[2|3]--VCHAN3
+     * so they are not used
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) {
+        bridge->b_even_resp |= 0x000f000f;
+        bridge->b_odd_resp |= 0x000f000f;
+    }
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        bridge->p_int_enable_64 = (picreg_t)int_enable;
+    } else {
+        bridge->b_int_enable = (bridgereg_t)int_enable;
+    }
     bridge->b_int_mode = 0;		/* do not send "clear interrupt" packets */
 
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
@@ -1788,20 +1930,59 @@
 		(BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev))
 	pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER;
 
-    pciio_provider_register(pcibr_vhdl, &pcibr_provider);
-    pciio_provider_startup(pcibr_vhdl);
-
-    pci_io_fb = 0x00000004;		/* I/O FreeBlock Base */
-    pci_io_fl = 0xFFFFFFFF;		/* I/O FreeBlock Last */
-
-    pci_lo_fb = 0x00000010;		/* Low Memory FreeBlock Base */
-    pci_lo_fl = 0x001FFFFF;		/* Low Memory FreeBlock Last */
+    /* PIC only supports 64-bit direct mapping in PCI-X mode.  Since
+     * all PCI-X devices that initiate memory transactions must be
+     * capable of generating 64-bit addressed, we force 64-bit DMAs.
+     */
+    if (IS_PCIX(pcibr_soft)) {
+	pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64;
+    }
 
-    pci_hi_fb = 0x00200000;		/* High Memory FreeBlock Base */
-    pci_hi_fl = 0x3FFFFFFF;		/* High Memory FreeBlock Last */
+    {
 
+    pciio_win_map_t         win_map_p;
+    iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;
+    int                     prom_base_size = 0x1000000;
+    iopaddr_t               prom_base_limit = prom_base_addr + prom_base_size; 
+
+    /* Allocate resource maps based on bus page size; for I/O and memory
+     * space, free all pages except those in the base area and in the
+     * range set by the PROM. 
+     *
+     * PROM creates BAR addresses in this format: 0x0ws00000 where w is
+     * the widget number and s is the device register offset for the slot.
+     */
 
-    PCI_ADDR_SPACE_LIMITS_STORE();
+    win_map_p = &pcibr_soft->bs_io_win_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_IO_MAX + 1,
+			     PCIBR_BUS_IO_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_IO_BASE,
+			      prom_base_addr - PCIBR_BUS_IO_BASE);
+    pciio_device_win_populate(win_map_p,
+			      prom_base_limit,
+			      (PCIBR_BUS_IO_MAX + 1) - prom_base_limit);
+
+    win_map_p = &pcibr_soft->bs_swin_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_SWIN_MAX + 1,
+			     PCIBR_BUS_SWIN_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_SWIN_BASE,
+			      (PCIBR_BUS_SWIN_MAX + 1) - PCIBR_BUS_SWIN_PAGE);
+
+    win_map_p = &pcibr_soft->bs_mem_win_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_MEM_MAX + 1,
+			     PCIBR_BUS_MEM_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_MEM_BASE,
+			      prom_base_addr - PCIBR_BUS_MEM_BASE);
+    pciio_device_win_populate(win_map_p,
+			      prom_base_limit,
+			      (PCIBR_BUS_MEM_MAX + 1) - prom_base_limit);
+    }
 
     /* build "no-slot" connection point
      */
@@ -1830,59 +2011,91 @@
     }
 #endif
 
-#ifdef LATER
-    /* If the bridge has been reset then there is no need to reset
-     * the individual PCI slots.
-     */
-    for (slot = 0; slot < 8; ++slot)  
-	/* Reset all the slots */
-	(void)pcibr_slot_reset(pcibr_vhdl, slot);
-#endif
-
-    for (slot = 0; slot < 8; ++slot)
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 	/* Find out what is out there */
 	(void)pcibr_slot_info_init(pcibr_vhdl,slot);
+    }
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Set up the address space for this slot in the PCI land */
+	(void)pcibr_slot_addr_space_init(pcibr_vhdl, slot);
 
-    for (slot = 0; slot < 8; ++slot)  
-	/* Set up the address space for this slot in the pci land */
-	(void)pcibr_slot_addr_space_init(pcibr_vhdl,slot);
-
-    for (slot = 0; slot < 8; ++slot)  
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
 	/* Setup the device register */
 	(void)pcibr_slot_device_init(pcibr_vhdl, slot);
 
-    for (slot = 0; slot < 8; ++slot)  
-	/* Setup host/guest relations */
-	(void)pcibr_slot_guest_info_init(pcibr_vhdl,slot);
-
-    for (slot = 0; slot < 8; ++slot)  
-	/* Initial RRB management */
-	(void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot);
+    if (IS_PCIX(pcibr_soft)) {
+        pcibr_soft->bs_pcix_rbar_inuse = 0;
+        pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
+	pcibr_soft->bs_pcix_rbar_percent_allowed = 
+					pcibr_pcix_rbars_calc(pcibr_soft);
+
+	for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	    /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */
+	    (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot);
+    }
+
+    /* Set up convenience links */
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
+	pcibr_bus_cnvlink(pcibr_soft->bs_vhdl);
 
-    /* driver attach routines should be called out from generic linux code */
-    for (slot = 0; slot < 8; ++slot)  
-	/* Call the device attach */
-	(void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0);
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Setup host/guest relations */
+	(void)pcibr_slot_guest_info_init(pcibr_vhdl, slot);
 
+    /* Handle initial RRB management for Bridge and Xbridge */
+    pcibr_initial_rrb(pcibr_vhdl, 
+                      pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot);
+    
+{  /* Before any drivers get called that may want to re-allocate
+    * RRB's, let's get some special cases pre-allocated. Drivers
+    * may override these pre-allocations, but by doing pre-allocations
+    * now we're assured not to step all over what the driver intended.
+    *
+    * Note: Someday this should probably be moved over to pcibr_rrb.c
+    */
     /*
      * Each Pbrick PCI bus only has slots 1 and 2.   Similarly for
      * widget 0xe on Ibricks.  Allocate RRB's accordingly.
      */
-    if (pcibr_soft->bs_moduleid > 0) {
-	switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) {
-	case 'p':		/* Pbrick */
-		do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-		do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+    if (pcibr_soft->bs_bricktype > 0) {
+	switch (pcibr_soft->bs_bricktype) {
+	case MODULE_PXBRICK:
+		/* 
+		 * If the IO9 is in the PXBrick (bus1, slot1) allocate
+                 * RRBs to all the devices
+		 */
+		if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) &&
+		    (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) &&
+		    (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) {
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 3, VCHAN0, 4);
+		} else {
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+		}
+
+		break;
+	case MODULE_PEBRICK:
+	case MODULE_PBRICK:
+		do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+		do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8);
 		break;
-	case 'i':		/* Ibrick */
+	case MODULE_IBRICK:
 	  	/* port 0xe on the Ibrick only has slots 1 and 2 */
 		if (pcibr_soft->bs_xid == 0xe) {
-			do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-			do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8);
 		}
 		else {
 		    	/* allocate one RRB for the serial port */
-			do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1);
 		}
 		break;
 	} /* switch */
@@ -1890,33 +2103,80 @@
 
 #ifdef LATER
     if (strstr(nicinfo, XTALK_PCI_PART_NUM)) {
-	do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-#if PCIBR_RRB_DEBUG
-	printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl);
-
-	printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n",
-		pcibr_vhdl,
-		pcibr_soft->bs_rrb_avail[0],
-		pcibr_soft->bs_rrb_avail[1]);
-
-	for (slot = 0; slot < 8; ++slot)
-	    printf("\t%d+%d+%d",
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot],
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
-
-	printf("\n");
+	do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+    }
 #endif
+}  /* OK Special RRB allocations are done. */
+
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Call the device attach */
+	(void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0);
+
+#ifdef PIC_LATER
+#if (defined(USS302_TIMEOUT_WAR))
+    /*
+     * If this bridge holds a Lucent USS-302 or USS-312 pci/usb controller,
+     * increase the Bridge PCI retry backoff interval.  This part seems
+     * to go away for long periods of time if a DAC appears on the bus during
+     * a read command that is being retried.
+     */
+
+{
+    ii_ixtt_u_t ixtt;
+
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	if (pcibr_soft->bs_slot[slot].bss_vendor_id ==
+					LUCENT_USBHC_VENDOR_ID_NUM &&
+	    (pcibr_soft->bs_slot[slot].bss_device_id ==
+					LUCENT_USBHC302_DEVICE_ID_NUM ||
+	     pcibr_soft->bs_slot[slot].bss_device_id ==
+					LUCENT_USBHC312_DEVICE_ID_NUM)) {
+	    printk(KERN_NOTICE
+		    "pcibr_attach: %x Bus holds a usb part - setting"
+		    "bridge PCI_RETRY_HLD to %d\n",
+		    pcibr_vhdl, USS302_BRIDGE_TIMEOUT_HLD);
+
+	    bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_HLD_MASK;
+	    bridge->b_bus_timeout |=
+			BRIDGE_BUS_PCI_RETRY_HLD(USS302_BRIDGE_TIMEOUT_HLD);
+
+	    /*
+	     * Have to consider the read response timer in the hub II as well
+	     */
+
+	    hubii_ixtt_get(xconn_vhdl, &ixtt);
+
+	    /*
+	     * bump rrsp_ps to allow at least 1ms for read
+ 	     * responses from this widget
+	     */
+
+	    ixtt.ii_ixtt_fld_s.i_rrsp_ps = 20000;
+	    hubii_ixtt_set(xconn_vhdl, &ixtt);
+
+	    /*
+	     * print the current setting
+	     */
+
+	    hubii_ixtt_get(xconn_vhdl, &ixtt);
+	    printk( "Setting hub ixtt.rrsp_ps field to 0x%x\n",
+		    ixtt.ii_ixtt_fld_s.i_rrsp_ps);
+
+	    break;	/* only need to do it once */
+	}
     }
+}
+#endif	/* (defined(USS302_TIMEOUT_WAR)) */
 #else
 	FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n");
-#endif
+#endif	/* PIC_LATER */
 
     if (aa)
 	    async_attach_add_info(noslot_conn, aa);
 
-    pciio_device_attach(noslot_conn, 0);
-
+    pciio_device_attach(noslot_conn, (int)0);
 
     /* 
      * Tear down pointer to async attach info -- async threads for
@@ -1927,11 +2187,13 @@
 
     return 0;
 }
+
 /*
  * pcibr_detach:
  *	Detach the bridge device from the hwgraph after cleaning out all the 
  *	underlying vertices.
  */
+
 int
 pcibr_detach(devfs_handle_t xconn)
 {
@@ -1939,6 +2201,9 @@
     devfs_handle_t	pcibr_vhdl;
     pcibr_soft_t	pcibr_soft;
     bridge_t		*bridge;
+    unsigned             s;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n"));
 
     /* Get the bridge vertex from its xtalk connection point */
     if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS)
@@ -1947,16 +2212,20 @@
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge = pcibr_soft->bs_base;
 
+
+    s = pcibr_lock(pcibr_soft);
     /* Disable the interrupts from the bridge */
-    bridge->b_int_enable = 0;
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	bridge->p_int_enable_64 = 0;
+    } else {
+	bridge->b_int_enable = 0;
+    }
+    pcibr_unlock(pcibr_soft, s);
 
     /* Detach all the PCI devices talking to this bridge */
-    for(slot = 0; slot < 8; slot++) {
-#ifdef DEBUG
-	printk("pcibr_device_detach called for %p/%d\n",
-		pcibr_vhdl,slot);
-#endif
-	pcibr_slot_detach(pcibr_vhdl, slot, 0);
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	pcibr_slot_detach(pcibr_vhdl, slot, 0, (char *)NULL, (int *)NULL);
     }
 
     /* Unregister the no-slot connection point */
@@ -1998,17 +2267,29 @@
 int
 pcibr_asic_rev(devfs_handle_t pconn_vhdl)
 {
-    devfs_handle_t            pcibr_vhdl;
+    devfs_handle_t          pcibr_vhdl;
+    int                     tmp_vhdl;
     arbitrary_info_t        ainfo;
 
     if (GRAPH_SUCCESS !=
 	hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl))
 	return -1;
 
-    if (GRAPH_SUCCESS !=
-	hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo))
-	return -1;
+    tmp_vhdl = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo);
+
+    /*
+     * Any hwgraph function that returns a vertex handle will implicity
+     * increment that vertex's reference count.  The caller must explicity
+     * decrement the vertex's referece count after the last reference to
+     * that vertex.
+     *
+     * Decrement reference count incremented by call to hwgraph_traverse().
+     *
+     */
+    hwgraph_vertex_unref(pcibr_vhdl);
 
+    if (tmp_vhdl != GRAPH_SUCCESS) 
+	return -1;
     return (int) ainfo;
 }
 
@@ -2018,7 +2299,7 @@
     pciio_info_t  pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t  pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     pciio_slot_t  slot;
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_device_write_gather_flush(pcibr_soft, slot);
     return 0;
 }
@@ -2048,11 +2329,13 @@
     size_t                  wsize;	/* size of device decode on PCI */
 
     int                     try;	/* DevIO(x) window scanning order control */
+    int			    maxtry, halftry;
     int                     win;	/* which DevIO(x) window is being used */
     pciio_space_t           mspace;	/* target space for devio(x) register */
     iopaddr_t               mbase;	/* base of devio(x) mapped area on PCI */
     size_t                  msize;	/* size of devio(x) mapped area on PCI */
     size_t                  mmask;	/* addr bits stored in Device(x) */
+    char		    tmp_str[512];
 
     unsigned long           s;
 
@@ -2061,6 +2344,17 @@
     if (pcibr_soft->bs_slot[slot].has_host) {
 	slot = pcibr_soft->bs_slot[slot].host_slot;
 	pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0];
+
+	/*
+	 * Special case for dual-slot pci devices such as ioc3 on IP27
+	 * baseio.  In these cases, pconn_vhdl should never be for a pci
+	 * function on a subordiate PCI bus, so we can safely reset pciio_info
+	 * to be the info struct embedded in pcibr_info.  Failure to do this
+	 * results in using a bogus pciio_info_t for calculations done later
+	 * in this routine.
+	 */
+
+	pciio_info = &pcibr_info->f_c;
     }
     if (space == PCIIO_SPACE_NONE)
 	goto done;
@@ -2080,7 +2374,7 @@
 	 */
 	if (((flags & PCIIO_BYTE_STREAM) == 0) &&
 	    ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF))
-	    xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot);
+	    xio_addr = pci_addr + PCIBR_TYPE0_CFG_DEV(pcibr_soft, slot);
 
 	goto done;
     }
@@ -2090,8 +2384,8 @@
 	 * enabling and disabling
 	 * decodes properly.
 	 */
-	wbase = pcibr_info->f_rbase;
-	wsize = pcibr_info->f_rsize;
+	wbase = pciio_info->c_rbase;
+	wsize = pciio_info->c_rsize;
 
 	/*
 	 * While the driver should know better
@@ -2113,13 +2407,13 @@
      */
     bar = space - PCIIO_SPACE_WIN0;
     if (bar < 6) {
-	wspace = pcibr_info->f_window[bar].w_space;
+	wspace = pciio_info->c_window[bar].w_space;
 	if (wspace == PCIIO_SPACE_NONE)
 	    goto done;
 
 	/* get PCI base and size */
-	wbase = pcibr_info->f_window[bar].w_base;
-	wsize = pcibr_info->f_window[bar].w_size;
+	wbase = pciio_info->c_window[bar].w_base;
+	wsize = pciio_info->c_window[bar].w_size;
 
 	/*
 	 * While the driver should know better
@@ -2147,11 +2441,15 @@
      * We will not attempt to satisfy a single request
      * by concatinating multiple windows.
      */
-    for (try = 0; try < 16; ++try) {
+    maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2;
+    halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1;
+    for (try = 0; try < maxtry; ++try) {
 	bridgereg_t             devreg;
 	unsigned                offset;
 
-	win = (try + slot) % 8;
+	/* calculate win based on slot, attempt, and max possible
+	   devices on bus */
+	win = (try + slot) % PCIBR_NUM_SLOTS(pcibr_soft);
 
 	/* If this DevIO(x) mapping area can provide
 	 * a mapping to this address, use it.
@@ -2176,7 +2474,7 @@
 	 * (only check this the second time through)
 	 */
 	mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space;
-	if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) {
+	if ((try > halftry) && (mspace == PCIIO_SPACE_NONE)) {
 
 	    /* If this is the primary DevIO(x) window
 	     * for some other device, skip it.
@@ -2214,25 +2512,61 @@
 		devreg &= ~BRIDGE_DEV_DEV_SWAP;
 
 	    if (pcibr_soft->bs_slot[win].bss_device != devreg) {
-		bridge->b_device[win].reg = devreg;
-		pcibr_soft->bs_slot[win].bss_device = devreg;
-		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			bridge->b_device[win].reg = devreg;
+			pcibr_soft->bs_slot[win].bss_device = devreg;
+			bridge->b_wid_tflush;   /* wait until Bridge PIO complete */
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_SET32((&bridge->b_device[win].reg)) = __swab32(devreg);
+				pcibr_soft->bs_slot[win].bss_device = devreg;
+				BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */
+			} else {
+				bridge->b_device[win].reg = devreg;
+				pcibr_soft->bs_slot[win].bss_device = devreg;
+				bridge->b_wid_tflush;   /* wait until Bridge PIO complete */
+			}
+		}
 
-#if DEBUG && PCI_DEBUG
-		printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg);
+#ifdef PCI_LATER
+		PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, 
+			    "pcibr_addr_pci_to_xio: Device(%d): %x\n",
+			    win, devreg, device_bits));
+#else
+	        printk("pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg);
 #endif
 	    }
 	    pcibr_soft->bs_slot[win].bss_devio.bssd_space = space;
 	    pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase;
-	    xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase);
+	    xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase);
 
-#if DEBUG && PCI_DEBUG
-	    printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", 
-		    __FUNCTION__, __LINE__, space, space_desc,
-		    pci_addr, pci_addr + req_size - 1,
-		    slot, win, devreg);
-#endif
+            /* Increment this DevIO's use count */
+            pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++;
+
+            /* Save the DevIO register index used to access this BAR */
+            if (bar != -1)
+                pcibr_info->f_window[bar].w_devio_index = win;
 
+	    /*
+	     * The kernel only allows functions to have so many variable args,
+	     * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printk
+	     * arguments fails so sprintf() it into a temporary string.
+	     */
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for "
+		        "slot %d allocates DevIO(%d) Device(%d) set to %x\n",
+		        space, space_desc, pci_addr, pci_addr + req_size - 1,
+		        slot, win, win, devreg, device_bits);
+#else
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to [%lx..%lx] for "
+		        "slot %d allocates DevIO(%d) Device(%d) set to %lx\n",
+		        (unsigned long)pci_addr, (unsigned long)(pci_addr + req_size - 1),
+		        (unsigned int)slot, win, win, (unsigned long)devreg);
+#endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	    goto done;
 	}				/* endif DevIO(x) not pointed */
 	mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base;
@@ -2251,12 +2585,23 @@
 	 * final XIO address, release the lock and
 	 * return.
 	 */
-	xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase);
+	xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase);
+
+        /* Increment this DevIO's use count */
+        pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++;
 
-#if DEBUG && PCI_DEBUG
-	printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n",
-		__FUNCTION__, __LINE__, space,  pci_addr, pci_addr + req_size - 1, slot, win);
+        /* Save the DevIO register index used to access this BAR */
+        if (bar != -1)
+            pcibr_info->f_window[bar].w_devio_index = win;
+
+	if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	    sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for "
+		    "slot %d uses DevIO(%d)\n", space, space_desc, pci_addr,
+		    pci_addr + req_size - 1, slot, win);
 #endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	}
 	goto done;
     }
 
@@ -2322,33 +2667,55 @@
 	if (bfn == bfo) {		/* we already match. */
 	    ;
 	} else if (bfo != 0) {		/* we have a conflict. */
-#if DEBUG && PCI_DEBUG
-	    printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n",
-		    space, 
-		    bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "",
-		    bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap conflict in %x, "
+		        "was%s%s, want%s%s\n", space, space_desc,
+		        bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "",
+		        bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
 #endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	    xio_addr = XIO_NOWHERE;
 	} else {			/* OK to make the change. */
-	    bridgereg_t             octl, nctl;
-
 	    swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP;
-	    octl = bridge->b_wid_control;
-	    nctl = bst ? octl | swb : octl & ~swb;
+	    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	    	picreg_t             octl, nctl;
+		octl = bridge->p_wid_control_64;
+		nctl = bst ? octl | (uint64_t)swb : octl & ((uint64_t)~swb);
 
-	    if (octl != nctl)		/* make the change if any */
-		bridge->b_wid_control = nctl;
+		if (octl != nctl)		/* make the change if any */
+			bridge->b_wid_control = nctl;
+	    }
+	    else {
+	    	picreg_t             octl, nctl;
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			octl = BRIDGE_REG_GET32((&bridge->b_wid_control));
+			nctl = bst ? octl | swb : octl & ~swb;
+
+			if (octl != nctl)           /* make the change if any */
+				BRIDGE_REG_SET32((&bridge->b_wid_control)) = __swab32(nctl);
+		} else {
+			octl = bridge->b_wid_control;
+			nctl = bst ? octl | swb : octl & ~swb;
 
+			if (octl != nctl)           /* make the change if any */
+				bridge->b_wid_control = nctl;
+		}
+	    }
 	    *bfp = bfn;			/* record the assignment */
 
-#if DEBUG && PCI_DEBUG
-	    printk("pcibr_addr_pci_to_xio: swap for space %d  set to%s%s\n",
-		    space, 
-		    bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap for %x set "
+			"to%s%s\n", space, space_desc,
+		        bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
 #endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	}
     }
   done:
@@ -2368,7 +2735,7 @@
 {
     pcibr_info_t	    pcibr_info = pcibr_info_get(pconn_vhdl);
     pciio_info_t            pciio_info = &pcibr_info->f_c;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
 
@@ -2380,8 +2747,11 @@
     unsigned long           s;
 
     /* Make sure that the req sizes are non-zero */
-    if ((req_size < 1) || (req_size_max < 1))
+    if ((req_size < 1) || (req_size_max < 1)) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piomap_alloc: req_size | req_size_max < 1\n"));
 	return NULL;
+    }
 
     /*
      * Code to translate slot/space/addr
@@ -2390,8 +2760,11 @@
      */
     xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags);
 
-    if (xio_addr == XIO_NOWHERE)
+    if (xio_addr == XIO_NOWHERE) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piomap_alloc: xio_addr == XIO_NOWHERE\n"));
 	return NULL;
+    }
 
     /* Check the piomap list to see if there is already an allocated
      * piomap entry but not in use. If so use that one. Otherwise
@@ -2415,7 +2788,7 @@
     }
 
     pcibr_piomap->bp_dev = pconn_vhdl;
-    pcibr_piomap->bp_slot = pciio_slot;
+    pcibr_piomap->bp_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, pciio_slot);
     pcibr_piomap->bp_flags = flags;
     pcibr_piomap->bp_space = space;
     pcibr_piomap->bp_pciaddr = pci_addr;
@@ -2446,6 +2819,10 @@
 	    pcibr_piomap = 0;
 	}
     }
+    
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piomap_alloc: map=0x%x\n", pcibr_piomap));
+
     return pcibr_piomap;
 }
 
@@ -2453,6 +2830,9 @@
 void
 pcibr_piomap_free(pcibr_piomap_t pcibr_piomap)
 {
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+		"pcibr_piomap_free: map=0x%x\n", pcibr_piomap));
+
     xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio);
     pcibr_piomap->bp_xtalk_pio = 0;
     pcibr_piomap->bp_mapsz = 0;
@@ -2464,16 +2844,24 @@
 		  iopaddr_t pci_addr,
 		  size_t req_size)
 {
-    return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio,
+    caddr_t	addr;
+    addr = xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio,
 			     pcibr_piomap->bp_xtalk_addr +
 			     pci_addr - pcibr_piomap->bp_pciaddr,
 			     req_size);
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+                "pcibr_piomap_free: map=0x%x, addr=0x%x\n", 
+		pcibr_piomap, addr));
+
+    return(addr);
 }
 
 /*ARGSUSED */
 void
 pcibr_piomap_done(pcibr_piomap_t pcibr_piomap)
 {
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+		"pcibr_piomap_done: map=0x%x\n", pcibr_piomap));
     xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio);
 }
 
@@ -2487,26 +2875,34 @@
 		    unsigned flags)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
 
     iopaddr_t               xio_addr;
+    caddr_t		    addr;
 
     xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags);
 
-    if (xio_addr == XIO_NOWHERE)
+    if (xio_addr == XIO_NOWHERE) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIODIR, pconn_vhdl,
+		    "pcibr_piotrans_addr: xio_addr == XIO_NOWHERE\n"));
 	return NULL;
+    }
 
-    return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS);
+    addr = xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS);
+    PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl,
+		"pcibr_piotrans_addr: xio_addr=0x%x, addr=0x%x\n",
+		xio_addr, addr));
+    return(addr);
 }
 
 /*
  * PIO Space allocation and management.
  *      Allocate and Manage the PCI PIO space (mem and io space)
  *      This routine is pretty simplistic at this time, and
- *      does pretty trivial management of allocation and freeing..
- *      The current scheme is prone for fragmentation..
+ *      does pretty trivial management of allocation and freeing.
+ *      The current scheme is prone for fragmentation.
  *      Change the scheme to use bitmaps.
  */
 
@@ -2525,7 +2921,6 @@
     pciio_piospace_t        piosp;
     unsigned long           s;
 
-    iopaddr_t              *pciaddr, *pcilast;
     iopaddr_t               start_addr;
     size_t                  align_mask;
 
@@ -2559,38 +2954,43 @@
     }
     ASSERT(!piosp);
 
+    /*
+     * Allocate PCI bus address, usually for the Universe chip driver;
+     * do not pass window info since the actual PCI bus address
+     * space will never be freed.  The space may be reused after it
+     * is logically released by pcibr_piospace_free().
+     */
     switch (space) {
     case PCIIO_SPACE_IO:
-	pciaddr = &pcibr_soft->bs_spinfo.pci_io_base;
-	pcilast = &pcibr_soft->bs_spinfo.pci_io_last;
+        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,
+                                          PCIIO_SPACE_IO,
+                                          0, req_size, alignment);
 	break;
+
     case PCIIO_SPACE_MEM:
     case PCIIO_SPACE_MEM32:
-	pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base;
-	pcilast = &pcibr_soft->bs_spinfo.pci_mem_last;
+        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,
+                                          PCIIO_SPACE_MEM32,
+                                          0, req_size, alignment);
 	break;
+
     default:
 	ASSERT(0);
 	pcibr_unlock(pcibr_soft, s);
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piospace_alloc: unknown space %d\n", space));
 	return 0;
     }
 
-    start_addr = *pciaddr;
-
     /*
-     * Align start_addr.
+     * If too big a request, reject it.
      */
-    if (start_addr & align_mask)
-	start_addr = (start_addr + align_mask) & ~align_mask;
-
-    if ((start_addr + req_size) > *pcilast) {
-	/*
-	 * If too big a request, reject it.
-	 */
+    if (!start_addr) {
 	pcibr_unlock(pcibr_soft, s);
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piospace_alloc: request 0x%x to big\n", req_size));
 	return 0;
     }
-    *pciaddr = (start_addr + req_size);
 
     NEW(piosp);
     piosp->free = 0;
@@ -2601,6 +3001,10 @@
     pcibr_info->f_piospace = piosp;
 
     pcibr_unlock(pcibr_soft, s);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piospace_alloc: piosp=0x%x\n", piosp));
+
     return start_addr;
 }
 
@@ -2612,7 +3016,9 @@
 		    size_t req_size)
 {
     pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);
+#ifdef PIC_LATER
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
+#endif
 
     pciio_piospace_t        piosp;
     unsigned long           s;
@@ -2655,6 +3061,9 @@
     }
     piosp->free = 1;
     pcibr_unlock(pcibr_soft, s);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piospace_free: piosp=0x%x\n", piosp));
     return;
 }
 
@@ -2713,7 +3122,7 @@
 	attributes &= ~PCI64_ATTR_PREF;
 
     /* the swap bit is in the address attributes for xbridge */
-    if (pcibr_soft->bs_xbridge) {
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
     	if (flags & PCIIO_BYTE_STREAM)
         	attributes |= PCI64_ATTR_SWAP;
     	if (flags & PCIIO_WORD_VALUES)
@@ -2742,6 +3151,11 @@
     if (flags & PCIBR_VCHAN0)
 	attributes &= ~PCI64_ATTR_VIRTUAL;
 
+    /* PIC in PCI-X mode only supports barrier & swap */
+    if (IS_PCIX(pcibr_soft)) {
+	attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP);
+    }
+
     return (attributes);
 }
 
@@ -2762,6 +3176,7 @@
     pcibr_dmamap_t          pcibr_dmamap;
     int                     ate_count;
     int                     ate_index;
+    int			    vchan = VCHAN0;
 
     /* merge in forced flags */
     flags |= pcibr_soft->bs_dma_flags;
@@ -2778,17 +3193,16 @@
     xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max,
 				      flags & DMAMAP_FLAGS);
     if (!xtalk_dmamap) {
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_attach: xtalk_dmamap_alloc failed\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		    "pcibr_dmamap_alloc: xtalk_dmamap_alloc failed\n"));
 	free_pciio_dmamap(pcibr_dmamap);
 	return 0;
     }
     xio_port = pcibr_soft->bs_mxid;
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_dmamap->bd_dev = pconn_vhdl;
-    pcibr_dmamap->bd_slot = slot;
+    pcibr_dmamap->bd_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot);
     pcibr_dmamap->bd_soft = pcibr_soft;
     pcibr_dmamap->bd_xtalk = xtalk_dmamap;
     pcibr_dmamap->bd_max_size = req_size_max;
@@ -2812,29 +3226,37 @@
 	    pcibr_dmamap->bd_xio_addr = 0;
 	    pcibr_dmamap->bd_pci_addr = pci_addr;
 
-	    /* Make sure we have an RRB (or two).
+	    /* If in PCI mode, make sure we have an RRB (or two). 
 	     */
-	    if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
+	    if (IS_PCI(pcibr_soft) && 
+		!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
 		if (flags & PCIBR_VCHAN1)
-		    slot += PCIBR_RRB_SLOT_VIRTUAL;
-		have_rrbs = pcibr_soft->bs_rrb_valid[slot];
+		    vchan = VCHAN1;
+		have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan];
 		if (have_rrbs < 2) {
 		    if (pci_addr & PCI64_ATTR_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using direct64\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		 	"pcibr_dmamap_alloc: using direct64, map=0x%x\n",
+			pcibr_dmamap));
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use direct64\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmamap_alloc: unable to use direct64\n"));
+
+	/* PIC only supports 64-bit direct mapping in PCI-X mode. */
+	if (IS_PCIX(pcibr_soft)) {
+	    DEL(pcibr_dmamap);
+	    return 0;
+	}
+
 	flags &= ~PCIIO_DMA_A64;
     }
     if (flags & PCIIO_FIXED) {
@@ -2849,17 +3271,17 @@
 	     * Mapping calls may fail if target
 	     * is outside the direct32 range.
 	     */
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using direct32\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmamap_alloc: using direct32, map=0x%x\n", 
+			pcibr_dmamap));
 	    pcibr_dmamap->bd_flags = flags;
 	    pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase;
 	    pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE;
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use direct32\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmamap_alloc: unable to use direct32\n"));
+
 	/* If the user demands FIXED and we can't
 	 * give it to him, fail.
 	 */
@@ -2892,9 +3314,9 @@
 	    int                     have_rrbs;
 	    int                     min_rrbs;
 
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using PMU\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+			"pcibr_dmamap_alloc: using PMU, ate_index=%d, "
+			"pcibr_dmamap=0x%x\n", ate_index, pcibr_dmamap));
 
 	    ate_proto = pcibr_flags_to_ate(flags);
 
@@ -2904,7 +3326,7 @@
 	    /*
 	     * for xbridge the byte-swap bit == bit 29 of PCI address
 	     */
-	    if (pcibr_soft->bs_xbridge) {
+	    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		    if (flags & PCIIO_BYTE_STREAM)
 			    ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr);
 		    /*
@@ -2926,18 +3348,19 @@
 	    /* Make sure we have an RRB (or two).
 	     */
 	    if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
-		have_rrbs = pcibr_soft->bs_rrb_valid[slot];
+		have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan];
 		if (have_rrbs < 2) {
 		    if (ate_proto & ATE_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
 	    if (ate_index >= pcibr_soft->bs_int_ate_size && 
-				!pcibr_soft->bs_xbridge) {
+				!IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		bridge_t               *bridge = pcibr_soft->bs_base;
 		volatile unsigned      *cmd_regp;
 		unsigned                cmd_reg;
@@ -2946,27 +3369,35 @@
 		pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM;
 
 		s = pcibr_lock(pcibr_soft);
-		cmd_regp = &(bridge->
-			     b_type0_cfg_dev[slot].
-			     l[PCI_CFG_COMMAND / 4]);
-		cmd_reg = *cmd_regp;
+		cmd_regp = pcibr_slot_config_addr(bridge, slot, 
+						PCI_CFG_COMMAND/4);
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4);
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_SET32((&cmd_reg)) = __swab32(*cmd_regp);
+			} else {
+				cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4);
+			}
+		}
 		pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp;
 		pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg;
 		pcibr_unlock(pcibr_soft, s);
 	    }
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use PMU\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		    "pcibr_dmamap_alloc: PMU use failed, ate_index=%d\n",
+		    ate_index));
+
 	pcibr_ate_free(pcibr_soft, ate_index, ate_count);
     }
     /* total failure: sorry, you just can't
      * get from here to there that way.
      */
-#if PCIBR_ATE_DEBUG
-    printk("pcibr_dmamap_alloc: complete failure.\n");
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		"pcibr_dmamap_alloc: complete failure.\n"));
     xtalk_dmamap_free(xtalk_dmamap);
     free_pciio_dmamap(pcibr_dmamap);
     return 0;
@@ -2977,7 +3408,8 @@
 pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap)
 {
     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
-    pciio_slot_t            slot = pcibr_dmamap->bd_slot;
+    pciio_slot_t            slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft,
+							pcibr_dmamap->bd_slot);
 
     unsigned                flags = pcibr_dmamap->bd_flags;
 
@@ -3001,6 +3433,9 @@
 	pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS);
     }
 
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_free: pcibr_dmamap=0x%x\n", pcibr_dmamap));
+
     free_pciio_dmamap(pcibr_dmamap);
 }
 
@@ -3029,15 +3464,15 @@
 	pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE;
 	return pci_addr;
     }
-    for (slot = 0; slot < 8; ++slot)
-	if ((xio_addr >= BRIDGE_DEVIO(slot)) &&
-	    (xio_lim < BRIDGE_DEVIO(slot + 1))) {
+    for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot)
+	if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) &&
+	    (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) {
 	    bridgereg_t             dev;
 
 	    dev = soft->bs_slot[slot].bss_device;
 	    pci_addr = dev & BRIDGE_DEV_OFF_MASK;
 	    pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT;
-	    pci_addr += xio_addr - BRIDGE_DEVIO(slot);
+	    pci_addr += xio_addr - PCIBR_BRIDGE_DEVIO(soft, slot);
 	    return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE;
 	}
     return 0;
@@ -3070,7 +3505,7 @@
     } else
 	xio_port = pcibr_dmamap->bd_xio_port;
 
-    /* If this DMA is to an address that
+    /* If this DMA is to an addres that
      * refers back to this Bridge chip,
      * reduce it back to the correct
      * PCI MEM address.
@@ -3099,14 +3534,12 @@
 	if (flags & PCIBR_NOPREFETCH)
 	    pci_addr &= ~PCI64_ATTR_PREF;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-	printk("pcibr_dmamap_addr (direct64):\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\tXIO port 0x%x offset 0x%x\n"
-		"\treturning PCI 0x%x\n",
-		paddr, paddr + req_size - 1,
-		xio_port, xio_addr, pci_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, 
+		    pcibr_dmamap->bd_dev,
+		    "pcibr_dmamap_addr: (direct64): wanted paddr [0x%x..0x%x] "
+		    "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr));
+
     } else if (flags & PCIIO_FIXED) {
 	/* A32 direct DMA:
 	 * always use 32-bit direct mapping,
@@ -3126,14 +3559,12 @@
 	    pci_addr = pcibr_dmamap->bd_pci_addr +
 		xio_addr - pcibr_dmamap->bd_xio_addr;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-	printk("pcibr_dmamap_addr (direct32):\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\tXIO port 0x%x offset 0x%x\n"
-		"\treturning PCI 0x%x\n",
-		paddr, paddr + req_size - 1,
-		xio_port, xio_addr, pci_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, 
+		    pcibr_dmamap->bd_dev,
+		    "pcibr_dmamap_addr (direct32): wanted paddr [0x%x..0x%x] "
+		    "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr));
+
     } else {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 	iopaddr_t               offset = IOPGOFF(xio_addr);
@@ -3148,14 +3579,6 @@
 	int                     ate_total = ate_count;
 	unsigned                freeze_time;
 #endif
-
-#if PCIBR_ATE_DEBUG
-	bridge_ate_t            ate_cmp;
-	bridge_ate_p            ate_cptr;
-	unsigned                ate_lo, ate_hi;
-	int                     ate_bad = 0;
-	int                     ate_rbc = 0;
-#endif
 	bridge_ate_p            ate_ptr = pcibr_dmamap->bd_ate_ptr;
 	bridge_ate_t            ate;
 
@@ -3183,7 +3606,21 @@
 		ATE_FREEZE();
 		ATE_WRITE();
 		ATE_THAW();
-		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+			} else {
+				bridge->b_wid_tflush;
+			}
+		}
+		PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+			    "pcibr_dmamap_addr (PMU) : wanted paddr "
+			    "[0x%x..0x%x] returning PCI 0x%x\n", 
+			    paddr, paddr + req_size - 1, pci_addr));
+
 	} else {
 		/* The number of ATE's required is greater than the number
 		 * allocated for this map. One way this can happen is if
@@ -3193,14 +3630,12 @@
 		 * The other possibility is that the map is just plain too
 		 * small to handle the requested target area.
 		 */
-#if PCIBR_ATE_DEBUG
-		printk(KERN_WARNING "pcibr_dmamap_addr :\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\tate_count 0x%x bd_ate_count 0x%x\n"
-			"\tATE's required > number allocated\n",
-			paddr, paddr + req_size - 1,
-			ate_count, pcibr_dmamap->bd_ate_count);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, 
+		            "pcibr_dmamap_addr (PMU) : wanted paddr "
+			    "[0x%x..0x%x] ate_count 0x%x bd_ate_count 0x%x "
+			    "ATE's required > number allocated\n",
+			     paddr, paddr + req_size - 1,
+			     ate_count, pcibr_dmamap->bd_ate_count));
 		pci_addr = 0;
 	}
 
@@ -3250,17 +3685,24 @@
 
     xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist,
 				       flags & DMAMAP_FLAGS);
-    if (!xtalk_alenlist)
+    if (!xtalk_alenlist) {
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                    "pcibr_dmamap_list: xtalk_dmamap_list() failed, "
+		    "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 	goto fail;
-
+    }
     alenlist_cursor_init(xtalk_alenlist, 0, NULL);
 
     if (inplace) {
 	pciio_alenlist = xtalk_alenlist;
     } else {
 	pciio_alenlist = alenlist_create(al_flags);
-	if (!pciio_alenlist)
+	if (!pciio_alenlist) {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+			"pcibr_dmamap_list: alenlist_create() failed, "
+			"pcibr_dmamap=0x%lx\n", (unsigned long)pcibr_dmamap));
 	    goto fail;
+	}
     }
 
     direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64;
@@ -3286,8 +3728,12 @@
 
 	if (xio_port == pcibr_soft->bs_xid) {
 	    new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length);
-	    if (new_addr == PCI_NOWHERE)
+	    if (new_addr == PCI_NOWHERE) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: pcibr_addr_xio_to_pci failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 		goto fail;
+	    }
 	} else if (direct64) {
 	    new_addr = pci_addr | xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
@@ -3318,9 +3764,8 @@
 		| (xio_port << ATE_TIDSHIFT)
 		| (xio_addr - offset);
 	    if (ate == ate_prev) {
-#if PCIBR_ATE_DEBUG
-		printk("pcibr_dmamap_list: ATE share\n");
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev,
+			    "pcibr_dmamap_list: ATE share\n"));
 		ate_ptr--;
 		ate_index--;
 		pci_addr -= IOPGSIZE;
@@ -3335,14 +3780,13 @@
 
 	    /* Ensure that this map contains enough ATE's */
 	    if (ate_total > pcibr_dmamap->bd_ate_count) {
-#if PCIBR_ATE_DEBUG
-		printk(KERN_WARNING "pcibr_dmamap_list :\n"
-			"\twanted xio_addr [0x%x..0x%x]\n"
-			"\tate_total 0x%x bd_ate_count 0x%x\n"
-			"\tATE's required > number allocated\n",
-			xio_addr, xio_addr + length - 1,
-			ate_total, pcibr_dmamap->bd_ate_count);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev,
+			     "pcibr_dmamap_list :\n"
+			     "\twanted xio_addr [0x%x..0x%x]\n"
+			     "\tate_total 0x%x bd_ate_count 0x%x\n"
+			     "\tATE's required > number allocated\n",
+			     xio_addr, xio_addr + length - 1,
+			     ate_total, pcibr_dmamap->bd_ate_count));
 		goto fail;
 	    }
 
@@ -3362,13 +3806,22 @@
 	if (inplace) {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_replace(pciio_alenlist, NULL,
-				 &new_addr, &length, al_flags))
+				 &new_addr, &length, al_flags)) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: alenlist_replace() failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
+
 		goto fail;
+	    }
 	} else {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_append(pciio_alenlist,
-				new_addr, length, al_flags))
+				new_addr, length, al_flags)) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: alenlist_append() failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 		goto fail;
+	    }
 	}
     }
     if (!inplace)
@@ -3386,8 +3839,21 @@
      */
     if (ate_freeze_done) {
 	ATE_THAW();
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+		} else {
+			bridge->b_wid_tflush;
+		}
+	}
     }
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_list: pcibr_dmamap=0x%x, pciio_alenlist=0x%x\n",
+		pcibr_dmamap, pciio_alenlist));
+
     return pciio_alenlist;
 
   fail:
@@ -3398,7 +3864,16 @@
      */
     if (ate_freeze_done) {
 	ATE_THAW();
-	bridge->b_wid_tflush;
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_wid_tflush;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+		} else {
+			bridge->b_wid_tflush;
+		}
+	}
     }
     if (pciio_alenlist && !inplace)
 	alenlist_destroy(pciio_alenlist);
@@ -3409,6 +3884,10 @@
 void
 pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap)
 {
+#ifdef PIC_LATER
+    pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
+    pciio_slot_t            slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft,
+#endif
     /*
      * We could go through and invalidate ATEs here;
      * for performance reasons, we don't.
@@ -3423,6 +3902,9 @@
 	    atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active));
     }
     xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_done: pcibr_dmamap=0x%x\n", pcibr_dmamap));
 }
 
 
@@ -3455,7 +3937,7 @@
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_slot_t       slotp = &pcibr_soft->bs_slot[pciio_slot];
 
     xwidgetnum_t            xio_port;
@@ -3464,6 +3946,7 @@
 
     int                     have_rrbs;
     int                     min_rrbs;
+    int			    vchan = VCHAN0;
 
     /* merge in forced flags */
     flags |= pcibr_soft->bs_dma_flags;
@@ -3471,16 +3954,10 @@
     xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size,
 				   flags & DMAMAP_FLAGS);
     if (!xio_addr) {
-#if PCIBR_DMA_DEBUG
-	printk("pcibr_dmatrans_addr:\n"
-		"\tpciio connection point %v\n"
-		"\txtalk connection point %v\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\txtalk_dmatrans_addr returned 0x%x\n",
-		pconn_vhdl, xconn_vhdl,
-		paddr, paddr + req_size - 1,
-		xio_addr);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], "
+		    "xtalk_dmatrans_addr failed with 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_addr));
 	return 0;
     }
     /*
@@ -3488,16 +3965,10 @@
      */
     if (XIO_PACKED(xio_addr)) {
 	if (xio_addr == XIO_NOWHERE) {
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		        "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], "
+		        "xtalk_dmatrans_addr failed with XIO_NOWHERE\n",
+		        paddr, paddr + req_size - 1));
 	    return 0;
 	}
 	xio_port = XIO_PORT(xio_addr);
@@ -3515,6 +3986,10 @@
      */
     if (xio_port == pcibr_soft->bs_xid) {
 	pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size);
+        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		    "xio_port=0x%x, pci_addr=0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, pci_addr));
 	return pci_addr;
     }
     /* If the caller can use A64, try to
@@ -3531,92 +4006,65 @@
 	if ((pci_addr != PCIBR_D64_BASE_UNSET) &&
 	    (flags == slotp->bss_d64_flags)) {
 
-#ifdef CONFIG_IA64_SGI_SN2
-	    pci_addr |= (PHYS_TO_DMA(xio_addr))
-		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#else
 	    pci_addr |=  xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#endif
 
-#if DEBUG && PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 	    if (xio_addr != 0x20000000)
 #endif
-		printk("pcibr_dmatrans_addr: [reuse]\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tdirect 64bit address is 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, pci_addr);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			    "xio_port=0x%x, direct64: pci_addr=0x%x\n",
+			    paddr, paddr + req_size - 1, xio_addr, pci_addr));
 	    return (pci_addr);
 	}
 	if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) {
 	    pci_addr = pcibr_flags_to_d64(flags, pcibr_soft);
 	    slotp->bss_d64_flags = flags;
 	    slotp->bss_d64_base = pci_addr;
-#ifdef CONFIG_IA64_SGI_SN2
-	    pci_addr |= (PHYS_TO_DMA(xio_addr))
-		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#else
             pci_addr |= xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#endif
 
-	    /* Make sure we have an RRB (or two).
+	    /* If in PCI mode, make sure we have an RRB (or two).
 	     */
-	    if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
+	    if (IS_PCI(pcibr_soft) && 
+		!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
 		if (flags & PCIBR_VCHAN1)
-		    pciio_slot += PCIBR_RRB_SLOT_VIRTUAL;
-		have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot];
+		    vchan = VCHAN1;
+		have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
 		if (have_rrbs < 2) {
 		    if (pci_addr & PCI64_ATTR_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
-#if PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 	    if (xio_addr != 0x20000000)
 #endif
-		printk("pcibr_dmatrans_addr:\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tdirect 64bit address is 0x%x\n"
-			"\tnew flags: 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, pci_addr, (uint64_t) flags);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			    "xio_port=0x%x, direct64: pci_addr=0x%x, "
+			    "new flags: 0x%x\n", paddr, paddr + req_size - 1,
+			    xio_addr, pci_addr, (uint64_t) flags));
 	    return (pci_addr);
 	}
-	/* our flags conflict with Device(x).
-	 */
-	flags = flags
-	    & ~PCIIO_DMA_A64
-	    & ~PCIBR_VCHAN0
-	    ;
 
-#if PCIBR_DMA_DEBUG
-	printk("pcibr_dmatrans_addr:\n"
-		"\tpciio connection point %v\n"
-		"\txtalk connection point %v\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\txtalk_dmatrans_addr returned 0x%x\n"
-		"\tUnable to set Device(x) bits for Direct-64\n",
-		pconn_vhdl, xconn_vhdl,
-		paddr, paddr + req_size - 1,
-		xio_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		    "xio_port=0x%x, Unable to set direct64 Device(x) bits\n",
+		    paddr, paddr + req_size - 1, xio_addr));
+
+	/* PIC only supports 64-bit direct mapping in PCI-X mode */
+	if (IS_PCIX(pcibr_soft)) {
+	    return 0;
+	}
+
+	/* our flags conflict with Device(x). try direct32*/
+	flags = flags & ~(PCIIO_DMA_A64 | PCIBR_VCHAN0);
     }
     /* Try to satisfy the request with the 32-bit direct
      * map. This can fail if the configuration bits in
@@ -3633,17 +4081,11 @@
 	    (xio_addr < xio_base) ||
 	    (xio_port != pcibr_soft->bs_dir_xport) ||
 	    (endoff > map_size)) {
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n"
-		    "\txio region outside direct32 target\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			"xio_port=0x%x, xio region outside direct32 target\n",
+			paddr, paddr + req_size - 1, xio_addr));
 	} else {
 	    pci_addr = slotp->bss_d32_base;
 	    if ((pci_addr != PCIBR_D32_BASE_UNSET) &&
@@ -3651,18 +4093,11 @@
 
 		pci_addr |= offset;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-		printk("pcibr_dmatrans_addr: [reuse]\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tmapped via direct32 offset 0x%x\n"
-			"\twill DMA via pci addr 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, offset, pci_addr);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                            "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                            "xio_port=0x%x, direct32: pci_addr=0x%x\n",
+                            paddr, paddr + req_size - 1, xio_addr, pci_addr));
+
 		return (pci_addr);
 	    }
 	    if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) {
@@ -3675,61 +4110,41 @@
 		/* Make sure we have an RRB (or two).
 		 */
 		if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
-		    have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot];
+		    have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
 		    if (have_rrbs < 2) {
 			if (slotp->bss_device & BRIDGE_DEV_PREF)
 			    min_rrbs = 2;
 			else
 			    min_rrbs = 1;
 			if (have_rrbs < min_rrbs)
-			    do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs);
+			    do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, 
+						   vchan, min_rrbs - have_rrbs);
 		    }
 		}
-#if PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 		if (xio_addr != 0x20000000)
 #endif
-		    printk("pcibr_dmatrans_addr:\n"
-			    "\tpciio connection point %v\n"
-			    "\txtalk connection point %v\n"
-			    "\twanted paddr [0x%x..0x%x]\n"
-			    "\txtalk_dmatrans_addr returned 0x%x\n"
-			    "\tmapped via direct32 offset 0x%x\n"
-			    "\twill DMA via pci addr 0x%x\n"
-			    "\tnew flags: 0x%x\n",
-			    pconn_vhdl, xconn_vhdl,
-			    paddr, paddr + req_size - 1,
-			    xio_addr, offset, pci_addr, (uint64_t) flags);
-#endif
+                    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                            "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                            "xio_port=0x%x, direct32: pci_addr=0x%x, "
+			    "new flags: 0x%x\n", paddr, paddr + req_size - 1,
+			    xio_addr, pci_addr, (uint64_t) flags));
+
 		return (pci_addr);
 	    }
 	    /* our flags conflict with Device(x).
 	     */
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n"
-		    "\tUnable to set Device(x) bits for Direct-32\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                    "xio_port=0x%x, Unable to set direct32 Device(x) bits\n",
+                    paddr, paddr + req_size - 1, xio_port));
 	}
     }
 
-#if PCIBR_DMA_DEBUG
-    printk("pcibr_dmatrans_addr:\n"
-	    "\tpciio connection point %v\n"
-	    "\txtalk connection point %v\n"
-	    "\twanted paddr [0x%x..0x%x]\n"
-	    "\txtalk_dmatrans_addr returned 0x%x\n"
-	    "\tno acceptable PCI address found or constructable\n",
-	    pconn_vhdl, xconn_vhdl,
-	    paddr, paddr + req_size - 1,
-	    xio_addr);
-#endif
+    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		"pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		"xio_port=0x%x, No acceptable PCI address found\n",
+		paddr, paddr + req_size - 1, xio_port));
 
     return 0;
 }
@@ -3744,7 +4159,7 @@
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_slot_t       slotp = &pcibr_soft->bs_slot[pciio_slot];
     xwidgetnum_t            xio_port;
 
@@ -3781,6 +4196,9 @@
 	    /* reuse previous base info */
 	} else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) {
 	    /* DMA configuration conflict */
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: DMA configuration conflict "
+			"for direct64, flags=0x%x\n", flags));
 	    goto fail;
 	} else {
 	    relbits = BRIDGE_DEV_D64_BITS;
@@ -3796,6 +4214,9 @@
 	    /* reuse previous base info */
 	} else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) {
 	    /* DMA configuration conflict */
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: DMA configuration conflict "
+			"for direct32, flags=0x%x\n", flags));
 	    goto fail;
 	} else {
 	    relbits = BRIDGE_DEV_D32_BITS;
@@ -3805,8 +4226,12 @@
 
     xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist,
 					 flags & DMAMAP_FLAGS);
-    if (!xtalk_alenlist)
+    if (!xtalk_alenlist) {
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: xtalk_dmatrans_list failed "
+			"xtalk_alenlist=0x%x\n", xtalk_alenlist));
 	goto fail;
+    }
 
     alenlist_cursor_init(xtalk_alenlist, 0, NULL);
 
@@ -3814,8 +4239,12 @@
 	pciio_alenlist = xtalk_alenlist;
     } else {
 	pciio_alenlist = alenlist_create(al_flags);
-	if (!pciio_alenlist)
+	if (!pciio_alenlist) {
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: alenlist_create failed with "
+			" 0x%x\n", pciio_alenlist));
 	    goto fail;
+	}
     }
 
     while (ALENLIST_SUCCESS ==
@@ -3827,16 +4256,8 @@
 	 */
 	if (XIO_PACKED(xio_addr)) {
 	    if (xio_addr == XIO_NOWHERE) {
-#if PCIBR_DMA_DEBUG
-		printk("pcibr_dmatrans_addr:\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr);
-#endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: xio_addr == XIO_NOWHERE\n"));
 		return 0;
 	    }
 	    xio_port = XIO_PORT(xio_addr);
@@ -3853,8 +4274,12 @@
 	 */
 	if (xio_port == pcibr_soft->bs_xid) {
 	    pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size);
-	    if ( (pci_addr == (alenaddr_t)NULL) )
+	    if (pci_addr == (alenaddr_t)NULL) {
+	        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: pcibr_addr_xio_to_pci failed "
+			"xio_addr=0x%x, xio_size=0x%x\n", xio_addr, xio_size));
 		goto fail;
+	    }
 	} else if (direct64) {
 	    ASSERT(xio_port != 0);
 	    pci_addr = pci_base | xio_addr
@@ -3866,8 +4291,14 @@
 	    if ((xio_size > map_size) ||
 		(xio_addr < xio_base) ||
 		(xio_port != pcibr_soft->bs_dir_xport) ||
-		(endoff > map_size))
+		(endoff > map_size)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: xio_size > map_size fail\n"
+			    "xio_addr=0x%x, xio_size=0x%x. map_size=0x%x, "
+			    "xio_port=0x%x, endoff=0x%x\n", 
+			    xio_addr, xio_size, map_size, xio_port, endoff));
 		goto fail;
+	    }
 
 	    pci_addr = pci_base + (xio_addr - xio_base);
 	}
@@ -3878,13 +4309,19 @@
 	if (inplace) {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_replace(pciio_alenlist, NULL,
-				 &pci_addr, &xio_size, al_flags))
+				 &pci_addr, &xio_size, al_flags)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: alenlist_replace failed\n"));
 		goto fail;
+	    }
 	} else {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_append(pciio_alenlist,
-				pci_addr, xio_size, al_flags))
+				pci_addr, xio_size, al_flags)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: alenlist_append failed\n"));
 		goto fail;
+	    }
 	}
     }
 
@@ -3904,6 +4341,11 @@
      * to the caller.
      */
     alenlist_cursor_init(pciio_alenlist, 0, NULL);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		"pcibr_dmatrans_list: pciio_alenlist=0x%x\n",
+		 pciio_alenlist));
+
     return pciio_alenlist;
 
   fail:
@@ -3973,8 +4415,9 @@
 int
 pcibr_reset(devfs_handle_t conn)
 {
+#ifdef PIC_LATER
     pciio_info_t            pciio_info = pciio_info_get(conn);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     bridgereg_t             ctlreg;
@@ -3984,42 +4427,59 @@
     pcibr_info_h            pcibr_infoh;
     pcibr_info_t            pcibr_info;
     int                     win;
+    int                     error = 0;
+#endif	/* PIC_LATER */
 
+	BUG();
+#ifdef PIC_LATER
     if (pcibr_soft->bs_slot[pciio_slot].has_host) {
 	pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot;
 	pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0];
     }
-    if (pciio_slot < 4) {
+
+    if ((pciio_slot >= pcibr_soft->bs_first_slot) &&
+        (pciio_slot <= pcibr_soft->bs_last_reset)) {
 	s = pcibr_lock(pcibr_soft);
 	nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo;
 	pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos;
 	for (f = 0; f < nf; ++f)
 	    if (pcibr_infoh[f])
-		cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4];
+		cfgctl[f] = pcibr_func_config_get(bridge, pciio_slot, f,
+							PCI_CFG_COMMAND/4);
+
+        error = iobrick_pci_slot_rst(pcibr_soft->bs_l1sc,
+                             pcibr_widget_to_bus(pcibr_soft->bs_vhdl),
+                             PCIBR_DEVICE_TO_SLOT(pcibr_soft,pciio_slot),
+                             NULL);
 
 	ctlreg = bridge->b_wid_control;
-	bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot);
-	/* XXX delay? */
-	bridge->b_wid_control = ctlreg;
-	/* XXX delay? */
+	bridge->b_wid_control = ctlreg & ~BRIDGE_CTRL_RST_PIN(pciio_slot);
+        nano_delay(&ts);
+	bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST_PIN(pciio_slot);
+        nano_delay(&ts);
 
 	for (f = 0; f < nf; ++f)
 	    if ((pcibr_info = pcibr_infoh[f]))
 		for (win = 0; win < 6; ++win)
 		    if (pcibr_info->f_window[win].w_base != 0)
-			bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] =
-			    pcibr_info->f_window[win].w_base;
+			pcibr_func_config_set(bridge, pciio_slot, f,
+					PCI_CFG_BASE_ADDR(win) / 4, 
+					pcibr_info->f_window[win].w_base);
 	for (f = 0; f < nf; ++f)
 	    if (pcibr_infoh[f])
-		bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f];
+		pcibr_func_config_set(bridge, pciio_slot, f,
+					PCI_CFG_COMMAND / 4,
+					cfgctl[f]);
 	pcibr_unlock(pcibr_soft, s);
 
+	if (error)
+            return(-1);
+
 	return 0;
     }
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    printk(KERN_WARNING   "%v: pcibr_reset unimplemented for slot %d\n",
-	    conn, pciio_slot);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, conn,
+    		"pcibr_reset unimplemented for slot %d\n", conn, pciio_slot));
+#endif	/* PIC_LATER */
     return -1;
 }
 
@@ -4029,7 +4489,7 @@
 		 pciio_endian_t desired_end)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridgereg_t             devreg;
     unsigned long           s;
@@ -4053,16 +4513,32 @@
     if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 
-	bridge->b_device[pciio_slot].reg = devreg;
-	pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;           /* wait until Bridge PIO complete */
+		}
+	}
     }
     pcibr_unlock(pcibr_soft, s);
 
-#if DEBUG && PCIBR_DEV_DEBUG
-    printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg);
+#ifdef PIC_LATER
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl,
+    		"pcibr_endian_set: Device(%d): %x\n",
+		pciio_slot, devreg, device_bits));
+#else
+    printk("pcibr_endian_set: Device(%d): %x\n", pciio_slot, devreg);
 #endif
-
     return desired_end;
 }
 
@@ -4130,9 +4606,22 @@
     if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 
-	bridge->b_device[pciio_slot].reg = devreg;
-	pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;           /* wait until Bridge PIO complete */
+		}
+	}
     }
     pcibr_unlock(pcibr_soft, s);
 
@@ -4144,7 +4633,7 @@
 		   pciio_priority_t device_prio)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
 
     (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio);
@@ -4168,7 +4657,7 @@
 		       pcibr_device_flags_t flags)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridgereg_t             set = 0;
     bridgereg_t             clr = 0;
@@ -4215,18 +4704,81 @@
 	if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	    bridge_t               *bridge = pcibr_soft->bs_base;
 
-	    bridge->b_device[pciio_slot].reg = devreg;
-	    pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	    bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	    if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	    }
+	    else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;       /* wait until Bridge PIO complete */
+		}
+	    }
 	}
 	pcibr_unlock(pcibr_soft, s);
-#if DEBUG && PCIBR_DEV_DEBUG
-	printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits);
+#ifdef PIC_LATER
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl,
+		    "pcibr_device_flags_set: Device(%d): %x\n",
+		    pciio_slot, devreg, device_bits));
+#else
+	printk("pcibr_device_flags_set: Device(%d): %x\n", pciio_slot, devreg);
 #endif
     }
     return (1);
 }
 
+/*
+ * PIC has 16 RBARs per bus; meaning it can have a total of 16 outstanding 
+ * split transactions.  If the functions on the bus have requested a total 
+ * of 16 or less, then we can give them what they requested (ie. 100%). 
+ * Otherwise we have make sure each function can get at least one buffer
+ * and then divide the rest of the buffers up among the functions as ``A 
+ * PERCENTAGE OF WHAT THEY REQUESTED'' (i.e. 0% - 100% of a function's
+ * pcix_type0_status.max_out_split).  This percentage does not include the
+ * one RBAR that all functions get by default.
+ */
+int
+pcibr_pcix_rbars_calc(pcibr_soft_t pcibr_soft)
+{
+    /* 'percent_allowed' is the percentage of requested RBARs that functions
+     * are allowed, ***less the 1 RBAR that all functions get by default***
+     */
+    int percent_allowed; 
+
+    if (pcibr_soft->bs_pcix_num_funcs) {
+	if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) {
+	    printk(KERN_WARNING
+		"%lx: Must oversubscribe Read Buffer Attribute Registers"
+		"(RBAR).  Bus has %d RBARs but %d funcs need them.\n",
+		(unsigned long)pcibr_soft->bs_vhdl, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs);
+	    percent_allowed = 0;
+	} else {
+	    percent_allowed = (((NUM_RBAR-pcibr_soft->bs_pcix_num_funcs)*100) /
+		               pcibr_soft->bs_pcix_split_tot);
+
+	    /* +1 to percentage to solve rounding errors that occur because
+	     * we're not doing fractional math. (ie. ((3 * 66%) / 100) = 1)
+	     * but should be "2" if doing true fractional math.  NOTE: Since
+	     * the greatest number of outstanding transactions a function 
+	     * can request is 32, this "+1" will always work (i.e. we won't
+	     * accidentally oversubscribe the RBARs because of this rounding
+	     * of the percentage).
+	     */
+	    percent_allowed=(percent_allowed > 100) ? 100 : percent_allowed+1;
+	}
+    } else {
+	return(ENODEV);
+    }
+
+    return(percent_allowed);
+}
+
 pciio_provider_t        pcibr_provider =
 {
     (pciio_piomap_alloc_f *) pcibr_piomap_alloc,
@@ -4262,17 +4814,17 @@
     (pciio_priority_set_f *) pcibr_priority_set,
     (pciio_config_get_f *) pcibr_config_get,
     (pciio_config_set_f *) pcibr_config_set,
-
-    (pciio_error_devenable_f *) 0,
-    (pciio_error_extract_f *) 0,
-
-#ifdef LATER
+#ifdef PIC_LATER
+    (pciio_error_devenable_f *) pcibr_error_devenable,
+    (pciio_error_extract_f *) pcibr_error_extract,
     (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback,
     (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback,
 #else
+    (pciio_error_devenable_f *) 0,
+    (pciio_error_extract_f *) 0,
     (pciio_driver_reg_callback_f *) 0,
     (pciio_driver_unreg_callback_f *) 0,
-#endif
+#endif	/* PIC_LATER */
     (pciio_device_unregister_f 	*) pcibr_device_unregister,
     (pciio_dma_enabled_f		*) pcibr_dma_enabled,
 };
@@ -4286,3 +4838,83 @@
 
     return xtalk_dma_enabled(pcibr_soft->bs_conn);
 }
+
+
+/*
+ * pcibr_debug() is used to print pcibr debug messages to the console.  A
+ * user enables tracing by setting the following global variables:
+ *
+ *    pcibr_debug_mask 	   -Bitmask of what to trace. see pcibr_private.h
+ *    pcibr_debug_module   -Module to trace.  'all' means trace all modules
+ *    pcibr_debug_widget   -Widget to trace. '-1' means trace all widgets
+ *    pcibr_debug_slot	   -Slot to trace.  '-1' means trace all slots
+ *
+ * 'type' is the type of debugging that the current PCIBR_DEBUG macro is
+ * tracing.  'vhdl' (which can be NULL) is the vhdl associated with the
+ * debug statement.  If there is a 'vhdl' associated with this debug
+ * statement, it is parsed to obtain the module, widget, and slot.  If the
+ * globals above match the PCIBR_DEBUG params, then the debug info in the
+ * parameter 'format' is sent to the console.
+ */
+void
+pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...)
+{
+    char hwpath[MAXDEVNAME] = "\0";
+    char copy_of_hwpath[MAXDEVNAME];
+    char *module = "all";
+    short widget = -1;
+    short slot = -1;
+    va_list ap;
+    char *strtok_r(char *string, const char *sepset, char **lasts);
+
+    if (pcibr_debug_mask & type) {
+        if (vhdl) {
+            if (!hwgraph_vertex_name_get(vhdl, hwpath, MAXDEVNAME)) {
+                char *cp;
+
+                if (strcmp(module, pcibr_debug_module)) {
+		    /* strtok_r() wipes out string, use a copy */
+                    (void)strcpy(copy_of_hwpath, hwpath);
+                    cp = strstr(copy_of_hwpath, "/module/");
+                    if (cp) {
+                        char *last = NULL;
+                        cp += strlen("/module");
+                        module = strtok_r(cp, "/", &last);
+                    }
+                }
+                if (pcibr_debug_widget != -1) {
+                    cp = strstr(hwpath, "/xtalk/");
+                    if (cp) {
+                        cp += strlen("/xtalk/");
+                        widget = atoi(cp);
+                    }
+                }
+                if (pcibr_debug_slot != -1) {
+                    cp = strstr(hwpath, "/pci/");
+                    if (cp) {
+                        cp += strlen("/pci/");
+                        slot = atoi(cp);
+                    }
+                }
+            }
+        }
+        if ((vhdl == NULL) ||
+            (!strcmp(module, pcibr_debug_module) &&
+             (widget == pcibr_debug_widget) &&
+             (slot == pcibr_debug_slot))) {
+#ifdef LATER
+            printk("PCIBR_DEBUG<%d>\t: %s :", cpuid(), hwpath);
+#else
+            printk("PCIBR_DEBUG\t: %s :", hwpath);
+#endif
+	    /*
+	     * Kernel printk translates to this 3 line sequence.
+	     * Since we have a variable length argument list, we
+	     * need to call printk this way rather than directly
+	     */
+	    va_start(ap, format);
+	    printk(format, ap);
+	    va_end(ap);
+        }
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c	2003-05-22 22:06:40.000000000 +0000
@@ -39,6 +39,14 @@
 #endif
 
 extern int	hubii_check_widget_disabled(nasid_t, int);
+#ifdef BRIDGE_B_DATACORR_WAR
+extern int              ql_bridge_rev_b_war(devfs_handle_t);
+extern int              bridge_rev_b_data_check_disable;
+char                   *rev_b_datacorr_warning =
+"***************************** WARNING! ******************************\n";
+char                   *rev_b_datacorr_mesg =
+"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n";
+#endif
 
 /* =====================================================================
  *    ERROR HANDLING
@@ -54,15 +62,18 @@
 #define BRIDGE_PIOERR_TIMEOUT	1	/* Timeout in non-debug mode                            */
 #endif
 
+/* PIC has 64bit interrupt error registers, but BRIDGE has 32bit registers.
+ * Thus 'bridge_errors_to_dump needs' to default to the larger of the two.
+ */
 #ifdef  DEBUG
 #ifdef ERROR_DEBUG
-bridgereg_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK;
+uint64_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK;
 #else
-bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP;
+uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP;
 #endif
 #else
-bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL |
-                                BRIDGE_ISR_PCIBUS_PIOERR;
+uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL |
+                                   BRIDGE_ISR_PCIBUS_PIOERR;
 #endif
 
 #if defined (PCIBR_LLP_CONTROL_WAR)
@@ -71,8 +82,6 @@
 
 /* FIXME: can these arrays be local ? */
 
-#ifdef LATER
-
 struct reg_values xio_cmd_pactyp[] =
 {
     {0x0, "RdReq"},
@@ -113,7 +122,21 @@
 
 struct reg_desc         bridge_int_status_desc[] =
 {
-    F(31, "MULTI_ERR"),
+    F(45, "PCI_X_SPLIT_MES_PE"),/* PIC ONLY */
+    F(44, "PCI_X_SPLIT_EMES"),	/* PIC ONLY */
+    F(43, "PCI_X_SPLIT_TO"),	/* PIC ONLY */
+    F(42, "PCI_X_UNEX_COMP"),	/* PIC ONLY */
+    F(41, "INT_RAM_PERR"),	/* PIC ONLY */
+    F(40, "PCI_X_ARB_ERR"),	/* PIC ONLY */
+    F(39, "PCI_X_REQ_TOUT"),	/* PIC ONLY */
+    F(38, "PCI_X_TABORT"),	/* PIC ONLY */
+    F(37, "PCI_X_PERR"),	/* PIC ONLY */
+    F(36, "PCI_X_SERR"),	/* PIC ONLY */
+    F(35, "PCI_X_MRETRY"),	/* PIC ONLY */
+    F(34, "PCI_X_MTOUT"),	/* PIC ONLY */
+    F(33, "PCI_X_DA_PARITY"),	/* PIC ONLY */
+    F(32, "PCI_X_AD_PARITY"),	/* PIC ONLY */
+    F(31, "MULTI_ERR"),		/* BRIDGE ONLY */
     F(30, "PMU_ESIZE_EFAULT"),
     F(29, "UNEXPECTED_RESP"),
     F(28, "BAD_XRESP_PACKET"),
@@ -128,7 +151,7 @@
     F(19, "LLP_RCTY"),
     F(18, "LLP_TX_RETRY"),
     F(17, "LLP_TCTY"),
-    F(16, "SSRAM_PERR"),
+    F(16, "SSRAM_PERR"),	/* BRIDGE ONLY */
     F(15, "PCI_ABORT"),
     F(14, "PCI_PARITY"),
     F(13, "PCI_SERR"),
@@ -136,7 +159,7 @@
     F(11, "PCI_MASTER_TOUT"),
     F(10, "PCI_RETRY_CNT"),
     F(9, "XREAD_REQ_TOUT"),
-    F(8, "GIO_BENABLE_ERR"),
+    F(8, "GIO_BENABLE_ERR"),	/* BRIDGE ONLY */
     F(7, "INT7"),
     F(6, "INT6"),
     F(5, "INT5"),
@@ -195,20 +218,17 @@
     {0}
 };
 
-#endif	/* LATER */
-
 void
 print_bridge_errcmd(uint32_t cmdword, char *errtype)
 {
-    printk(
-	    "\t    Bridge %s Error Command Word Register %R\n",
-	    errtype, cmdword, xio_cmd_bits);
+    printk("\t    Bridge %s Error Command Word Register ", errtype);
+    print_register(cmdword, xio_cmd_bits);
 }
 
 char             *pcibr_isr_errs[] =
 {
     "", "", "", "", "", "", "", "",
-    "08: GIO non-contiguous byte enable in crosstalk packet",
+    "08: GIO non-contiguous byte enable in crosstalk packet", /* BRIDGE ONLY */
     "09: PCI to Crosstalk read request timeout",
     "10: PCI retry operation count exhausted.",
     "11: PCI bus device select timeout",
@@ -216,7 +236,7 @@
     "13: PCI Address/Cmd parity error ",
     "14: PCI Bridge detected parity error",
     "15: PCI abort condition",
-    "16: SSRAM parity error",
+    "16: SSRAM parity error", /* BRIDGE ONLY */
     "17: LLP Transmitter Retry count wrapped",
     "18: LLP Transmitter side required Retry",
     "19: LLP Receiver retry count wrapped",
@@ -231,13 +251,29 @@
     "28: Framing error, response cmd data size does not match actual",
     "29: Unexpected response arrived",
     "30: PMU Access Fault",
-    "31: Multiple errors occurred",
+    "31: Multiple errors occurred", /* BRIDGE ONLY */
+    
+    /* bits 32-45 are PIC ONLY */
+    "32: PCI-X address or attribute cycle parity error",
+    "33: PCI-X data cycle parity error",
+    "34: PCI-X master timeout (ie. master abort)",
+    "35: PCI-X pio retry counter exhausted",
+    "36: PCI-X SERR",
+    "37: PCI-X PERR", 
+    "38: PCI-X target abort",
+    "39: PCI-X read request timeout",
+    "40: PCI / PCI-X device requestin arbitration error",
+    "41: internal RAM parity error",
+    "42: PCI-X unexpected completion cycle to master",
+    "43: PCI-X split completion timeout",
+    "44: PCI-X split completion error message",
+    "45: PCI-X split completion message parity error",
 };
 
 #define BEM_ADD_STR(s)  printk("%s", (s))
-#define BEM_ADD_VAR(v)  printk("\t%20s: 0x%x\n", #v, (v))
-#define BEM_ADD_REG(r)  printk("\t%20s: %R\n", #r, (r), r ## _desc)
-#define BEM_ADD_NSPC(n,s)       printk("\t%20s: %R\n", n, s, space_desc)
+#define BEM_ADD_VAR(v)  printk("\t%20s: 0x%llx\n", #v, ((unsigned long long)v))
+#define BEM_ADD_REG(r)  printk("\t%20s: ", #r); print_register((r), r ## _desc)
+#define BEM_ADD_NSPC(n,s)       printk("\t%20s: ", n); print_register(s, space_desc)
 #define BEM_ADD_SPC(s)          BEM_ADD_NSPC(#s, s)
 
 /*
@@ -246,6 +282,7 @@
 void
 pcibr_show_dir_state(paddr_t paddr, char *prefix)
 {
+#ifdef LATER
 	int state;
 	uint64_t vec_ptr;
 	hubreg_t elo;
@@ -254,8 +291,9 @@
 
 	get_dir_ent(paddr, &state, &vec_ptr, &elo);
 
-	printf("%saddr 0x%x: state 0x%x owner 0x%x (%s)\n", 
+	printk("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", 
 		prefix, paddr, state, vec_ptr, dir_state_str[state]);
+#endif
 }
 
 
@@ -267,40 +305,70 @@
 pcibr_error_dump(pcibr_soft_t pcibr_soft)
 {
     bridge_t               *bridge = pcibr_soft->bs_base;
-    bridgereg_t             int_status;
-    bridgereg_t             mult_int;
-    int			    bit;
+    uint64_t		    int_status;
+    bridgereg_t             int_status_32;
+    picreg_t		    int_status_64;
+    uint64_t		    mult_int;
+    bridgereg_t             mult_int_32;
+    picreg_t		    mult_int_64;
+    uint64_t		    bit;
+    int			    number_bits;
     int                     i;
     char		    *reg_desc;
-    paddr_t		    addr;
+    paddr_t		    addr = (paddr_t)0;
+
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+	int_status = (uint64_t)int_status_64;
+	number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+	int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+	int_status = ((uint64_t)int_status_32) & 0xffffffff;
+	number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
 
-    int_status = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
     if (!int_status) {
 	/* No error bits set */
 	return;
     }
 
     /* Check if dumping the same error information multiple times */
-    if (test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat,
-	    int_status) == int_status) {
+    if ( pcibr_soft->bs_errinfo.bserr_intstat == int_status )
 	return;
-    }
+    pcibr_soft->bs_errinfo.bserr_intstat = int_status;
 
-    printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%X for %s\n"
-	"    Dumping relevant %sBridge registers for each bit set...\n",
+    printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%lx for %s\n"
+	"    Dumping relevant %s registers for each bit set...\n",
 	    int_status, pcibr_soft->bs_name,
-	    (is_xbridge(bridge) ? "X" : ""));
+	    (IS_PIC_SOFT(pcibr_soft) ? "PIC" : 
+	        (IS_BRIDGE_SOFT(pcibr_soft) ? "BRIDGE" : "XBRIDGE")));
 
-    for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) {
-	bit = 1 << i;
+    for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) {
+	bit = 1ull << i;
 
 	/*
 	 * A number of int_status bits are only defined for Bridge.
-	 * Ignore them in the case of an XBridge.
+	 * Ignore them in the case of an XBridge or PIC.
 	 */
-	if (is_xbridge(bridge) && ((bit == BRIDGE_ISR_MULTI_ERR) ||
-		(bit == BRIDGE_ISR_SSRAM_PERR) ||
-		(bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) {
+	if ((IS_XBRIDGE_SOFT(pcibr_soft) || IS_PIC_SOFT(pcibr_soft)) &&
+	    ((bit == BRIDGE_ISR_MULTI_ERR) ||
+	     (bit == BRIDGE_ISR_SSRAM_PERR) ||
+	     (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) {
+	    continue;
+	}
+
+	/* A number of int_status bits are only valid for PIC's bus0 */
+	if ((IS_PIC_SOFT(pcibr_soft) && (pcibr_soft->bs_busnum != 0)) && 
+	    ((bit == BRIDGE_ISR_UNSUPPORTED_XOP) ||
+	     (bit == BRIDGE_ISR_LLP_REC_SNERR) ||
+	     (bit == BRIDGE_ISR_LLP_REC_CBERR) ||
+	     (bit == BRIDGE_ISR_LLP_RCTY) ||
+	     (bit == BRIDGE_ISR_LLP_TX_RETRY) ||
+	     (bit == BRIDGE_ISR_LLP_TCTY))) {
 	    continue;
 	}
 
@@ -308,91 +376,241 @@
 	    printk("\t%s\n", pcibr_isr_errs[i]);
 
 	    switch (bit) {
-	    case BRIDGE_ISR_PAGE_FAULT:		/* PMU_PAGE_FAULT  (XBridge) */
-/*	    case BRIDGE_ISR_PMU_ESIZE_FAULT:	   PMU_ESIZE_FAULT (Bridge) */
-		if (is_xbridge(bridge))
+
+	    case PIC_ISR_INT_RAM_PERR:	    /* bit41	INT_RAM_PERR */
+		/* XXX: should breakdown meaning of bits in reg */
+		printk( "\t	Internal RAM Parity Error: 0x%lx\n",
+		    bridge->p_ate_parity_err_64);
+		break;
+
+	    case PIC_ISR_PCIX_ARB_ERR:	    /* bit40	PCI_X_ARB_ERR */
+		/* XXX: should breakdown meaning of bits in reg */
+		printk( "\t	Arbitration Reg: 0x%x\n",
+		    bridge->b_arb);
+		break;
+
+	    case PIC_ISR_PCIX_REQ_TOUT:	    /* bit39	PCI_X_REQ_TOUT */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X DMA Request Error Address Reg: 0x%lx\n"
+		    "\t	   PCI-X DMA Request Error Attribute Reg: 0x%lx\n",
+		    bridge->p_pcix_dma_req_err_addr_64,
+		    bridge->p_pcix_dma_req_err_attr_64);
+		break;
+
+	    case PIC_ISR_PCIX_SPLIT_MSG_PE: /* bit45	PCI_X_SPLIT_MES_PE */
+	    case PIC_ISR_PCIX_SPLIT_EMSG:   /* bit44	PCI_X_SPLIT_EMESS */
+	    case PIC_ISR_PCIX_SPLIT_TO:	    /* bit43	PCI_X_SPLIT_TO */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X Split Request Address Reg: 0x%lx\n"
+		    "\t	   PCI-X Split Request Attribute Reg: 0x%lx\n",
+		    bridge->p_pcix_pio_split_addr_64,
+		    bridge->p_pcix_pio_split_attr_64);
+		/* FALL THRU */
+
+	    case PIC_ISR_PCIX_UNEX_COMP:    /* bit42	PCI_X_UNEX_COMP */
+	    case PIC_ISR_PCIX_TABORT:	    /* bit38	PCI_X_TABORT */
+	    case PIC_ISR_PCIX_PERR:	    /* bit37	PCI_X_PERR */
+	    case PIC_ISR_PCIX_SERR:	    /* bit36	PCI_X_SERR */
+	    case PIC_ISR_PCIX_MRETRY:	    /* bit35	PCI_X_MRETRY */
+	    case PIC_ISR_PCIX_MTOUT:	    /* bit34	PCI_X_MTOUT */
+	    case PIC_ISR_PCIX_DA_PARITY:    /* bit33	PCI_X_DA_PARITY */
+	    case PIC_ISR_PCIX_AD_PARITY:    /* bit32	PCI_X_AD_PARITY */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X Bus Error Address Reg: 0x%lx\n"
+		    "\t	   PCI-X Bus Error Attribute Reg: 0x%lx\n"
+		    "\t	   PCI-X Bus Error Data Reg: 0x%lx\n",
+		    bridge->p_pcix_bus_err_addr_64,
+		    bridge->p_pcix_bus_err_attr_64,
+		    bridge->p_pcix_bus_err_data_64);
+		break;
+
+	    case BRIDGE_ISR_PAGE_FAULT:	    /* bit30	PMU_PAGE_FAULT */
+/*	    case BRIDGE_ISR_PMU_ESIZE_FAULT:   bit30	PMU_ESIZE_FAULT */
+		if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
 		    reg_desc = "Map Fault Address";
 		else
 		    reg_desc = "SSRAM Parity Error";
 
-		printk("\t    %s Register: 0x%x\n", reg_desc,
+		printk( "\t    %s Register: 0x%x\n", reg_desc,
 		    bridge->b_ram_perr_or_map_fault);
 		break;
 
-	    case BRIDGE_ISR_UNEXP_RESP:		/* UNEXPECTED_RESP */
-		print_bridge_errcmd(bridge->b_wid_aux_err, "Aux");
-		break;
+	    case BRIDGE_ISR_UNEXP_RESP:    /* bit29	UNEXPECTED_RESP */
+		print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
 
-	    case BRIDGE_ISR_BAD_XRESP_PKT:		/* BAD_RESP_PACKET */
-	    case BRIDGE_ISR_RESP_XTLK_ERR:		/* RESP_XTALK_ERROR */
-	    case BRIDGE_ISR_XREAD_REQ_TIMEOUT:		/* XREAD_REQ_TOUT */
+		/* PIC in PCI-X mode, dump the PCIX DMA Request registers */
+		if (IS_PIC_SOFT(pcibr_soft) && IS_PCIX(pcibr_soft)) {
+		    /* XXX: should breakdown meaning of attr bit */
+		    printk( 
+			"\t    PCI-X DMA Request Error Addr Reg: 0x%lx\n"
+			"\t    PCI-X DMA Request Error Attr Reg: 0x%lx\n",
+			bridge->p_pcix_dma_req_err_addr_64,
+			bridge->p_pcix_dma_req_err_attr_64);
+		}
+		break;
 
-		addr = (((uint64_t) (bridge->b_wid_resp_upper & 0xFFFF) << 32)
-			| bridge->b_wid_resp_lower);
-		printk(
-		    "\t    Bridge Response Buffer Error Upper Address Register: 0x%x\n"
-		    "\t    Bridge Response Buffer Error Lower Address Register: 0x%x\n"
-		    "\t    dev-num %d buff-num %d addr 0x%x\n",
-		    bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
-		    ((bridge->b_wid_resp_upper >> 20) & 0x3),
-		    ((bridge->b_wid_resp_upper >> 16) & 0xF),
-		    addr);
+	    case BRIDGE_ISR_BAD_XRESP_PKT:  /* bit28	BAD_RESP_PACKET */
+	    case BRIDGE_ISR_RESP_XTLK_ERR:  /* bit26	RESP_XTALK_ERROR */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		}
+		 
+		/* If PIC in PCI-X mode, DMA Request Error registers are
+		 * valid.  But PIC in PCI mode, Response Buffer Address 
+		 * register are valid.
+		 */
+		if (IS_PCIX(pcibr_soft)) {
+		    /* XXX: should breakdown meaning of attribute bit */
+		    printk( 
+			"\t    PCI-X DMA Request Error Addr Reg: 0x%lx\n"
+		        "\t    PCI-X DMA Request Error Attribute Reg: 0x%lx\n",
+		        bridge->p_pcix_dma_req_err_addr_64,
+		        bridge->p_pcix_dma_req_err_attr_64);
+		} else {
+		    addr= (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF)<<32)
+			   | bridge->b_wid_resp_lower);
+		    printk("\t    Bridge Response Buf Error Upper Addr Reg: 0x%x\n"
+		        "\t    Bridge Response Buf Error Lower Addr Reg: 0x%x\n"
+		        "\t    dev-num %d buff-num %d addr 0x%lx\n",
+		        bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
+		        ((bridge->b_wid_resp_upper >> 20) & 0x3),
+		        ((bridge->b_wid_resp_upper >> 16) & 0xF),
+		        addr);
+		}
 		if (bit == BRIDGE_ISR_RESP_XTLK_ERR) {
 			/* display memory directory associated with cacheline */
 			pcibr_show_dir_state(addr, "\t    ");
 		}
 		break;
 
-	    case BRIDGE_ISR_BAD_XREQ_PKT:		/* BAD_XREQ_PACKET */
-	    case BRIDGE_ISR_REQ_XTLK_ERR:		/* REQ_XTALK_ERROR */
-	    case BRIDGE_ISR_INVLD_ADDR:			/* INVALID_ADDRESS */
-	    case BRIDGE_ISR_UNSUPPORTED_XOP:		/* UNSUPPORTED_XOP */
-		print_bridge_errcmd(bridge->b_wid_aux_err, "");
-		printk("\t    Bridge Error Upper Address Register: 0x%x\n"
-		    "\t    Bridge Error Lower Address Register: 0x%x\n"
-		    "\t    Bridge Error Address: 0x%x\n",
+	    case BRIDGE_ISR_BAD_XREQ_PKT:   /* bit27	BAD_XREQ_PACKET */
+	    case BRIDGE_ISR_REQ_XTLK_ERR:   /* bit25	REQ_XTALK_ERROR */
+	    case BRIDGE_ISR_INVLD_ADDR:	    /* bit24	INVALID_ADDRESS */
+		print_bridge_errcmd(bridge->b_wid_err_cmdword, "");
+		printk( 
+		    "\t    Bridge Error Upper Address Register: 0x%lx\n"
+		    "\t    Bridge Error Lower Address Register: 0x%lx\n"
+		    "\t    Bridge Error Address: 0x%lx\n",
 		    (uint64_t) bridge->b_wid_err_upper,
 		    (uint64_t) bridge->b_wid_err_lower,
 		    (((uint64_t) bridge->b_wid_err_upper << 32) |
 		    bridge->b_wid_err_lower));
 		break;
 
-	    case BRIDGE_ISR_SSRAM_PERR:			/* SSRAM_PERR */
-		if (!is_xbridge(bridge)) {	/* only defined on Bridge */
+	    case BRIDGE_ISR_UNSUPPORTED_XOP:/* bit23	UNSUPPORTED_XOP */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		    printk( 
+			"\t    Address Holding Link Side Error Reg: 0x%lx\n",
+			bridge->p_addr_lkerr_64);
+		} else {
+		    print_bridge_errcmd(bridge->b_wid_err_cmdword, "");
+		    printk( 
+			"\t    Bridge Error Upper Address Register: 0x%lx\n"
+		        "\t    Bridge Error Lower Address Register: 0x%lx\n"
+		        "\t    Bridge Error Address: 0x%lx\n",
+		        (uint64_t) bridge->b_wid_err_upper,
+		        (uint64_t) bridge->b_wid_err_lower,
+		        (((uint64_t) bridge->b_wid_err_upper << 32) |
+		        bridge->b_wid_err_lower));
+		}
+		break;
+
+	    case BRIDGE_ISR_XREQ_FIFO_OFLOW:/* bit22	XREQ_FIFO_OFLOW */
+		/* Link side error registers are only valid for PIC */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		    printk(
+			"\t    Address Holding Link Side Error Reg: 0x%lx\n",
+			bridge->p_addr_lkerr_64);
+		}
+		break;
+
+	    case BRIDGE_ISR_SSRAM_PERR:	    /* bit16	SSRAM_PERR */
+		if (IS_BRIDGE_SOFT(pcibr_soft)) {
 		    printk(
 			"\t    Bridge SSRAM Parity Error Register: 0x%x\n",
 			bridge->b_ram_perr);
 		}
 		break;
 
-	    case BRIDGE_ISR_PCI_ABORT:			/* PCI_ABORT */
-	    case BRIDGE_ISR_PCI_PARITY:			/* PCI_PARITY */
-	    case BRIDGE_ISR_PCI_SERR:			/* PCI_SERR */
-	    case BRIDGE_ISR_PCI_PERR:			/* PCI_PERR */
-	    case BRIDGE_ISR_PCI_MST_TIMEOUT:		/* PCI_MASTER_TOUT */
-	    case BRIDGE_ISR_PCI_RETRY_CNT:		/* PCI_RETRY_CNT */
-	    case BRIDGE_ISR_GIO_B_ENBL_ERR:		/* GIO BENABLE_ERR */
-		printk("\t    PCI Error Upper Address Register: 0x%x\n"
-		    "\t    PCI Error Lower Address Register: 0x%x\n"
-		    "\t    PCI Error Address: 0x%x\n",
+	    case BRIDGE_ISR_PCI_ABORT:	    /* bit15	PCI_ABORT */
+	    case BRIDGE_ISR_PCI_PARITY:	    /* bit14	PCI_PARITY */
+	    case BRIDGE_ISR_PCI_SERR:	    /* bit13	PCI_SERR */
+	    case BRIDGE_ISR_PCI_PERR:	    /* bit12	PCI_PERR */
+	    case BRIDGE_ISR_PCI_MST_TIMEOUT:/* bit11	PCI_MASTER_TOUT */
+	    case BRIDGE_ISR_PCI_RETRY_CNT:  /* bit10	PCI_RETRY_CNT */
+	    case BRIDGE_ISR_GIO_B_ENBL_ERR: /* bit08	GIO BENABLE_ERR */
+		printk( 
+		    "\t    PCI Error Upper Address Register: 0x%lx\n"
+		    "\t    PCI Error Lower Address Register: 0x%lx\n"
+		    "\t    PCI Error Address: 0x%lx\n",
 		    (uint64_t) bridge->b_pci_err_upper,
 		    (uint64_t) bridge->b_pci_err_lower,
 		    (((uint64_t) bridge->b_pci_err_upper << 32) |
 		    bridge->b_pci_err_lower));
 		break;
+
+	    case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09	XREAD_REQ_TOUT */
+		addr = (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF) << 32)
+		    | bridge->b_wid_resp_lower);
+		printk(
+		    "\t    Bridge Response Buf Error Upper Addr Reg: 0x%x\n"
+		    "\t    Bridge Response Buf Error Lower Addr Reg: 0x%x\n"
+		    "\t    dev-num %d buff-num %d addr 0x%lx\n",
+		    bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
+		    ((bridge->b_wid_resp_upper >> 20) & 0x3),
+		    ((bridge->b_wid_resp_upper >> 16) & 0xF),
+		    addr);
+		break;
 	    }
 	}
     }
 
-    if (is_xbridge(bridge) && (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK)) {
-	mult_int = bridge->b_mult_int;
-	printk("    XBridge Multiple Interrupt Register is 0x%x\n",
-		mult_int);
-	for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) {
-	    if (mult_int & (1 << i))
-		printk("\t%s\n", pcibr_isr_errs[i]);
-	    }
+    /* We read the INT_MULT register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	mult_int_64 = (bridge->p_mult_int_64 & ~BRIDGE_ISR_INT_MSK);
+	mult_int = (uint64_t)mult_int_64;
+	number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+	mult_int_32 = (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK);
+	mult_int = ((uint64_t)mult_int_32) & 0xffffffff;
+	number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
+
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)&&(mult_int & ~BRIDGE_ISR_INT_MSK)) {
+	printk( "    %s Multiple Interrupt Register is 0x%lx\n",
+		IS_PIC_SOFT(pcibr_soft) ? "PIC" : "XBridge", mult_int);
+	for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) {
+	    if (mult_int & (1ull << i))
+		printk( "\t%s\n", pcibr_isr_errs[i]);
 	}
+    }
+
+#if BRIDGE_ERROR_INTR_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {	/* known bridge bug */
+	/*
+	 * Should never receive interrupts for these reasons on Rev 1 bridge
+	 * as they are not enabled. Assert for it.
+	 */
+	ASSERT((int_status & (BRIDGE_IMR_PCI_MST_TIMEOUT |
+			      BRIDGE_ISR_RESP_XTLK_ERR |
+			      BRIDGE_ISR_LLP_TX_RETRY)) == 0);
+    }
+    if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) {	/* known bridge bug */
+	/*
+	 * This interrupt is turned off at init time. So, should never
+	 * see this interrupt.
+	 */
+	ASSERT((int_status & BRIDGE_ISR_BAD_XRESP_PKT) == 0);
+    }
+#endif
 }
 
 #define PCIBR_ERRINTR_GROUP(error)	\
@@ -430,9 +648,11 @@
 pcibr_pioerr_check(pcibr_soft_t soft)
 {
     bridge_t		   *bridge;
-    bridgereg_t		    b_int_status;
-    bridgereg_t		    b_pci_err_lower;
-    bridgereg_t		    b_pci_err_upper;
+    uint64_t              int_status;
+    bridgereg_t             int_status_32;
+    picreg_t                int_status_64;
+    bridgereg_t		    pci_err_lower;
+    bridgereg_t		    pci_err_upper;
     iopaddr_t		    pci_addr;
     pciio_slot_t	    slot;
     pcibr_piomap_t	    map;
@@ -442,40 +662,48 @@
     int			    func;
 
     bridge = soft->bs_base;
-    b_int_status = bridge->b_int_status;
-    if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
-	b_pci_err_lower = bridge->b_pci_err_lower;
-	b_pci_err_upper = bridge->b_pci_err_upper;
-	b_int_status = bridge->b_int_status;
-	if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
-
-	    pci_addr = b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK;
-	    pci_addr = (pci_addr << 32) | b_pci_err_lower;
-
-	    slot = 8;
-	    while (slot-- > 0) {
-		int 		nfunc = soft->bs_slot[slot].bss_ninfo;
-		pcibr_info_h	pcibr_infoh = soft->bs_slot[slot].bss_infos;
-
-		for (func = 0; func < nfunc; func++) {
-		    pcibr_info_t 	pcibr_info = pcibr_infoh[func];
-
-		    if (!pcibr_info)
-			continue;
-
-		    for (map = pcibr_info->f_piomap;
-			 map != NULL; map = map->bp_next) {
-			base = map->bp_pciaddr;
-			size = map->bp_mapsz;
-			win = map->bp_space - PCIIO_SPACE_WIN(0);
-			if (win < 6)
-			    base += 
-				soft->bs_slot[slot].bss_window[win].bssw_base;
-			else if (map->bp_space == PCIIO_SPACE_ROM)
-			    base += pcibr_info->f_rbase;
-			if ((pci_addr >= base) && (pci_addr < (base + size)))
-			    atomicAddInt(map->bp_toc, 1);
-		    }
+
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(soft)) {
+        int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+        int_status = (uint64_t)int_status_64;
+    } else {
+        int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+        int_status = ((uint64_t)int_status_32) & 0xffffffff;
+    }
+
+    if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
+	pci_err_lower = bridge->b_pci_err_lower;
+	pci_err_upper = bridge->b_pci_err_upper;
+
+	pci_addr = pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK;
+	pci_addr = (pci_addr << 32) | pci_err_lower;
+
+	slot = PCIBR_NUM_SLOTS(soft);
+	while (slot-- > 0) {
+	    int 		nfunc = soft->bs_slot[slot].bss_ninfo;
+	    pcibr_info_h	pcibr_infoh = soft->bs_slot[slot].bss_infos;
+
+	    for (func = 0; func < nfunc; func++) {
+		pcibr_info_t 	pcibr_info = pcibr_infoh[func];
+
+		if (!pcibr_info)
+		    continue;
+
+		for (map = pcibr_info->f_piomap;
+		        map != NULL; map = map->bp_next) {
+		    base = map->bp_pciaddr;
+		    size = map->bp_mapsz;
+		    win = map->bp_space - PCIIO_SPACE_WIN(0);
+		    if (win < 6)
+			base += soft->bs_slot[slot].bss_window[win].bssw_base;
+		    else if (map->bp_space == PCIIO_SPACE_ROM)
+			base += pcibr_info->f_rbase;
+		    if ((pci_addr >= base) && (pci_addr < (base + size)))
+			atomic_inc(&map->bp_toc[0]);
 		}
 	    }
 	}
@@ -502,25 +730,33 @@
  *                due to read or write error!.
  */
 
-
 void
-pcibr_error_intr_handler(intr_arg_t arg)
+pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep)
 {
     pcibr_soft_t            pcibr_soft;
     bridge_t               *bridge;
-    bridgereg_t             int_status;
-    bridgereg_t             err_status;
+    uint64_t              int_status;
+    uint64_t              err_status;
+    bridgereg_t             int_status_32;
+    picreg_t                int_status_64;
+    int			    number_bits;
     int                     i;
 
     /* REFERENCED */
-    bridgereg_t             disable_errintr_mask = 0;
+    uint64_t		    disable_errintr_mask = 0;
+#ifdef EHE_ENABLE
     int 		    rv;
     int 		    error_code = IOECODE_DMA | IOECODE_READ;
     ioerror_mode_t 	    mode = MODE_DEVERROR;
     ioerror_t 	            ioe;
+#endif /* EHE_ENABLE */
     nasid_t		    nasid;
 
+
 #if PCIBR_SOFT_LIST
+    /*
+     * Defensive code for linked pcibr_soft structs
+     */
     {
 	extern pcibr_list_p	pcibr_list;
 	pcibr_list_p            entry;
@@ -528,17 +764,14 @@
 	entry = pcibr_list;
 	while (1) {
 	    if (entry == NULL) {
-		PRINT_PANIC(
-			"pcibr_error_intr_handler:\n"
-			"\tmy parameter (0x%x) is not a pcibr_soft!",
-			arg);
+		PRINT_PANIC("pcibr_error_intr_handler:\tmy parameter (0x%p) is not a pcibr_soft!", arg);
 	    }
 	    if ((intr_arg_t) entry->bl_soft == arg)
 		break;
 	    entry = entry->bl_next;
 	}
     }
-#endif
+#endif /* PCIBR_SOFT_LIST */
     pcibr_soft = (pcibr_soft_t) arg;
     bridge = pcibr_soft->bs_base;
 
@@ -568,16 +801,37 @@
 
     nasid = NASID_GET(bridge);
     if (hubii_check_widget_disabled(nasid, pcibr_soft->bs_xid)) {
-	timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT);
+	DECLARE_WAIT_QUEUE_HEAD(wq);
+	sleep_on_timeout(&wq, BRIDGE_PIOERR_TIMEOUT*HZ );  /* sleep */
 	pcibr_soft->bs_errinfo.bserr_toutcnt++;
+	/* Let's go recursive */
+	return(pcibr_error_intr_handler(irq, arg, ep));
+#ifdef LATER
+	timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT);
+#endif
 	return;
     }
 
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+        int_status = (uint64_t)int_status_64;
+        number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+        int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+        int_status = ((uint64_t)int_status_32) & 0xffffffff;
+        number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn,
+		"pcibr_error_intr_handler: int_status=0x%x\n", int_status));
+
     /* int_status is which bits we have to clear;
      * err_status is the bits we haven't handled yet.
      */
-
-    int_status = bridge->b_int_status &  ~BRIDGE_ISR_INT_MSK;
     err_status = int_status & ~BRIDGE_ISR_MULTI_ERR;
 
     if (!(int_status & ~BRIDGE_ISR_INT_MSK)) {
@@ -593,11 +847,29 @@
 	pcibr_pioerr_check(pcibr_soft);
     }
 
+#ifdef BRIDGE_B_DATACORR_WAR
+    if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) &&
+	(err_status & BRIDGE_IMR_LLP_REC_CBERR)) {
+	if (bridge_rev_b_data_check_disable)
+	    printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning,
+		    pcibr_soft->bs_name, rev_b_datacorr_mesg,
+		    rev_b_datacorr_warning);
+	else {
+	    ql_bridge_rev_b_war(pcibr_soft->bs_vhdl);
+	    PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning,
+		    pcibr_soft->bs_name, rev_b_datacorr_mesg,
+		    rev_b_datacorr_warning);
+	}
+
+	err_status &= ~BRIDGE_IMR_LLP_REC_CBERR;
+    }
+#endif				/* BRIDGE_B_DATACORR_WAR */
+
     if (err_status) {
 	struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat;
 
-	for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++, bs_estat++) {
-	    if (err_status & (1 << i)) {
+	for (i = PCIBR_ISR_ERR_START; i < number_bits; i++, bs_estat++) {
+	    if (err_status & (1ull << i)) {
 		uint32_t              errrate = 0;
 		uint32_t              errcount = 0;
 		uint32_t              errinterval = 0, current_tick = 0;
@@ -606,12 +878,14 @@
 
 		bs_estat->bs_errcount_total++;
 
-		current_tick = lbolt;
+		current_tick = jiffies;
 		errinterval = (current_tick - bs_estat->bs_lasterr_timestamp);
 		errcount = (bs_estat->bs_errcount_total -
 			    bs_estat->bs_lasterr_snapshot);
 
-		is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY == (1 << i));
+		/* LLP interrrupt errors are only valid on BUS0 of the PIC */
+		if (pcibr_soft->bs_busnum == 0)
+		    is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY==(1ull << i));
 
 		/* Check for the divide by zero condition while
 		 * calculating the error rates.
@@ -698,6 +972,15 @@
 			    bs_estat->bs_errcount_total;
 		    }
 		}
+		/* PIC BRINGUP WAR (PV# 856155):
+		 * Dont disable PCI_X_ARB_ERR interrupts, we need the
+		 * interrupt inorder to clear the DEV_BROKE bits in
+		 * b_arb register to re-enable the device.
+		 */
+		if (IS_PIC_SOFT(pcibr_soft) &&
+				!(err_status & PIC_ISR_PCIX_ARB_ERR) &&
+				PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {
+
 		if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) {
 		    /*
 		     * We have seen a fairly large number of errors of
@@ -709,18 +992,26 @@
 			    pcibr_soft->bs_name,
 			    pcibr_isr_errs[i],
 			    bs_estat->bs_errcount_total);
-		    disable_errintr_mask |= (1 << i);
+		    disable_errintr_mask |= (1ull << i);
 		}
+		} /* PIC: WAR for PV 856155 end-of-if */
 	    }
 	}
     }
 
     if (disable_errintr_mask) {
+	unsigned s;
 	/*
 	 * Disable some high frequency errors as they
 	 * could eat up too much cpu time.
 	 */
-	bridge->b_int_enable &= ~disable_errintr_mask;
+	s = pcibr_lock(pcibr_soft);
+	if (IS_PIC_SOFT(pcibr_soft)) {
+	    bridge->p_int_enable_64 &= (picreg_t)(~disable_errintr_mask);
+	} else {
+	    bridge->b_int_enable &= (bridgereg_t)(~disable_errintr_mask);
+	}
+	pcibr_unlock(pcibr_soft, s);
     }
     /*
      * If we leave the PROM cacheable, T5 might
@@ -783,15 +1074,34 @@
     if (rv != IOERROR_HANDLED) {
 #endif /* EHE_ENABLE */
 
+    bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR;
+
     /* Dump/Log Bridge error interrupt info */
     if (err_status & bridge_errors_to_dump) {
-	printk("BRIDGE ERR_STATUS 0x%x\n", err_status);
+	printk("BRIDGE ERR_STATUS 0x%lx\n", err_status);
 	pcibr_error_dump(pcibr_soft);
     }
 
+    /* PIC BRINGUP WAR (PV# 867308):
+     * Make BRIDGE_ISR_LLP_REC_SNERR & BRIDGE_ISR_LLP_REC_CBERR fatal errors
+     * so we know we've hit the problem defined in PV 867308 that we believe
+     * has only been seen in simulation
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) &&
+        (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) {
+        printk("BRIDGE ERR_STATUS 0x%x\n", err_status);
+        pcibr_error_dump(pcibr_soft);
+#ifdef LATER
+        machine_error_dump("");
+#endif
+        PRINT_PANIC("PCI Bridge Error interrupt killed the system");
+    }
+
     if (err_status & BRIDGE_ISR_ERROR_FATAL) {
+#ifdef LATER
 	machine_error_dump("");
-	cmn_err_tag(14, CE_PANIC, "PCI Bridge Error interrupt killed the system");
+#endif
+	PRINT_PANIC("PCI Bridge Error interrupt killed the system");
 	    /*NOTREACHED */
     }
 
@@ -804,11 +1114,27 @@
      * it would cause problems for devices like IOC3 (Lost
      * interrupts ?.). So, just cleanup the interrupt, and
      * use saved values later..
+     * 
+     * PIC doesn't require groups of interrupts to be cleared...
      */
-    bridge->b_int_rst_stat = pcibr_errintr_group(int_status);
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	bridge->p_int_rst_stat_64 = (picreg_t)(int_status | BRIDGE_IRR_MULTI_CLR);
+    } else {
+	bridge->b_int_rst_stat = (bridgereg_t)pcibr_errintr_group(int_status);
+    }
+
+    /* PIC BRINGUP WAR (PV# 856155):
+     * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from
+     * the b_arb register to re-enable the device.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) &&
+		(err_status & PIC_ISR_PCIX_ARB_ERR) &&
+		PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {
+	bridge->b_arb |= (0xf << 20);
+    }
 
     /* Zero out bserr_intstat field */
-    test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, 0);
+    pcibr_soft->bs_errinfo.bserr_intstat = 0;
 }
 
 /*
@@ -832,7 +1158,7 @@
 		  iopaddr_t *offsetp,
 		  pciio_function_t *funcp)
 {
-    int                     s, f, w;
+    int                     s, f = 0, w;
     iopaddr_t               base;
     size_t                  size;
     pciio_piospace_t        piosp;
@@ -864,7 +1190,7 @@
 
 	return s;
     }
-    for (s = 0; s < 8; s++) {
+    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {
 	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;
 	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;
 
@@ -874,8 +1200,7 @@
 	    if (!pcibr_info)
 		continue;
 	    for (w = 0; w < 6; w++) {
-		if (pcibr_info->f_window[w].w_space
-		    == PCIIO_SPACE_NONE) {
+		if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) {
 		    continue;
 		}
 		base = pcibr_info->f_window[w].w_base;
@@ -898,7 +1223,7 @@
      * Check if the address was allocated as part of the
      * pcibr_piospace_alloc calls.
      */
-    for (s = 0; s < 8; s++) {
+    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {
 	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;
 	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;
 
@@ -950,8 +1275,14 @@
     ASSERT(error_code & IOECODE_PIO);
     error_code = error_code;
 
-    bridge->b_int_rst_stat =
-	(BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR);
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        bridge->p_int_rst_stat_64 = BRIDGE_IRR_PCI_GRP_CLR |
+				    PIC_PCIX_GRP_CLR |
+				    BRIDGE_IRR_MULTI_CLR;
+    } else {
+        bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR;
+    }
+
     (void) bridge->b_wid_tflush;	/* flushbus */
 }
 
@@ -1040,13 +1371,6 @@
  *      associated with this device.
  */
 
-#define BEM_ADD_STR(s)	printk("%s", (s))
-#define BEM_ADD_VAR(v)	printk("\t%20s: 0x%x\n", #v, (v))
-#define BEM_ADD_REG(r)	printk("\t%20s: %R\n", #r, (r), r ## _desc)
-
-#define BEM_ADD_NSPC(n,s)	printk("\t%20s: %R\n", n, s, space_desc)
-#define BEM_ADD_SPC(s)		BEM_ADD_NSPC(#s, s)
-
 /* BEM_ADD_IOE doesn't dump the whole ioerror, it just
  * decodes the PCI specific portions -- we count on our
  * callers to dump the raw IOE data.
@@ -1054,40 +1378,38 @@
 #define BEM_ADD_IOE(ioe)						\
 	do {								\
 	    if (IOERROR_FIELDVALID(ioe, busspace)) {			\
-		unsigned		spc;				\
-		unsigned		win;				\
+		iopaddr_t		spc;				\
+		iopaddr_t		win;				\
+		short			widdev;				\
+		iopaddr_t		busaddr;			\
 									\
-		spc = IOERROR_GETVALUE(ioe, busspace);			\
+		IOERROR_GETVALUE(spc, ioe, busspace);			\
 		win = spc - PCIIO_SPACE_WIN(0);				\
+		IOERROR_GETVALUE(busaddr, ioe, busaddr);		\
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);		\
 									\
 		switch (spc) {						\
 		case PCIIO_SPACE_CFG:					\
-		    printk(					\
-			    "\tPCI Slot %d Func %d CFG space Offset 0x%x\n",	\
-	    pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-	    pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI Slot %d Func %d CFG space Offset 0x%lx\n",\
+			    	pciio_widgetdev_slot_get(widdev),	\
+	    			pciio_widgetdev_func_get(widdev),	\
+				busaddr);				\
 		    break;						\
 		case PCIIO_SPACE_IO:					\
-		    printk(					\
-			    "\tPCI I/O space  Offset 0x%x\n",		\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI I/O space  Offset 0x%lx\n", busaddr);	\
 		    break;						\
 		case PCIIO_SPACE_MEM:					\
 		case PCIIO_SPACE_MEM32:					\
 		case PCIIO_SPACE_MEM64:					\
-		    printk(					\
-			    "\tPCI MEM space Offset 0x%x\n",		\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI MEM space Offset 0x%lx\n", busaddr);	\
 		    break;						\
 		default:						\
 		    if (win < 6) {					\
-		    printk(					\
-			    "\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\
-	    pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-	    pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-			    win,					\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI Slot %d Func %d Window %ld Offset 0x%lx\n",\
+	    			pciio_widgetdev_slot_get(widdev),	\
+	    			pciio_widgetdev_func_get(widdev),	\
+			    	win,					\
+			    	busaddr);				\
 		    }							\
 		    break;						\
 		}							\
@@ -1129,34 +1451,38 @@
      * and need to construct the slot/space/offset.
      */
 
-    bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr);
+    IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_pioerror: pcibr_soft=0x%x, bad_xaddr=0x%x\n",
+		pcibr_soft, bad_xaddr));
 
     slot = PCIIO_SLOT_NONE;
     func = PCIIO_FUNC_NONE;
     raw_space = PCIIO_SPACE_NONE;
     raw_paddr = 0;
 
-    if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) &&
-	(bad_xaddr < BRIDGE_TYPE1_CFG)) {
-	raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0;
+    if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft)) &&
+	(bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) {
+	raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft);
 	slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF;
 	raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF;
 	raw_space = PCIIO_SPACE_CFG;
     }
-    if ((bad_xaddr >= BRIDGE_TYPE1_CFG) &&
-	(bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) {
+    if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) &&
+	(bad_xaddr < (PCIBR_TYPE1_CFG(pcibr_soft) + 0x1000))) {
 	/* Type 1 config space:
 	 * slot and function numbers not known.
 	 * Perhaps we can read them back?
 	 */
-	raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG;
+	raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft);
 	raw_space = PCIIO_SPACE_CFG;
     }
-    if ((bad_xaddr >= BRIDGE_DEVIO0) &&
-	(bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) {
+    if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO0(pcibr_soft)) &&
+	(bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) {
 	int                     x;
 
-	raw_paddr = bad_xaddr - BRIDGE_DEVIO0;
+	raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO0(pcibr_soft);
 	x = raw_paddr / BRIDGE_DEVIO_OFF;
 	raw_paddr %= BRIDGE_DEVIO_OFF;
 	/* first two devio windows are double-sized */
@@ -1223,7 +1549,9 @@
 	 * going on (no guessing).
 	 */
 
-	for (cs = 0; (cs < 8) && (slot == PCIIO_SLOT_NONE); cs++) {
+	for (cs = pcibr_soft->bs_min_slot; 
+		(cs < PCIBR_NUM_SLOTS(pcibr_soft)) && 
+					(slot == PCIIO_SLOT_NONE); cs++) {
 	    int                     nf = pcibr_soft->bs_slot[cs].bss_ninfo;
 	    pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;
 
@@ -1283,7 +1611,8 @@
      * strict count, the excess counts are not a
      * problem.
      */
-    for (cs = 0; cs < 8; ++cs) {
+    for (cs = pcibr_soft->bs_min_slot; 
+				cs < PCIBR_NUM_SLOTS(pcibr_soft); ++cs) {
 	int 		nf = pcibr_soft->bs_slot[cs].bss_ninfo;
 	pcibr_info_h	pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;
 
@@ -1313,7 +1642,7 @@
 		wx = PCIIO_SPACE_MEM;
 	    wl = wb + ws;
 	    if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) {
-		atomicAddInt(map->bp_toc, 1);
+		atomic_inc(&map->bp_toc[0]);
 		if (slot == PCIIO_SLOT_NONE) {
 		    slot = cs;
 		    space = map->bp_space;
@@ -1325,15 +1654,21 @@
 	}
     }
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_pioerror: offset=0x%x, slot=0x%x, func=0x%x\n",
+		offset, slot, func));
+
     if (space != PCIIO_SPACE_NONE) {
-	if (slot != PCIIO_SLOT_NONE) 
-	    if (func != PCIIO_FUNC_NONE)
+	if (slot != PCIIO_SLOT_NONE) {
+	    if (func != PCIIO_FUNC_NONE) {
 		IOERROR_SETVALUE(ioe, widgetdev, 
 				 pciio_widgetdev_create(slot,func));
-	    else
+	    }
+	    else {
     		IOERROR_SETVALUE(ioe, widgetdev, 
 				 pciio_widgetdev_create(slot,0));
-
+	    }
+	}
 	IOERROR_SETVALUE(ioe, busspace, space);
 	IOERROR_SETVALUE(ioe, busaddr, offset);
     }
@@ -1360,7 +1695,7 @@
 
     if (space == PCIIO_SPACE_NONE) {
 	printk("XIO Bus Error at %s\n"
-		"\taccess to XIO bus offset 0x%x\n"
+		"\taccess to XIO bus offset 0x%lx\n"
 		"\tdoes not correspond to any PCI address\n",
 		pcibr_soft->bs_name, bad_xaddr);
 
@@ -1434,17 +1769,21 @@
 	     */
 
 	    BEM_ADD_STR("Raw info from Bridge/PCI layer:\n");
-	    if (bridge->b_int_status & BRIDGE_ISR_PCIBUS_PIOERR)
-		pcibr_error_dump(pcibr_soft);
+	    if (IS_PIC_SOFT(pcibr_soft)) {
+		if (bridge->p_int_status_64 & (picreg_t)BRIDGE_ISR_PCIBUS_PIOERR)
+		    pcibr_error_dump(pcibr_soft);
+	    } else {
+		if (bridge->b_int_status & (bridgereg_t)BRIDGE_ISR_PCIBUS_PIOERR)
+		    pcibr_error_dump(pcibr_soft);
+	    }
 	    BEM_ADD_SPC(raw_space);
 	    BEM_ADD_VAR(raw_paddr);
 	    if (IOERROR_FIELDVALID(ioe, widgetdev)) {
-
-		slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, 
-								 widgetdev));
-		func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, 
-								 widgetdev));
-		if (slot < 8) {
+		short widdev;
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);
+		slot = pciio_widgetdev_slot_get(widdev);
+		func = pciio_widgetdev_func_get(widdev);
+		if (slot < PCIBR_NUM_SLOTS(pcibr_soft)) {
 		    bridgereg_t             device = bridge->b_device[slot].reg;
 
 		    BEM_ADD_VAR(slot);
@@ -1472,11 +1811,12 @@
 	 *      Need a way to ensure we don't inadvertently clear some
 	 *      other errors.
 	 */
-	if (IOERROR_FIELDVALID(ioe, widgetdev))
-	    pcibr_device_disable(pcibr_soft, 
-				 pciio_widgetdev_slot_get(
-					  IOERROR_GETVALUE(ioe, widgetdev)));
-
+	if (IOERROR_FIELDVALID(ioe, widgetdev)) {
+		short widdev;
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);
+		pcibr_device_disable(pcibr_soft, 
+				 pciio_widgetdev_slot_get(widdev));
+	}
 	if (mode == MODE_DEVUSERERROR)
 	    pcibr_error_cleanup(pcibr_soft, error_code);
     }
@@ -1490,8 +1830,6 @@
  *      and try to invoke the appropriate bus service to handle this.
  */
 
-#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT)
-
 int
 pcibr_dmard_error(
 		     pcibr_soft_t pcibr_soft,
@@ -1511,7 +1849,11 @@
      * Look up the address, in the bridge error registers, and
      * take appropriate action
      */
-    ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid);
+    {
+	short tmp;
+	IOERROR_GETVALUE(tmp, ioe, widgetnum);
+	ASSERT(tmp == pcibr_soft->bs_xid);
+    }
     ASSERT(bridge);
 
     /*
@@ -1540,10 +1882,11 @@
      */
 
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
-    if (retval != IOERROR_HANDLED)
-	pcibr_device_disable(pcibr_soft, 
-			     pciio_widgetdev_slot_get(
-				      IOERROR_GETVALUE(ioe,widgetdev)));
+    if (retval != IOERROR_HANDLED) {
+	short tmp;
+	IOERROR_GETVALUE(tmp, ioe, widgetdev);
+	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));
+    }
 
     /*
      * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR
@@ -1609,10 +1952,10 @@
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
 
     if (retval != IOERROR_HANDLED) {
-	pcibr_device_disable(pcibr_soft, 
-			     pciio_widgetdev_slot_get(
-				      IOERROR_GETVALUE(ioe, widgetdev)));
+	short tmp;
 
+	IOERROR_GETVALUE(tmp, ioe, widgetdev);
+	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));
     }
     return retval;
 }
@@ -1646,6 +1989,10 @@
 
     pcibr_soft = (pcibr_soft_t) einfo;
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+		"pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n",
+		pcibr_soft, error_code));
+
 #ifdef EHE_ENABLE
     xconn_vhdl = pcibr_soft->bs_conn;
     pcibr_vhdl = pcibr_soft->bs_vhdl;
@@ -1664,7 +2011,7 @@
 #endif /* EHE_ENABLE */
 
 #if DEBUG && ERROR_DEBUG
-    printk("%s: pcibr_error_handler\n", pcibr_soft->bs_name);
+    printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name);
 #endif
 
     ASSERT(pcibr_soft != NULL);
@@ -1704,6 +2051,159 @@
 }
 
 /*
+ * PIC has 2 busses under a single widget so pcibr_attach2 registers this
+ * wrapper function rather than pcibr_error_handler() for PIC.  It's upto
+ * this wrapper to call pcibr_error_handler() with the correct pcibr_soft
+ * struct (ie. the pcibr_soft struct for the bus that saw the error).
+ *
+ * NOTE: this wrapper function is only registered for PIC ASICs and will
+ * only be called for a PIC
+ */
+int
+pcibr_error_handler_wrapper(
+		       error_handler_arg_t einfo,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioe)
+{
+    pcibr_soft_t       pcibr_soft = (pcibr_soft_t) einfo;
+    int                pio_retval = -1; 
+    int		       dma_retval = -1;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_error_handler_wrapper: pcibr_soft=0x%x, "
+		"error_code=0x%x\n", pcibr_soft, error_code));
+
+    /*
+     * It is possible that both a IOECODE_PIO and a IOECODE_DMA, and both
+     * IOECODE_READ and IOECODE_WRITE could be set in error_code so we must
+     * process all.  Since we are a wrapper for pcibr_error_handler(), and
+     * will be calling it several times within this routine, we turn off the
+     * error_code bits we don't want it to be processing during that call.
+     */
+    /* 
+     * If the error was a result of a PIO, we tell what bus on the PIC saw
+     * the error from the PIO address.
+     */
+
+#if 0
+    if (mode == MODE_DEVPROBE)
+	pio_retval = IOERROR_HANDLED;
+    else {
+#endif
+    if (error_code & IOECODE_PIO) {
+	iopaddr_t               bad_xaddr;
+	/*
+	 * PIC bus0 PIO space 0x000000 - 0x7fffff or 0x40000000 - 0xbfffffff
+	 *     bus1 PIO space 0x800000 - 0xffffff or 0xc0000000 - 0x13fffffff
+	 */
+	IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);
+	if ((bad_xaddr <= 0x7fffff) ||
+	    ((bad_xaddr >= 0x40000000) && (bad_xaddr <= 0xbfffffff))) {
+	    /* bus 0 saw the error */
+	    pio_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~IOECODE_DMA), mode, ioe);
+	} else if (((bad_xaddr >= 0x800000) && (bad_xaddr <= 0xffffff)) ||
+	    ((bad_xaddr >= 0xc0000000) && (bad_xaddr <= 0x13fffffff))) {
+	    /* bus 1 saw the error */
+	    pcibr_soft = pcibr_soft->bs_peers_soft;
+	    if (!pcibr_soft) {
+#if DEBUG
+		printk(KERN_WARNING "pcibr_error_handler: "
+			"bs_peers_soft==NULL. bad_xaddr= 0x%x mode= 0x%x\n",
+						bad_xaddr, mode);
+#endif
+  		pio_retval = IOERROR_HANDLED;
+	    } else
+	        pio_retval= pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~IOECODE_DMA), mode, ioe);
+	} else {
+	    printk(KERN_WARNING "pcibr_error_handler_wrapper(): IOECODE_PIO: "
+		    "saw an invalid pio address: 0x%lx\n", bad_xaddr);
+	    pio_retval = IOERROR_UNHANDLED;
+	}
+    } 
+#if 0
+    } /* MODE_DEVPROBE */
+#endif
+
+    /* 
+     * If the error was a result of a DMA Write, we tell what bus on the PIC
+     * saw the error by looking at tnum.
+     */
+    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_WRITE)) {
+	short tmp;
+	/*
+         * For DMA writes [X]Bridge encodes the TNUM field of a Xtalk
+         * packet like this:
+         *              bits  value
+         *              4:3   10b
+         *              2:0   device number
+         *
+         * BUT PIC needs the bus number so it does this:
+         *              bits  value
+         *              4:3   10b
+         *              2     busnumber
+         *              1:0   device number
+	 *
+	 * Pull out the bus number from `tnum' and reset the `widgetdev'
+	 * since when hubiio_crb_error_handler() set `widgetdev' it had
+	 * no idea if it was a PIC or a BRIDGE ASIC so it set it based
+	 * off bits 2:0
+	 */
+	IOERROR_GETVALUE(tmp, ioe, tnum);
+	IOERROR_SETVALUE(ioe, widgetdev, (tmp & 0x3));
+	if ((tmp & 0x4) == 0) {
+	    /* bus 0 saw the error. */
+	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);
+	} else {
+	    /* bus 1 saw the error */
+	    pcibr_soft = pcibr_soft->bs_peers_soft;
+	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);
+	}
+    } 
+    
+    /* 
+     * If the error was a result of a DMA READ, XXX ???
+     */
+    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_READ)) {
+	/*
+	 * A DMA Read error will result in a BRIDGE_ISR_RESP_XTLK_ERR
+	 * or BRIDGE_ISR_BAD_XRESP_PKT bridge error interrupt which 
+	 * are fatal interrupts (ie. BRIDGE_ISR_ERROR_FATAL) causing
+	 * pcibr_error_intr_handler() to panic the system.  So is the
+	 * error handler even going to get called???  It appears that
+	 * the pcibr_dmard_error() attempts to clear the interrupts
+	 * so pcibr_error_intr_handler() won't see them, but there
+	 * appears to be nothing to prevent pcibr_error_intr_handler()
+	 * from running before pcibr_dmard_error() has a chance to
+	 * clear the interrupt.
+	 *
+	 * Since we'll be panicing anyways, don't bother handling the
+	 * error for now until we can fix this race condition mentioned
+	 * above.
+	 */
+	dma_retval = IOERROR_UNHANDLED;
+    } 
+    
+    /* XXX: pcibr_error_handler() should probably do the same thing, it over-
+     * write it's return value as it processes the different "error_code"s.
+     */
+    if ((pio_retval == -1) && (dma_retval == -1)) {
+    	return IOERROR_BADERRORCODE;
+    } else if (dma_retval != IOERROR_HANDLED) {
+	return dma_retval;
+    } else if (pio_retval != IOERROR_HANDLED) {
+	return pio_retval;
+    } else {
+	return IOERROR_HANDLED;
+    }
+}
+
+
+/*
  * Reenable a device after handling the error.
  * This is called by the lower layers when they wish to be reenabled
  * after an error.
@@ -1715,7 +2215,7 @@
 pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
 
     ASSERT(error_code & IOECODE_PIO);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c	2003-05-22 22:06:40.000000000 +0000
@@ -85,11 +85,9 @@
 
     if (hint)
 	hint->ph_rrb_fixed = mask;
-#if DEBUG
     else
-	printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_fix_rrbs: pcibr_hints_get failed\n"));
 }
 
 void
@@ -107,11 +105,9 @@
 
     if (hint)
 	hint->ph_host_slot[guest] = host + 1;
-#if DEBUG
     else
-	printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_dualslot: pcibr_hints_get failed\n"));
 }
 
 void
@@ -122,11 +118,9 @@
 
     if (hint)
 	hint->ph_intr_bits = xxx_intr_bits;
-#if DEBUG
     else
-	printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n"
-	       "\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_intr_bits: pcibr_hints_get failed\n"));
 }
 
 void
@@ -145,11 +139,9 @@
 
     if (hint)
 	hint->ph_hands_off = 1;
-#if DEBUG
     else
-	printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_handsoff: pcibr_hints_get failed\n"));
 }
 
 void
@@ -161,13 +153,11 @@
     char                    sdname[16];
     devfs_handle_t            pconn_vhdl = GRAPH_VERTEX_NONE;
 
-    sprintf(sdname, "pci/%d", slot);
+    sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot);
     (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl);
     if (pconn_vhdl == GRAPH_VERTEX_NONE) {
-#if DEBUG
-	printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n"
-		"\t%p (seeking %s)\n", xconn_vhdl, sdname);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_subdevs: hwgraph_path_create failed\n"));
 	return;
     }
     hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo);
@@ -176,10 +166,8 @@
 
 	NEW(subdevp);
 	if (!subdevp) {
-#if DEBUG
-	    printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n"
-		    "\t%p\n", pconn_vhdl);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+			"pcibr_hints_subdevs: subdev ptr alloc failed\n"));
 	    return;
 	}
 	*subdevp = subdevs;
@@ -189,16 +177,12 @@
 	    return;
 	DEL(subdevp);
 	if (ainfo == (arbitrary_info_t) NULL) {
-#if DEBUG
-	    printk("pcibr_hints_subdevs: null subdevs ptr at\n"
-		    "\t%p\n", pconn_vhdl);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+			"pcibr_hints_subdevs: null subdevs ptr\n"));
 	    return;
 	}
-#if DEBUG
-	printk("pcibr_subdevs_get: dup subdev add_LBL at\n"
-		"\t%p\n", pconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_subdevs_get: dup subdev add_LBL\n"));
     }
     *(uint64_t *) ainfo = subdevs;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2003-05-22 22:06:24.000000000 +0000
@@ -4,11 +4,10 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <asm/sn/sgi.h>
@@ -39,11 +38,11 @@
 #define rmalloc atealloc
 #endif
 
-unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);
+unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots);
 pcibr_intr_t            pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
 void                    pcibr_intr_free(pcibr_intr_t);
 void              pcibr_setpciint(xtalk_intr_t);
-int                     pcibr_intr_connect(pcibr_intr_t);
+int                     pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
 void                    pcibr_intr_disconnect(pcibr_intr_t);
 
 devfs_handle_t            pcibr_intr_cpu_get(pcibr_intr_t);
@@ -58,9 +57,9 @@
 
 unsigned
 pcibr_intr_bits(pciio_info_t info,
-		pciio_intr_line_t lines)
+		pciio_intr_line_t lines, int nslots)
 {
-    pciio_slot_t            slot = pciio_info_slot_get(info);
+    pciio_slot_t            slot = PCIBR_INFO_SLOT_GET_INT(info);
     unsigned		    bbits = 0;
 
     /*
@@ -79,7 +78,7 @@
      *      7       7 3 7 3
      */
 
-    if (slot < 8) {
+    if (slot < nslots) {
 	if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C))
 	    bbits |= 1 << slot;
 	if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D))
@@ -165,20 +164,26 @@
  *	to check if a specific Bridge b_int_status bit is set, and if so,
  *	cause the setting of the corresponding interrupt bit.
  *
- *	On a XBridge (IP35), we do this by writing the appropriate Bridge Force 
- *	Interrupt register.
+ *	On a XBridge (SN1), we do this by writing the appropriate Bridge Force 
+ *	Interrupt register. On SN0, or SN1 with an older Bridge, the Bridge 
+ *	Force Interrupt register does not exist, so we write the Hub 
+ *	INT_PEND_MOD register directly. Likewise for Octane, where we write the 
+ *	Heart Set Interrupt Status register directly.
  */
 void
 pcibr_force_interrupt(pcibr_intr_wrap_t wrap)
 {
+#ifdef PIC_LATER
 	unsigned	bit;
 	pcibr_soft_t    pcibr_soft = wrap->iw_soft;
 	bridge_t       *bridge = pcibr_soft->bs_base;
-	cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl);
 
-	bit = wrap->iw_intr;
+	bit = wrap->iw_ibit;
 
-	if (pcibr_soft->bs_xbridge) {
+	PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl,
+		    "pcibr_force_interrupt: bit=0x%x\n", bit));
+
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 	    bridge->b_force_pin[bit].intr = 1;
 	} else if ((1 << bit) & *wrap->iw_stat) {
 	    cpuid_t	    cpu;
@@ -187,11 +192,10 @@
 				pcibr_soft->bs_intr[bit].bsi_xtalk_intr;
 
 	    intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
-	    cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-#if defined(CONFIG_IA64_SGI_SN1)
+	    cpu = xtalk_intr_cpuid_get(xtalk_intr);
 	    REMOTE_CPU_SEND_INTR(cpu, intr_bit);
-#endif
 	}
+#endif	/* PIC_LATER */
 }
 
 /*ARGSUSED */
@@ -202,12 +206,11 @@
 		 devfs_handle_t owner_dev)
 {
     pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pcibr_info->f_slot;
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     is_threaded = 0;
-    int                     thread_swlevel;
 
     xtalk_intr_t           *xtalk_intr_p;
     pcibr_intr_t           *pcibr_intr_p;
@@ -222,41 +225,32 @@
     pcibr_intr_list_t       intr_list;
     bridgereg_t             int_dev;
 
-#if DEBUG && INTR_DEBUG
-    printk("%v: pcibr_intr_alloc\n"
-	    "%v:%s%s%s%s%s\n",
-	    owner_dev, pconn_vhdl,
-	    !(lines & 15) ? " No INTs?" : "",
-	    lines & 1 ? " INTA" : "",
-	    lines & 2 ? " INTB" : "",
-	    lines & 4 ? " INTC" : "",
-	    lines & 8 ? " INTD" : "");
-#endif
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+    		"pcibr_intr_alloc: %s%s%s%s%s\n",
+		!(lines & 15) ? " No INTs?" : "",
+		lines & 1 ? " INTA" : "",
+		lines & 2 ? " INTB" : "",
+		lines & 4 ? " INTC" : "",
+		lines & 8 ? " INTD" : ""));
 
     NEW(pcibr_intr);
     if (!pcibr_intr)
 	return NULL;
 
-    if (dev_desc) {
-	cpuid_t intr_target_from_desc(device_desc_t, int);
-    } else {
-	extern int default_intr_pri;
-
-	is_threaded = 1; /* PCI interrupts are threaded, by default */
-	thread_swlevel = default_intr_pri;
-    }
-
     pcibr_intr->bi_dev = pconn_vhdl;
     pcibr_intr->bi_lines = lines;
     pcibr_intr->bi_soft = pcibr_soft;
     pcibr_intr->bi_ibits = 0;		/* bits will be added below */
+    pcibr_intr->bi_func = 0;            /* unset until connect */
+    pcibr_intr->bi_arg = 0;             /* unset until connect */
     pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;
     pcibr_intr->bi_mustruncpu = CPU_NONE;
     pcibr_intr->bi_ibuf.ib_in = 0;
     pcibr_intr->bi_ibuf.ib_out = 0;
     mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock);
-
-    pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines);
+    pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines, 
+		PCIBR_NUM_SLOTS(pcibr_soft));
 
 
     /*
@@ -265,9 +259,8 @@
      * to, and make sure there are xtalk resources
      * allocated for it.
      */
-#if DEBUG && INTR_DEBUG
-    printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits);
-#endif 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+		"pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits));
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) {
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
 	    xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
@@ -282,10 +275,9 @@
 		 *    ordering problems with DMA, completion interrupts, and error
 		 *    interrupts. (Use of xconn_vhdl forces this.)
 		 *
-		 * 2) On IP35, addressing constraints on IP35 and Bridge force
+		 * 2) On SN1, addressing constraints on SN1 and Bridge force
 		 *    us to use a single PI number for all interrupts from a
-		 *    single Bridge. (IP35-specific code forces this, and we
-		 *    verify in pcibr_setwidint.)
+		 *    single Bridge. (SN1-specific code forces this).
 		 */
 
 		/*
@@ -298,9 +290,9 @@
 		 */
 		xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, 
 			owner_dev);
-#if DEBUG && INTR_DEBUG
-		printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr);
-#endif
+
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "pcibr_intr_alloc: xtalk_intr=0x%x\n", xtalk_intr));
 
 		/* both an assert and a runtime check on this:
 		 * we need to check in non-DEBUG kernels, and
@@ -338,10 +330,9 @@
 		    int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit);
 		    bridge->b_int_device = int_dev;	/* XXXMP */
 
-#if DEBUG && INTR_DEBUG
-		    printk("%v: bridge intr bit %d clears my wrb\n",
-			    pconn_vhdl, pcibr_int_bit);
-#endif
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+		    		"bridge intr bit %d clears my wrb\n",
+				pcibr_int_bit));
 		} else {
 		    /* someone else got one allocated first;
 		     * free the one we just created, and
@@ -373,25 +364,17 @@
 	    intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg);
 	    intr_list_p = 
 		&pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
-#if DEBUG && INTR_DEBUG
-#if defined(SUPPORT_PRINTING_V_FORMAT)
-	    printk("0x%x: Bridge bit %d wrap=0x%x\n",
-		pconn_vhdl, pcibr_int_bit,
-		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#else
-	    printk("%v: Bridge bit %d wrap=0x%x\n",
-		pconn_vhdl, pcibr_int_bit,
-		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#endif
-#endif
+
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			"Bridge bit 0x%x wrap=0x%x\n", pcibr_int_bit,
+			pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap));
 
 	    if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		/* we are the first interrupt on this bridge bit.
 		 */
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) allocated [FIRST]\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    intr_list = *intr_list_p;
@@ -402,10 +385,9 @@
 		 * don't need our intr_entry.
 		 */
 		DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) replaces erased first\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) replaces erased first\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    intr_list_p = &intr_list->il_next;
@@ -413,10 +395,9 @@
 		/* we are the new second interrupt on this bit.
 		 */
 		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1;
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) is new SECOND\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) is new SECOND\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    while (1) {
@@ -427,20 +408,19 @@
 		     * don't need our intr_entry.
 		     */
 		    DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
-		    printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n",
-			    pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+				"INT 0x%x (bridge bit %d) replaces erase Nth\n",
+				pcibr_int_bits, pcibr_int_bit));
 		    break;
 		}
 		intr_list_p = &intr_list->il_next;
 		if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		    /* entry appended to share list
 		     */
-#if DEBUG && INTR_DEBUG
-		    printk("%v INT 0x%x (bridge bit %d) is new Nth\n",
-			    pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+				"INT 0x%x (bridge bit %d) is new Nth\n",
+				pcibr_int_bits, pcibr_int_bit));
 		    break;
 		}
 		/* step to next record in chain
@@ -479,10 +459,11 @@
 		if (compare_and_swap_ptr((void **) &intr_list->il_intr, 
 					 pcibr_intr, 
 					 NULL)) {
-#if DEBUG && INTR_DEBUG
-		    printk("%s: cleared a handler from bit %d\n",
-			    pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, 
+				pcibr_intr->bi_dev,
+		    		"pcibr_intr_free: cleared hdlr from bit 0x%x\n",
+				pcibr_int_bit));
 		}
 	    /* If this interrupt line is not being shared between multiple
 	     * devices release the xtalk interrupt resources.
@@ -515,34 +496,49 @@
 void
 pcibr_setpciint(xtalk_intr_t xtalk_intr)
 {
-    iopaddr_t               addr = xtalk_intr_addr_get(xtalk_intr);
-    xtalk_intr_vector_t     vect = xtalk_intr_vector_get(xtalk_intr);
-    bridgereg_t            *int_addr = (bridgereg_t *)
-    xtalk_intr_sfarg_get(xtalk_intr);
-
-    *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
-		 (BRIDGE_INT_ADDR_FLD & vect));
+    iopaddr_t		 addr;
+    xtalk_intr_vector_t	 vect;
+    devfs_handle_t	 vhdl;
+    bridge_t		*bridge;
+
+    addr = xtalk_intr_addr_get(xtalk_intr);
+    vect = xtalk_intr_vector_get(xtalk_intr);
+    vhdl = xtalk_intr_dev_get(xtalk_intr);
+    bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0);
+
+    if (is_pic(bridge)) {
+	picreg_t	*int_addr;
+	int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+	*int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) |
+		     (PIC_INT_ADDR_HOST & addr));
+    } else {
+	bridgereg_t	*int_addr;
+	int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+	*int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
+		     (BRIDGE_INT_ADDR_FLD & vect));
+    }
 }
 
 /*ARGSUSED */
 int
-pcibr_intr_connect(pcibr_intr_t pcibr_intr)
+pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg)
 {
     pcibr_soft_t            pcibr_soft = pcibr_intr->bi_soft;
     bridge_t               *bridge = pcibr_soft->bs_base;
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
-    bridgereg_t             b_int_enable;
+    uint64_t		    int_enable;
     unsigned long           s;
 
     if (pcibr_intr == NULL)
 	return -1;
 
-#if DEBUG && INTR_DEBUG
-    printk("%v: pcibr_intr_connect\n",
-	    pcibr_intr->bi_dev);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+		"pcibr_intr_connect: intr_func=0x%x\n",
+		pcibr_intr));
 
+    pcibr_intr->bi_func = intr_func;
+    pcibr_intr->bi_arg = intr_arg;
     *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED;
 
     /*
@@ -553,9 +549,12 @@
      */
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+            pcibr_intr_wrap_t       intr_wrap;
 	    xtalk_intr_t            xtalk_intr;
+            void                   *int_addr;
 
 	    xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
 
 	    /*
 	     * If this interrupt line is being shared and the connect has
@@ -569,21 +568,43 @@
 	     * Use the pcibr wrapper function to handle all Bridge interrupts
 	     * regardless of whether the interrupt line is shared or not.
 	     */
-	    xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint,
-			       (void *)&(bridge->b_int_addr[pcibr_int_bit].addr));
+	    if (IS_PIC_SOFT(pcibr_soft)) 
+		int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+	    else
+		int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
+	    xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap,
+					(xtalk_intr_setfunc_t) pcibr_setpciint,
+			       			(void *)int_addr);
+
 	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;
 
-#if DEBUG && INTR_DEBUG
-	    printk("%v bridge bit %d wrapper connected\n",
-		    pcibr_intr->bi_dev, pcibr_int_bit);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, "
+			"pcibr_int_bit=0x%x\n", int_addr,
+			(is_pic(bridge) ? 
+			 *(picreg_t *)int_addr : *(bridgereg_t *)int_addr),
+			pcibr_int_bit));
 	}
-    s = pcibr_lock(pcibr_soft);
-    b_int_enable = bridge->b_int_enable;
-    b_int_enable |= pcibr_int_bits;
-    bridge->b_int_enable = b_int_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
-    pcibr_unlock(pcibr_soft, s);
+
+	/* PIC WAR. PV# 854697
+	 * On PIC we must write 64-bit MMRs with 64-bit stores
+	 */
+	s = pcibr_lock(pcibr_soft);
+	if (IS_PIC_SOFT(pcibr_soft) &&
+			PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+	    int_enable = bridge->p_int_enable_64;
+	    int_enable |= pcibr_int_bits;
+	    bridge->p_int_enable_64 = int_enable;
+	} else {
+	    bridgereg_t int_enable;
+
+	    int_enable = bridge->b_int_enable;
+	    int_enable |= pcibr_int_bits;
+	    bridge->b_int_enable = int_enable;
+	}
+	bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	pcibr_unlock(pcibr_soft, s);
 
     return 0;
 }
@@ -596,13 +617,15 @@
     bridge_t               *bridge = pcibr_soft->bs_base;
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
-    bridgereg_t             b_int_enable;
+    pcibr_intr_wrap_t       intr_wrap;
+    uint64_t                int_enable;
     unsigned long           s;
 
     /* Stop calling the function. Now.
      */
     *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED;
-
+    pcibr_intr->bi_func = 0;
+    pcibr_intr->bi_arg = 0;
     /*
      * For each PCI interrupt line requested, figure
      * out which Bridge PCI Interrupt Line it maps
@@ -619,15 +642,30 @@
     if (!pcibr_int_bits)
 	return;
 
+    /* PIC WAR. PV# 854697
+     * On PIC we must write 64-bit MMRs with 64-bit stores
+     */
     s = pcibr_lock(pcibr_soft);
-    b_int_enable = bridge->b_int_enable;
-    b_int_enable &= ~pcibr_int_bits;
-    bridge->b_int_enable = b_int_enable;
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+	int_enable = bridge->p_int_enable_64;
+	int_enable &= ~pcibr_int_bits;
+	bridge->p_int_enable_64 = int_enable;
+    } else {
+	int_enable = (uint64_t)bridge->b_int_enable;
+	int_enable &= ~pcibr_int_bits;
+	bridge->b_int_enable = (bridgereg_t)int_enable;
+    }
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
     pcibr_unlock(pcibr_soft, s);
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+		"pcibr_intr_disconnect: disabled int_bits=0x%x\n", 
+		pcibr_int_bits));
+
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+            void                   *int_addr;
+
 	    /* if the interrupt line is now shared,
 	     * do not disconnect it.
 	     */
@@ -637,10 +675,9 @@
 	    xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
 	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0;
 
-#if DEBUG && INTR_DEBUG
-	    printk("%s: xtalk disconnect done for Bridge bit %d\n",
-		pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_intr_disconnect: disconnect int_bits=0x%x\n",
+			pcibr_int_bits));
 
 	    /* if we are sharing the interrupt line,
 	     * connect us up; this closes the hole
@@ -650,9 +687,22 @@
 	    if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
 		continue;
 
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+            if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
+                continue;
+
+            if (IS_PIC_SOFT(pcibr_soft))
+                int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+            else
+                int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
 	    xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,
+				pcibr_intr_func, (intr_arg_t) intr_wrap,
 			       (xtalk_intr_setfunc_t)pcibr_setpciint,
-			       (void *) &(bridge->b_int_addr[pcibr_int_bit].addr));
+			       (void *)pcibr_int_bit);
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_intr_disconnect: now-sharing int_bits=0x%x\n",
+			pcibr_int_bit));
 	}
 }
 
@@ -729,6 +779,10 @@
     bridge->b_wid_int_upper = NEW_b_wid_int_upper;
     bridge->b_wid_int_lower = NEW_b_wid_int_lower;
     bridge->b_int_host_err = vect;
+
+printk("pcibr_setwidint: b_wid_int_upper 0x%x b_wid_int_lower 0x%x b_int_host_err 0x%x\n",
+	NEW_b_wid_int_upper, NEW_b_wid_int_lower, vect);
+
 }
 
 /*
@@ -752,6 +806,9 @@
 				   XTALK_ADDR_TO_UPPER(addr));
 	bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
 	bridge->b_int_host_err = vect;
+printk("pcibr_xintr_preset: b_wid_int_upper 0x%lx b_wid_int_lower 0x%lx b_int_host_err 0x%x\n",
+	( (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)),
+	XTALK_ADDR_TO_LOWER(addr), vect);
 
 	/* turn on all interrupts except
 	 * the PCI interrupt requests,
@@ -794,12 +851,37 @@
 {
     pcibr_intr_wrap_t       wrap = (pcibr_intr_wrap_t) arg;
     reg_p                   wrbf;
+    intr_func_t             func;
     pcibr_intr_t            intr;
     pcibr_intr_list_t       list;
     int                     clearit;
     int			    do_nonthreaded = 1;
     int			    is_threaded = 0;
     int			    x = 0;
+    pcibr_soft_t            pcibr_soft = wrap->iw_soft;
+    bridge_t               *bridge = pcibr_soft->bs_base;
+    uint64_t		    p_enable = pcibr_soft->bs_int_enable;
+    int			    bit = wrap->iw_ibit;
+
+	/*
+	 * PIC WAR.  PV#855272
+	 * Early attempt at a workaround for the runaway
+	 * interrupt problem.   Briefly disable the enable bit for
+	 * this device.
+	 */
+	if (IS_PIC_SOFT(pcibr_soft) &&
+			PCIBR_WAR_ENABLED(PV855272, pcibr_soft)) {
+		unsigned s;
+
+		/* disable-enable interrupts for this bridge pin */
+
+		p_enable &= ~(1 << bit);
+	        s = pcibr_lock(pcibr_soft);
+		bridge->p_int_enable_64 = p_enable;
+		p_enable |= (1 << bit);
+		bridge->p_int_enable_64 = p_enable;
+	        pcibr_unlock(pcibr_soft, s);
+	}
 
 	/*
 	 * If any handler is still running from a previous interrupt
@@ -821,35 +903,31 @@
 	clearit = 1;
 	while (do_nonthreaded) {
 	    for (list = wrap->iw_list; list != NULL; list = list->il_next) {
-		if ((intr = list->il_intr) &&
-		    (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
+		if ((intr = list->il_intr) && (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
 
-		/*
-		 * This device may have initiated write
-		 * requests since the bridge last saw
-		 * an edge on this interrupt input; flushing
-		 * the buffer prior to invoking the handler
-		 * should help but may not be sufficient if we 
-		 * get more requests after the flush, followed
-		 * by the card deciding it wants service, before
-		 * the interrupt handler checks to see if things need
-		 * to be done.
-		 *
-		 * There is a similar race condition if
-		 * an interrupt handler loops around and
-		 * notices further service is required.
-		 * Perhaps we need to have an explicit
-		 * call that interrupt handlers need to
-		 * do between noticing that DMA to memory
-		 * has completed, but before observing the
-		 * contents of memory?
-		 */
-
-			if ((do_nonthreaded) && (!is_threaded)) {
-			/* Non-threaded. 
-			 * Call the interrupt handler at interrupt level
-			 */
+		    /*
+		     * This device may have initiated write
+		     * requests since the bridge last saw
+		     * an edge on this interrupt input; flushing
+		     * the buffer prior to invoking the handler
+		     * should help but may not be sufficient if we 
+		     * get more requests after the flush, followed
+		     * by the card deciding it wants service, before
+		     * the interrupt handler checks to see if things need
+		     * to be done.
+		     *
+		     * There is a similar race condition if
+		     * an interrupt handler loops around and
+		     * notices further service is required.
+		     * Perhaps we need to have an explicit
+		     * call that interrupt handlers need to
+		     * do between noticing that DMA to memory
+		     * has completed, but before observing the
+		     * contents of memory?
+		     */
 
+		    if ((do_nonthreaded) && (!is_threaded)) {
+			/* Non-threaded -  Call the interrupt handler at interrupt level */
 			/* Only need to flush write buffers if sharing */
 
 			if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {
@@ -864,21 +942,23 @@
 				    (void *)list->il_intr->bi_dev, (long) wrbf);
 #endif
 			}
+			func = intr->bi_func;
+			if ( func )
+				func(intr->bi_arg);
 		    }
-
 		    clearit = 0;
 		}
 	    }
+	    do_nonthreaded = 0;
 
-		do_nonthreaded = 0;
-		/*
-		 * If the non-threaded handler was the last to complete,
-		 * (i.e., no threaded handlers still running) force an
-		 * interrupt to avoid a potential deadlock situation.
-		 */
-		if (wrap->iw_hdlrcnt == 0) {
-			pcibr_force_interrupt(wrap);
-		}
+	    /*
+	     * If the non-threaded handler was the last to complete,
+	     * (i.e., no threaded handlers still running) force an
+	     * interrupt to avoid a potential deadlock situation.
+	     */
+	    if (wrap->iw_hdlrcnt == 0) {
+		pcibr_force_interrupt(wrap);
+	    }
 	}
 
 	/* If there were no handlers,
@@ -892,14 +972,24 @@
 	if (clearit) {
 	    pcibr_soft_t            pcibr_soft = wrap->iw_soft;
 	    bridge_t               *bridge = pcibr_soft->bs_base;
-	    bridgereg_t             b_int_enable;
-	    bridgereg_t		    mask = 1 << wrap->iw_intr;
+	    bridgereg_t             int_enable;
+	    bridgereg_t		    mask = 1 << wrap->iw_ibit;
 	    unsigned long           s;
 
+	    /* PIC BRINUGP WAR (PV# 854697):
+	     * On PIC we must write 64-bit MMRs with 64-bit stores
+	     */
 	    s = pcibr_lock(pcibr_soft);
-	    b_int_enable = bridge->b_int_enable;
-	    b_int_enable &= ~mask;
-	    bridge->b_int_enable = b_int_enable;
+	    if (IS_PIC_SOFT(pcibr_soft) &&
+				PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+		int_enable = bridge->p_int_enable_64;
+		int_enable &= ~mask;
+		bridge->p_int_enable_64 = int_enable;
+	    } else {
+		int_enable = (uint64_t)bridge->b_int_enable;
+		int_enable &= ~mask;
+		bridge->b_int_enable = (bridgereg_t)int_enable;
+	    }
 	    bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
 	    pcibr_unlock(pcibr_soft, s);
 	    return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2003-05-22 22:06:27.000000000 +0000
@@ -33,259 +33,478 @@
 
 void              do_pcibr_rrb_clear(bridge_t *, int);
 void              do_pcibr_rrb_flush(bridge_t *, int);
-int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t);
+int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t, int);
 int               do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t);
-int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int);
-int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int);
+int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int, int);
+int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int, int);
+void		  do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t);
 
-void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int);
+void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);
 
 int		  pcibr_wrb_flush(devfs_handle_t);
 int               pcibr_rrb_alloc(devfs_handle_t, int *, int *);
 int               pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *);
-int               pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int);
 void              pcibr_rrb_flush(devfs_handle_t);
 int		  pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
 
-/* 
- *    RRB Management
- */
-
-#define LSBIT(word)		((word) &~ ((word)-1))
-
-void
-do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
-{
-    bridgereg_t             status;
-
-    /* bridge_lock must be held;
-     * this RRB must be disabled.
-     */
-
-    /* wait until RRB has no outstanduing XIO packets. */
-    while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
-	;				/* XXX- beats on bridge. bad idea? */
-    }
-
-    /* if the RRB has data, drain it. */
-    if (status & BRIDGE_RRB_VALID(rrb)) {
-	bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
-
-	/* wait until RRB is no longer valid. */
-	while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
-	    ;				/* XXX- beats on bridge. bad idea? */
-	}
-    }
-}
-
-void
-do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
-{
-    reg_p                   rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
-    bridgereg_t             rrbv;
-    int                     shft = 4 * (rrbn >> 1);
-    unsigned                ebit = BRIDGE_RRB_EN << shft;
-
-    rrbv = *rrbp;
-    if (rrbv & ebit)
-	*rrbp = rrbv & ~ebit;
-
-    do_pcibr_rrb_clear(bridge, rrbn);
-
-    if (rrbv & ebit)
-	*rrbp = rrbv;
-}
+void		  pcibr_rrb_debug(char *, pcibr_soft_t);
 
 /*
- *    pcibr_rrb_count_valid: count how many RRBs are
- *      marked valid for the specified PCI slot on this
- *      bridge.
- *
- *      NOTE: The "slot" parameter for all pcibr_rrb
- *      management routines must include the "virtual"
- *      bit; when manageing both the normal and the
- *      virtual channel, separate calls to these
- *      routines must be made. To denote the virtual
- *      channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot
- *      number.
- *
- *      IMPL NOTE: The obvious algorithm is to iterate
- *      through the RRB fields, incrementing a count if
- *      the RRB is valid and matches the slot. However,
- *      it is much simpler to use an algorithm derived
- *      from the "partitioned add" idea. First, XOR in a
- *      pattern such that the fields that match this
- *      slot come up "all ones" and all other fields
- *      have zeros in the mismatching bits. Then AND
- *      together the bits in the field, so we end up
- *      with one bit turned on for each field that
- *      matched. Now we need to count these bits. This
- *      can be done either with a series of shift/add
- *      instructions or by using "tmp % 15"; I expect
- *      that the cascaded shift/add will be faster.
- */
-
+ * RRB Management
+ *
+ * All the do_pcibr_rrb_ routines manipulate the Read Response Buffer (rrb)
+ * registers within the Bridge.	 Two 32 registers (b_rrb_map[2] also known
+ * as the b_even_resp & b_odd_resp registers) are used to allocate the 16
+ * rrbs to devices.  The b_even_resp register represents even num devices,
+ * and b_odd_resp represent odd number devices.	 Each rrb is represented by
+ * 4-bits within a register.
+ *   BRIDGE & XBRIDGE:	1 enable bit, 1 virtual channel bit, 2 device bits
+ *   PIC:		1 enable bit, 2 virtual channel bits, 1 device bit
+ * PIC has 4 devices per bus, and 4 virtual channels (1 normal & 3 virtual)
+ * per device.	BRIDGE & XBRIDGE have 8 devices per bus and 2 virtual
+ * channels (1 normal & 1 virtual) per device.	See the BRIDGE and PIC ASIC
+ * Programmers Reference guides for more information.
+ */ 
+ 
+#define RRB_MASK (0xf)			/* mask a single rrb within reg */
+#define RRB_SIZE (4)			/* sizeof rrb within reg (bits) */
+ 
+#define RRB_ENABLE_BIT(bridge)		(0x8)  /* [BRIDGE | PIC]_RRB_EN */
+#define NUM_PDEV_BITS(bridge)		(is_pic((bridge)) ? 1 : 2)
+#define NUM_VDEV_BITS(bridge)		(is_pic((bridge)) ? 2 : 1)
+#define NUMBER_VCHANNELS(bridge)	(is_pic((bridge)) ? 4 : 2)
+#define SLOT_2_PDEV(bridge, slot)	((slot) >> 1)
+#define SLOT_2_RRB_REG(bridge, slot)	((slot) & 0x1)
+ 
+/* validate that the slot and virtual channel are valid for a given bridge */
+#define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \
+  (is_pic((bridge)) ? \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0))
+ 
+/*  
+ * Count how many RRBs are marked valid for the specified PCI slot
+ * and virtual channel.	 Return the count.
+ */ 
 int
 do_pcibr_rrb_count_valid(bridge_t *bridge,
-			 pciio_slot_t slot)
+			 pciio_slot_t slot,
+			 int vchan)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index, cnt=0;
+
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan);
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+    
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp ^= 0x11111111 * (7 - slot / 2);
-    tmp &= (0xCCCCCCCC & tmp) >> 2;
-    tmp &= (0x22222222 & tmp) >> 1;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_count_avail: count how many RRBs are
- *      available to be allocated for the specified slot.
- *
- *      IMPL NOTE: similar to the above, except we are
- *      just counting how many fields have the valid bit
- *      turned off.
- */
+ 
+ 
+/*  
+ * Count how many RRBs are available to be allocated to the specified
+ * slot.  Return the count.
+ */ 
 int
 do_pcibr_rrb_count_avail(bridge_t *bridge,
 			 pciio_slot_t slot)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit;
+    int rrb_index, cnt=0;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, 0)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan");
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~tmp) >> 3;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_alloc: allocate some additional RRBs
- *      for the specified slot. Returns -1 if there were
- *      insufficient free RRBs to satisfy the request,
- *      or 0 if the request was fulfilled.
- *
- *      Note that if a request can be partially filled,
- *      it will be, even if we return failure.
- *
- *      IMPL NOTE: again we avoid iterating across all
- *      the RRBs; instead, we form up a word containing
- *      one bit for each free RRB, then peel the bits
- *      off from the low end.
- */
+ 
+ 
+/*  
+ * Allocate some additional RRBs for the specified slot and the specified
+ * virtual channel.  Returns -1 if there were insufficient free RRBs to
+ * satisfy the request, or 0 if the request was fulfilled.
+ *
+ * Note that if a request can be partially filled, it will be, even if
+ * we return failure.
+ */ 
 int
 do_pcibr_rrb_alloc(bridge_t *bridge,
 		   pciio_slot_t slot,
+		   int vchan,
 		   int more)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, bit;
+    bridgereg_t reg, tmp = (bridgereg_t)0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit) {
+	    /* clear the rrb and OR in the new rrb into 'reg' */
+	    reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    reg = reg | (rrb_bits << (RRB_SIZE * rrb_index));
+	    more--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    reg = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~reg) >> 3;
-    while (more-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
 	}
-	tmp &= ~bit;
-	reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2)));
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
-    return rv;
+    return (more ? -1 : 0);
 }
-
-/*
- *    do_pcibr_rrb_free: release some of the RRBs that
- *      have been allocated for the specified
- *      slot. Returns zero for success, or negative if
- *      it was unable to free that many RRBs.
- *
- *      IMPL NOTE: We form up a bit for each RRB
- *      allocated to the slot, aligned with the VALID
- *      bitfield this time; then we peel bits off one at
- *      a time, releasing the corresponding RRB.
- */
+ 
+ 
+/*  
+ * Release some of the RRBs that have been allocated for the specified
+ * slot. Returns zero for success, or negative if it was unable to free
+ * that many RRBs.
+ *
+ * Note that if a request can be partially fulfilled, it will be, even
+ * if we return failure.
+ */ 
 int
 do_pcibr_rrb_free(bridge_t *bridge,
 		  pciio_slot_t slot,
+		  int vchan,
 		  int less)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, clr, bit;
-    int                     i;
+    bridgereg_t reg, tmp = (bridgereg_t)0, clr = 0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits) {
+	   /*
+	    * the old do_pcibr_rrb_free() code only clears the enable bit
+	    * but I say we should clear the whole rrb (ie):
+	    *	  reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    * But to be compatable with old code we'll only clear enable.
+	    */
+	    reg = reg & ~(RRB_ENABLE_BIT(bridge) << (RRB_SIZE * rrb_index));
+	    clr = clr | (enable_bit << (RRB_SIZE * rrb_index));
+	    less--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    clr = 0;
-    reg = bridge->b_rrb_map[slot & 1].reg;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+	}
+    }
 
-    /* This needs to be done otherwise the rrb's on the virtual channel
-     * for this slot won't be freed !!
+    /* call do_pcibr_rrb_clear() for all the rrbs we've freed */
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if (clr & (enable_bit << (RRB_SIZE * rrb_index)))
+	    do_pcibr_rrb_clear(bridge, (2 * rrb_index) + evn_odd);
+    }
+    
+    return (less ? -1 : 0);
+}
+ 
+  
+/*  
+ * free all the rrbs (both the normal and virtual channels) for the
+ * specified slot.
+ */ 
+void
+do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft,
+		      bridge_t *bridge,
+		      pciio_slot_t slot)
+{
+    int vchan;
+    int vchan_total = NUMBER_VCHANNELS(bridge);
+    
+    /* pretend we own all 8 rrbs and just ignore the return value */
+    for (vchan = 0; vchan < vchan_total; vchan++) {
+	    (void)do_pcibr_rrb_free(bridge, slot, vchan, 8);
+	    pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+    }
+}
+ 
+ 
+/*
+ * Wait for the the specified rrb to have no outstanding XIO pkts
+ * and for all data to be drained.  Mark the rrb as no longer being 
+ * valid.
+ */
+void
+do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
+{
+    bridgereg_t             status;
+
+    /* bridge_lock must be held;
+     * this RRB must be disabled.
      */
-    tmp = reg & 0xbbbbbbbb;
 
-    tmp ^= (0x11111111 * (7 - slot / 2));
-    tmp &= (0x33333333 & tmp) << 2;
-    tmp &= (0x44444444 & tmp) << 1;
-    while (less-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	/* wait until RRB has no outstanduing XIO packets. */
+	while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+		;				/* XXX- beats on bridge. bad idea? */
+	}
+
+	/* if the RRB has data, drain it. */
+	if (status & BRIDGE_RRB_VALID(rrb)) {
+		bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+
+		/* wait until RRB is no longer valid. */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+			;				/* XXX- beats on bridge. bad idea? */
+		}
+	}
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb));
+
+			/* wait until RRB is no longer valid. */
+			while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	} else { /* io_get_sh_swapper(NASID_GET(bridge)) */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+			/* wait until RRB is no longer valid. */
+			while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	}
+    }
+}
+
+
+/* 
+ * Flush the specified rrb by calling do_pcibr_rrb_clear().  This
+ * routine is just a wrapper to make sure the rrb is disabled 
+ * before calling do_pcibr_rrb_clear().
+ */
+void
+do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
+{
+    reg_p	 rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
+    bridgereg_t	 rrbv;
+    int		 shft = (RRB_SIZE * (rrbn >> 1));
+    unsigned long	 ebit = RRB_ENABLE_BIT(bridge) << shft;
+
+    if ( is_pic(bridge) ) {
+	rrbv = *rrbp;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		rrbv = BRIDGE_REG_GET32((&rrbp));
+	} else {
+		rrbv = *rrbp;
+	}
+    }
+
+    if (rrbv & ebit) {
+    	if ( is_pic(bridge) ) {
+		*rrbp = rrbv & ~ebit;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit));
+		} else {
+			*rrbp = rrbv & ~ebit;
+		}
 	}
-	tmp &= ~bit;
-	reg &= ~bit;
-	clr |= bit;
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
 
-    for (i = 0; i < 8; i++)
-	if (clr & (8 << (4 * i)))
-	    do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1));
+    do_pcibr_rrb_clear(bridge, rrbn);
 
-    return rv;
+    if (rrbv & ebit) {
+	if ( is_pic(bridge) ) {
+		*rrbp = rrbv;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv);
+		} else {
+			*rrbp = rrbv;
+		}
+	}
+    }
 }
 
+
 void
 do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft,
 		       int slot,
+		       int vchan, 
 		       int more_rrbs)
 {
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     got;
 
     for (got = 0; got < more_rrbs; ++got) {
-	if (pcibr_soft->bs_rrb_res[slot & 7] > 0)
-	    pcibr_soft->bs_rrb_res[slot & 7]--;
+	if (pcibr_soft->bs_rrb_res[slot] > 0)
+	    pcibr_soft->bs_rrb_res[slot]--;
 	else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0)
 	    pcibr_soft->bs_rrb_avail[slot & 1]--;
 	else
 	    break;
-	if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0)
+	if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0)
 	    break;
-#if PCIBR_RRB_DEBUG
-	printk("do_pcibr_rrb_autoalloc: add one to slot %d%s\n",
-		slot & 7, slot & 8 ? "v" : "");
-#endif
-	pcibr_soft->bs_rrb_valid[slot]++;
-    }
-#if PCIBR_RRB_DEBUG
-    printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name,
-	    pcibr_soft->bs_rrb_avail[0],
-	    pcibr_soft->bs_rrb_avail[1]);
-    for (slot = 0; slot < 8; ++slot)
-	printk("\t%d+%d+%d",
-		0xFFF & pcibr_soft->bs_rrb_valid[slot],
-		0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-		pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+
+	pcibr_soft->bs_rrb_valid[slot][vchan]++;
+    }
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		"do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs "
+		"to slot %d, vchan %d\n", got, more_rrbs, 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan));
+
+    pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft);
 }
 
+
+/*
+ * Flush all the rrb's assigned to the specified connection point.
+ */
+void
+pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t  pciio_info = pciio_info_get(pconn_vhdl);
+    pcibr_soft_t  pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info);
+    pciio_slot_t  slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
+    bridge_t	 *bridge = pcibr_soft->bs_base;
+
+    bridgereg_t tmp;
+    uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask;
+    int rrb_index;
+    unsigned long s;
+
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | pdev_bits;
+    rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1);
+
+    tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+
+    s = pcibr_lock(pcibr_soft);
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if ((tmp & rrb_mask) == rrb_bits)
+	    do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd);
+	tmp = (tmp >> RRB_SIZE);
+    }
+    pcibr_unlock(pcibr_soft, s);
+}
+
+
 /*
  * Device driver interface to flush the write buffers for a specified
  * device hanging off the bridge.
@@ -294,14 +513,24 @@
 pcibr_wrb_flush(devfs_handle_t pconn_vhdl)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     volatile bridgereg_t   *wrb_flush;
 
     wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg);
-    while (*wrb_flush);
-
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	while (*wrb_flush)
+		;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while (BRIDGE_REG_GET32((wrb_flush)));
+	} else {
+		while (*wrb_flush)
+			;
+	}
+    }
     return(0);
 }
 
@@ -322,7 +551,7 @@
 		int *count_vchan1)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     desired_vchan0;
@@ -335,7 +564,9 @@
     int                     final_vchan1;
     int                     avail_rrbs;
     int                     res_rrbs;
-    unsigned long           s;
+    int			    vchan_total;
+    int			    vchan;
+    unsigned long                s;
     int                     error;
 
     /*
@@ -352,20 +583,21 @@
 
     s = pcibr_lock(pcibr_soft);
 
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
     /* Save the boot-time RRB configuration for this slot */
-    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] < 0) {
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot] =
-                pcibr_soft->bs_rrb_valid[pciio_slot]; 
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] =
-                pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) {
+	for (vchan = 0; vchan < vchan_total; vchan++) 
+	    pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] =
+		    pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
         pcibr_soft->bs_rrb_res_dflt[pciio_slot] =
                 pcibr_soft->bs_rrb_res[pciio_slot];
                   
     }
 
     /* How many RRBs do we own? */
-    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot];
-    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
+    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
     /* How many RRBs do we want? */
     desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0;
@@ -417,14 +649,14 @@
 	/* Commit the allocations: free, then alloc.
 	 */
 	if (delta_vchan0 < 0)
-	    (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0);
 	if (delta_vchan1 < 0)
-	    (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1);
 
 	if (delta_vchan0 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0);
 	if (delta_vchan1 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1);
 
 	/* Return final values to caller.
 	 */
@@ -442,8 +674,8 @@
 	 * number of available RRBs.
 	 */
 
-	pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0;
-	pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1;
 	pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
 	    pcibr_soft->bs_rrb_avail[pciio_slot & 1]
 	    + pcibr_soft->bs_rrb_res[pciio_slot]
@@ -455,34 +687,21 @@
          * Reserve enough RRBs so this slot's RRB configuration can be
          * reset to its boot-time default following a hot-plug shut-down
          */
-        res_rrbs =   (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot]) 
-                   + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot +
-                                                    PCIBR_RRB_SLOT_VIRTUAL] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot +
-                                               PCIBR_RRB_SLOT_VIRTUAL])
-                   + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_res[pciio_slot]);
-
-         if (res_rrbs > 0) {
-             pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
-             pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
-                 pcibr_soft->bs_rrb_avail[pciio_slot & 1]
-                 - res_rrbs;
-         }
- 
-#if PCIBR_RRB_DEBUG
-	printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n",
-		pciio_slot, final_vchan0, final_vchan1,
-		pcibr_soft->bs_rrb_avail[0],
-		pcibr_soft->bs_rrb_avail[1]);
-	for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot)
-	    printk("\t%d+%d+%d",
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot],
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL],
+	res_rrbs = (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
 		    pcibr_soft->bs_rrb_res[pciio_slot]);
-	printk("\n");
-#endif
+	for (vchan = 0; vchan < vchan_total; vchan++) {
+	    res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] -
+			 pcibr_soft->bs_rrb_valid[pciio_slot][vchan]);
+	}
+
+	if (res_rrbs > 0) {
+            pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
+            pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
+                pcibr_soft->bs_rrb_avail[pciio_slot & 1]
+                - res_rrbs;
+        }
+ 
+	pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft);
 
 	error = 0;
     }
@@ -543,22 +762,22 @@
     pciio_info_t            pciio_info;
     pciio_slot_t            pciio_slot;
     pcibr_soft_t            pcibr_soft;
-    unsigned long           s;
+    unsigned long                s;
     int                     error = -1;
 
     if ((pciio_info = pciio_info_get(pconn_vhdl)) &&
 	(pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) &&
-	((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) {
+	((pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) {
 
 	s = pcibr_lock(pcibr_soft);
 
 	if (count_vchan0)
 	    *count_vchan0 =
-		pcibr_soft->bs_rrb_valid[pciio_slot];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
 
 	if (count_vchan1)
 	    *count_vchan1 =
-		pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
 	if (count_reserved)
 	    *count_reserved =
@@ -575,159 +794,6 @@
     return error;
 }
 
-/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities
- * requested for each of the devices.  The evn_odd argument indicates whether
- * allocation is for the odd or even rrbs. The next group of four argument
- * pairs indicate the amount of rrbs to be assigned to each device. The first
- * argument of each pair indicate the total number of rrbs to allocate for that
- * device. The second argument of each pair indicates how many rrb's from the
- * first argument should be assigned to the virtual channel. The total of all
- * of the first arguments should be <= 8. The second argument should be <= the
- * first argument.
- * if even_odd = 0 the devices in order are 0, 2, 4, 6 
- * if even_odd = 1 the devices in order are 1, 3, 5, 7
- * returns 0 if no errors else returns -1
- */
-
-int
-pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd,
-		     int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2,
-		     int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4)
-{
-    devfs_handle_t          pcibr_vhdl;
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t)0;
-    bridge_t               *bridge = NULL;
-
-    uint32_t                rrb_setting = 0;
-    int                     rrb_shift = 7;
-    uint32_t                cur_rrb;
-    int                     dev_rrbs[4];
-    int                     virt[4];
-    int                     i, j;
-    unsigned long           s;
-
-    if (GRAPH_SUCCESS ==
-	hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) {
-	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-	if (pcibr_soft)
-	    bridge = pcibr_soft->bs_base;
-	hwgraph_vertex_unref(pcibr_vhdl);
-    }
-    if (bridge == NULL)
-	bridge = (bridge_t *) xtalk_piotrans_addr
-	    (vhdl, NULL, 0, sizeof(bridge_t), 0);
-
-    even_odd &= 1;
-
-    dev_rrbs[0] = dev_1_rrbs;
-    dev_rrbs[1] = dev_2_rrbs;
-    dev_rrbs[2] = dev_3_rrbs;
-    dev_rrbs[3] = dev_4_rrbs;
-
-    virt[0] = virt1;
-    virt[1] = virt2;
-    virt[2] = virt3;
-    virt[3] = virt4;
-
-    if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) {
-	return -1;
-    }
-    if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) {
-	return -1;
-    }
-    /* walk through rrbs */
-    for (i = 0; i < 4; i++) {
-	if (virt[i]) {
-		for( j = 0; j < virt[i]; j++) {
-			cur_rrb = i | 0xc;
-			cur_rrb = cur_rrb << (rrb_shift * 4);
-			rrb_shift--;
-			rrb_setting = rrb_setting | cur_rrb;
-			dev_rrbs[i] = dev_rrbs[i] - 1;
-		}
-	}
-	for (j = 0; j < dev_rrbs[i]; j++) {
-	    cur_rrb = i | 0x8;
-	    cur_rrb = cur_rrb << (rrb_shift * 4);
-	    rrb_shift--;
-	    rrb_setting = rrb_setting | cur_rrb;
-	}
-    }
-
-    if (pcibr_soft)
-	s = pcibr_lock(pcibr_soft);
-
-    bridge->b_rrb_map[even_odd].reg = rrb_setting;
-
-    if (pcibr_soft) {
-
-	pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd;
-
-	/* since we've "FIXED" the allocations
-	 * for these slots, we probably can dispense
-	 * with tracking avail/res/valid data, but
-	 * keeping it up to date helps debugging.
-	 */
-
-	pcibr_soft->bs_rrb_avail[even_odd] =
-	    8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs);
-
-	pcibr_soft->bs_rrb_res[even_odd + 0] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 2] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 4] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 6] = 0;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4;
-
-	pcibr_unlock(pcibr_soft, s);
-    }
-    return 0;
-}
-
-/*
- *    pcibr_rrb_flush: chase down all the RRBs assigned
- *      to the specified connection point, and flush
- *      them.
- */
-void
-pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
-{
-    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
-    bridge_t               *bridge = pcibr_soft->bs_base;
-    unsigned long           s;
-    reg_p                   rrbp;
-    unsigned                rrbm;
-    int                     i;
-    int                     rrbn;
-    unsigned                sval;
-    unsigned                mask;
-
-    sval = BRIDGE_RRB_EN | (pciio_slot >> 1);
-    mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV;
-    rrbn = pciio_slot & 1;
-    rrbp = &bridge->b_rrb_map[rrbn].reg;
-
-    s = pcibr_lock(pcibr_soft);
-    rrbm = *rrbp;
-    for (i = 0; i < 8; ++i) {
-	if ((rrbm & mask) == sval)
-	    do_pcibr_rrb_flush(bridge, rrbn);
-	rrbm >>= 4;
-	rrbn += 2;
-    }
-    pcibr_unlock(pcibr_soft, s);
-}
-
 /*
  * pcibr_slot_initial_rrb_alloc
  *	Allocate a default number of rrbs for this slot on 
@@ -743,75 +809,82 @@
     pcibr_info_h	 pcibr_infoh;
     pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    int                  c0, c1, r;
+    int 		 vchan_total;
+    int			 vchan;
+    int                  chan[4];
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    /* How may RRBs are on this slot?
-     */
-    c0 = do_pcibr_rrb_count_valid(bridge, slot);
-    c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL);
+    bridge = pcibr_soft->bs_base;
 
-#if PCIBR_RRB_DEBUG
-    printk(
+    /* How many RRBs are on this slot? */
+    vchan_total = NUMBER_VCHANNELS(bridge);
+    for (vchan = 0; vchan < vchan_total; vchan++) 
+        chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan);
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+ 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
+	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n",
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3]));
+    } else {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
 	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n",
-            slot, c0, c1);
-#endif
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1]));
+    }
 
     /* Do we really need any?
      */
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
     pcibr_info = pcibr_infoh[0];
-    if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
-	!pcibr_soft->bs_slot[slot].has_host) {
-	if (c0 > 0)
-	    do_pcibr_rrb_free(bridge, slot, c0);
-	if (c1 > 0)
-	    do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1);
-	pcibr_soft->bs_rrb_valid[slot] = 0x1000;
-	pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000;
-	return(ENODEV);
-    }
 
-    pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1;
-    pcibr_soft->bs_rrb_valid[slot] = c0;
-    pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1;
-
-    pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0);
-    pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1);
+    if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && IS_PIC_SOFT(pcibr_soft) &&
+                        (slot == 2 || slot == 3) &&
+                        (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
+                        !pcibr_soft->bs_slot[slot].has_host) {
+
+        for (vchan = 0; vchan < 2; vchan++) {
+            do_pcibr_rrb_free(bridge, slot, vchan, 8);
+            pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+        }
 
-    r = 3 - (c0 + c1);
+        pcibr_soft->bs_rrb_valid[slot][3] = chan[3];
 
-    if (r > 0) {
-	pcibr_soft->bs_rrb_res[slot] = r;
-	pcibr_soft->bs_rrb_avail[slot & 1] -= r;
+        return(ENODEV);
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("\t%d+%d+%d",
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot],
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    for (vchan = 0; vchan < vchan_total; vchan++)
+        pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan];
 
     return(0);
 }
 
+void
+rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot)
+{
+        int res = pcibr_soft->bs_rrb_res[slot];
+
+        if (res) {
+                 pcibr_soft->bs_rrb_avail[slot & 1] += res;
+                 pcibr_soft->bs_rrb_res[slot] = 0;
+        }
+}
+
 /*
  * pcibr_initial_rrb
  *      Assign an equal total number of RRBs to all candidate slots, 
  *      where the total is the sum of the number of RRBs assigned to
  *      the normal channel, the number of RRBs assigned to the virtual
- *      channel, and the number of RRBs assigned as reserved. 
+ *      channels, and the number of RRBs assigned as reserved. 
  *
- *      A candidate slot is a populated slot on a non-SN1 system or 
- *      any existing (populated or empty) slot on an SN1 system.
+ *      A candidate slot is any existing (populated or empty) slot.
  *      Empty SN1 slots need RRBs to support hot-plug operations.
  */
 
@@ -822,7 +895,9 @@
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t               *bridge = pcibr_soft->bs_base;
     pciio_slot_t            slot;
-    int                     c0, c1;
+    int			    rrb_total;
+    int			    vchan_total;
+    int			    vchan;
     int                     have[2][3];
     int                     res[2];
     int                     eo;
@@ -831,16 +906,21 @@
     have[1][0] = have[1][1] = have[1][2] = 0;
     res[0] = res[1] = 0;
 
-    for (slot = 0; slot < 8; ++slot) {
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
+    for (slot = pcibr_soft->bs_min_slot; 
+			slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
         /* Initial RRB management; give back RRBs in all non-existent slots */
         (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
 
         /* Base calculations only on existing slots */
         if ((slot >= first) && (slot <= last)) {
-            c0 = pcibr_soft->bs_rrb_valid[slot];
-            c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-            if ((c0 + c1) < 3)
-                have[slot & 1][c0 + c1]++;
+	    rrb_total = 0;
+	    for (vchan = 0; vchan < vchan_total; vchan++) 
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+            if (rrb_total < 3)
+                have[slot & 1][rrb_total]++;
         }
     }
 
@@ -867,30 +947,70 @@
     for (slot = first; slot <= last; ++slot) {
         int                     r;
 
-        c0 = pcibr_soft->bs_rrb_valid[slot];
-        c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-        r = res[slot & 1] - (c0 + c1);
+	rrb_total = 0;
+	for (vchan = 0; vchan < vchan_total; vchan++)
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+        r = res[slot & 1] - (rrb_total);
 
         if (r > 0) {
             pcibr_soft->bs_rrb_res[slot] = r;
             pcibr_soft->bs_rrb_avail[slot & 1] -= r;
-            }
+        }
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("%v RRB MANAGEMENT: %d+%d free\n",
-            pcibr_vhdl,
-            pcibr_soft->bs_rrb_avail[0],
-            pcibr_soft->bs_rrb_avail[1]);
-    for (slot = first; slot <= last; ++slot)
-        printk("\tslot %d: %d+%d+%d", slot,
-                0xFFF & pcibr_soft->bs_rrb_valid[slot],
-                0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-                pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft);
 
     return 0;
 
 }
 
+/*
+ * Dump the pcibr_soft_t RRB state variable
+ */
+void
+pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft)
+{
+    pciio_slot_t slot;
+    char tmp_str[256];
+    
+    if (pcibr_debug_mask & PCIBR_DEBUG_RRB) {
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                    "%s: rrbs available, even=%d, odd=%d\n", calling_func,
+                    pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]));
+
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n"));
+        } else {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		        "\tslot\tvchan0\tvchan1\treserved\n"));
+        }
+
+        for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) {
+	    /*
+             * The kernel only allows functions to have so many variable args,
+             * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf
+             * arguments fails so sprintf() it into a temporary string.
+             */
+	    if (IS_PIC_SOFT(pcibr_soft)) {
+                sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3],
+                        pcibr_soft->bs_rrb_res[slot]);
+	    } else {
+	        sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+		        pcibr_soft->bs_rrb_res[slot]);
+	    }
+    
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "%s", tmp_str));
+        }
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c	2003-05-22 22:06:38.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
@@ -30,70 +31,90 @@
 #include <asm/sn/eeprom.h>
 #include <asm/sn/io.h>
 #include <asm/sn/sn_private.h>
+#include <asm/sn/ate_utils.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
 
 extern pcibr_info_t     pcibr_info_get(devfs_handle_t);
-extern int              pcibr_widget_to_bus(int);
+extern int              pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl);
 extern pcibr_info_t     pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
-extern void             pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
 extern int		pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
-#if 0
-int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-#endif
+extern int		pcibr_pcix_rbars_calc(pcibr_soft_t);
 
 int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
+int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,  pciio_slot_t slot);
 int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
 int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
-int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags);
+int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
+                 int drv_flags, char *l1_msg, int *sub_errorp);
 int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
-void		 pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
-extern uint64_t  do_pcibr_config_get(cfg_p, unsigned, unsigned);
+static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
+void pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
+iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, 
+                               pciio_space_t, int, int, int);
+void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t);
+cfg_p pcibr_find_capability(cfg_p, unsigned);
+extern uint64_t  do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
+void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); 
 
-#ifdef LATER
 int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
                 int drv_flags, char *l1_msg, int *sub_errorp);
-int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *);
-int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
-int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
-void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func,
-                 pcibr_slot_func_info_resp_t funcp);
+
 int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot,
                  pcibr_slot_info_resp_t respp);
-int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
-#endif	/* LATER */
 
 extern devfs_handle_t baseio_pci_vhdl;
 int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t);
 
+
 /* For now .... */
 /*
  * PCI Hot-Plug Capability Flags
+
  */
 #define D_PCI_HOT_PLUG_ATTACH  0x200  /* Driver supports PCI hot-plug attach */
 #define D_PCI_HOT_PLUG_DETACH  0x400  /* Driver supports PCI hot-plug detach */
 
 
+/* 
+ * PCI-X Max Outstanding Split Transactions translation array and Max Memory
+ * Read Byte Count translation array, as defined in the PCI-X Specification.
+ * Section 7.2.3 & 7.2.4 of PCI-X Specification - rev 1.0
+ */
+#define MAX_SPLIT_TABLE 8
+#define MAX_READCNT_TABLE 4
+int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32};
+int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 };
+
+
 /*==========================================================================
  *	BRIDGE PCI SLOT RELATED IOCTLs
  */
 
-#ifdef LATER
-
 /*
  * pcibr_slot_startup
  *	Software start-up the PCI slot.
  */
+
+#ifdef PIC_LATER
+
 int
 pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_up_resp_s    tmp_up_resp;
@@ -103,17 +124,22 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     /* Do not allow start-up of a slot in a shoehorn */
     if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
        return(PCI_SLOT_IN_SHOEHORN);
     }
  
     /* Check for the valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) {
         error = PCI_SLOT_ALREADY_UP;
@@ -132,9 +158,10 @@
 
     startup_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
     return(error);
 }
 
@@ -147,7 +174,7 @@
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t                      *bridge;
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_down_resp_s  tmp_down_resp;
@@ -158,10 +185,13 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     bridge = pcibr_soft->bs_base;
 
     /* Check for valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
     /* Do not allow shut-down of a slot in a shoehorn */
@@ -169,8 +199,10 @@
        return(PCI_SLOT_IN_SHOEHORN);
     }
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) ||
         ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) {
@@ -182,6 +214,13 @@
         goto shutdown_unlock;
     }
 
+    /* Do not allow a multi-function card to be hot-plug removed */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        tmp_down_resp.resp_sub_errno = EPERM;
+        error = PCI_MULTI_FUNC_ERR;
+        goto shutdown_copyout;
+    }
+
     /* Do not allow the last 33 MHz card to be removed */
     if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) ==
          BRIDGE_CTRL_BUS_SPEED_33) {
@@ -204,17 +243,22 @@
     strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE);
     tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0';
 
+    shutdown_copyout:
+
     if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) {
         return(EFAULT);
     }
 
     shutdown_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
+#endif
 
     return(error);
 }
+#endif	/* PIC_LATER */
 
 char *pci_space_name[] = {"NONE", 
 			  "ROM",
@@ -240,6 +284,7 @@
 {
     pcibr_info_t                 pcibr_info = pcibr_infoh[func];
     int                          win;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     funcp->resp_f_status = 0;
 
@@ -248,16 +293,19 @@
     }
 
     funcp->resp_f_status |= FUNC_IS_VALID;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
-
+#endif
     if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
         funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
     }
 
     funcp->resp_f_bus = pcibr_info->f_bus;
-    funcp->resp_f_slot = pcibr_info->f_slot;
+    funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info);
     funcp->resp_f_func = pcibr_info->f_func;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
+#endif
     funcp->resp_f_pops = pcibr_info->f_pops;
     funcp->resp_f_efunc = pcibr_info->f_efunc;
     funcp->resp_f_einfo = pcibr_info->f_einfo;
@@ -297,20 +345,29 @@
     reg_p                        b_respp;
     pcibr_slot_info_resp_t       slotp;
     pcibr_slot_func_info_resp_t  funcp;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
+    extern void snia_kmem_free(void *, int);
 
-    slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP);
+    slotp = snia_kmem_zalloc(sizeof(*slotp), 0);
     if (slotp == NULL) {
         return(ENOMEM);
     }
 
     pss = &pcibr_soft->bs_slot[slot];
 
+    slotp->resp_bs_bridge_mode = pcibr_soft->bs_bridge_mode;
+    slotp->resp_bs_bridge_type = pcibr_soft->bs_bridge_type;
+
     slotp->resp_has_host = pss->has_host;
     slotp->resp_host_slot = pss->host_slot;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
+#else
+    sprintf(slotp->resp_slot_conn_name, "%p", (void *)pss->slot_conn);
+#endif
     slotp->resp_slot_status = pss->slot_status;
 
-    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
+    slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl);
 
     if (is_sys_critical_vertex(pss->slot_conn)) {
         slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
@@ -342,9 +399,10 @@
     slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
     slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
 
-    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
-    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
-                                                      PCIBR_RRB_SLOT_VIRTUAL];
+    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot][VCHAN0];
+    slotp->resp_bs_rrb_valid_v1 = pcibr_soft->bs_rrb_valid[slot][VCHAN1];
+    slotp->resp_bs_rrb_valid_v2 = pcibr_soft->bs_rrb_valid[slot][VCHAN2];
+    slotp->resp_bs_rrb_valid_v3 = pcibr_soft->bs_rrb_valid[slot][VCHAN3];
     slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
 
     if (slot & 1) {
@@ -355,16 +413,21 @@
 
     slotp->resp_b_resp = *b_respp;
 
-    slotp->resp_b_wid_control = bridge->b_wid_control;
     slotp->resp_b_int_device = bridge->b_int_device;
-    slotp->resp_b_int_enable = bridge->b_int_enable;
-    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	slotp->resp_p_int_enable = bridge->p_int_enable_64;
+	slotp->resp_p_int_host = bridge->p_int_addr_64[slot];
+    } else {
+	slotp->resp_b_int_enable = bridge->b_int_enable;
+	slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+    }
 
     if (COPYOUT(slotp, respp, sizeof(*respp))) {
         return(EFAULT);
     }
 
-    kmem_free(slotp, sizeof(*slotp));
+    snia_kmem_free(slotp, sizeof(*slotp));
 
     return(0);
 }
@@ -395,19 +458,26 @@
 pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t            slot = reqp->req_slot;
+    pciio_slot_t            slot;
     pciio_slot_t            tmp_slot;
     pcibr_slot_info_resp_t  respp = reqp->req_respp.query;
     int                     size = reqp->req_size;
-    int                     error;
+    int                     error = 0;
 
     /* Make sure that we are dealing with a bridge device vertex */
     if (!pcibr_soft) {
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl,
+                "pcibr_slot_query: pcibr_soft=0x%x, slot=%d, reqp=0x%x\n",
+                pcibr_soft, slot, reqp));
+
     /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
+    if ((!PCIBR_VALID_SLOT(pcibr_soft, slot)) && (slot != PCIIO_SLOT_NONE)) {
         return(PCI_NOT_A_SLOT);
     }
 
@@ -422,32 +492,37 @@
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, slot, respp);
 
+#ifdef PIC_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         return(error);
     }
 
     /* Return information for all the slots */
-    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
+    for (tmp_slot = pcibr_soft->bs_min_slot; 
+		tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); tmp_slot++) {
 
         if (size < sizeof(*respp)) {
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
 
+#ifdef PCI_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         if (error) {
             return(error);
         }
@@ -458,60 +533,92 @@
 
     return(error);
 }
-#endif	/* LATER */
 
-/* FIXME: there should be a better way to do this.
- * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE
+#if 0
+/*
+ * pcibr_slot_reset
+ *	Reset the PCI device in the particular slot.
+ *
+ *      The Xbridge does not comply with the PCI Specification
+ *      when resetting an indiviaudl slot.  An individual slot is
+ *      is reset by toggling the slot's bit in the Xbridge Control
+ *      Register.  The Xbridge will assert the target slot's 
+ *      (non-bussed) RST signal, but does not assert the (bussed) 
+ *      REQ64 signal as required by the specification.   As
+ *      designed, the Xbridge cannot assert the REQ64 signal
+ *      becuase it may interfere with a bus transaction in progress.
+ *      The practical effects of this Xbridge implementation is
+ *      device dependent;  it probably will not adversely effect
+ *      32-bit cards, but may disable 64-bit data transfers by those
+ *      cards that normally support 64-bit data transfers.  
+ *
+ *      The Xbridge will assert REQ64 when all four slots are reset
+ *      by simultaneously toggling all four slot reset bits in the
+ *      Xbridge Control Register.  This is basically a PCI bus reset
+ *      and asserting the (bussed) REQ64 signal will not interfere
+ *      with any bus transactions in progress.
+ *
+ *      The Xbridge (and the SN0 Bridge) support resetting only
+ *      four PCI bus slots via the (X)bridge Control Register.
+ *
+ *      To reset an individual slot for the PCI Hot-Plug feature
+ *      use the L1 console commands to power-down and then 
+ *      power-up the slot, or use the kernel infrastructure
+ *      functions to power-down/up the slot when they are
+ *      implemented for SN1.
  */
+int
+pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
+{
+	pcibr_soft_t		 pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+	bridge_t		*bridge;
+	bridgereg_t		 ctrlreg,tmp;
+	volatile bridgereg_t	*wrb_flush;
 
-/* 
- * PCI_ADDR_SPACE_LIMITS_LOAD
- *	Gets the current values of 
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_LOAD()			\
-    pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base;	\
-    pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last;	\
-    pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base;	\
-    pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last;	\
-    pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base;	\
-    pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last;
-/*
- * PCI_ADDR_SPACE_LIMITS_STORE
- *	Sets the current values of
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_STORE()			\
-    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\
-    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\
-    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\
-    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\
-    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\
-    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
-
-#define PCI_ADDR_SPACE_LIMITS_PRINT()			\
-    printf("+++++++++++++++++++++++\n"			\
-	   "IO base 0x%x last 0x%x\n"			\
-	   "SWIN base 0x%x last 0x%x\n"			\
-	   "MEM base 0x%x last 0x%x\n"			\
-	   "+++++++++++++++++++++++\n",			\
-	   pcibr_soft->bs_spinfo.pci_io_base,		\
-	   pcibr_soft->bs_spinfo.pci_io_last,		\
-	   pcibr_soft->bs_spinfo.pci_swin_base,		\
-	   pcibr_soft->bs_spinfo.pci_swin_last,		\
-	   pcibr_soft->bs_spinfo.pci_mem_base,		\
-	   pcibr_soft->bs_spinfo.pci_mem_last);
+	if (!pcibr_soft)
+		return(EINVAL);
+
+	if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+		return(EINVAL);
+
+	/* Enable the DMA operations from this device of the xtalk widget
+	 * (PCI host bridge in this case).
+	 */
+	xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot);
+
+	/* Set the reset slot bit in the bridge's wid control register
+	 * to reset the PCI slot 
+	 */
+	bridge = pcibr_soft->bs_base;
+
+	/* Read the bridge widget control and clear out the reset pin
+	 * bit for the corresponding slot. 
+	 */
+	tmp = ctrlreg = bridge->b_wid_control;
+
+	tmp &= ~BRIDGE_CTRL_RST_PIN(slot); 
+
+	bridge->b_wid_control = tmp;
+	tmp = bridge->b_wid_control;
+
+	/* Restore the old control register back.
+	 * NOTE : PCI card gets reset when the reset pin bit
+	 * changes from 0 (set above) to 1 (going to be set now).
+	 */
+
+	bridge->b_wid_control = ctrlreg;
 
+	/* Flush the write buffers if any !! */
+	wrb_flush = &(bridge->b_wr_req_buf[slot].reg);
+	while (*wrb_flush);
+
+	return(0);
+}
+#endif
+
+#define PROBE_LOCK 0	/* FIXME: we're attempting to lock around accesses
+			 * to b_int_enable.   This hangs pcibr_probe_slot()
+			 */
 
 /*
  * pcibr_slot_info_init
@@ -534,12 +641,12 @@
     pciio_vendor_id_t       vendor;
     pciio_device_id_t       device;
     unsigned                htype;
+    unsigned                lt_time;
+    int                     nbars;
     cfg_p                   wptr;
+    cfg_p                   pcix_cap;
     int                     win;
     pciio_space_t           space;
-    iopaddr_t		    pci_io_fb,	pci_io_fl;
-    iopaddr_t		    pci_lo_fb,  pci_lo_fl;
-    iopaddr_t		    pci_hi_fb,  pci_hi_fl;
     int			    nfunc;
     pciio_function_t	    rfunc;
     int			    func;
@@ -552,7 +659,7 @@
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization
@@ -566,28 +673,35 @@
     if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
         return(EPERM);
 
-    /* Load the current values of allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
-    
     /* Try to read the device-id/vendor-id from the config space */
-    cfgw = bridge->b_type0_cfg_dev[slot].l;
+    cfgw = pcibr_slot_config_addr(bridge, slot, 0);
 
+#if PROBE_LOCK
+    s = pcibr_lock(pcibr_soft);
+#endif
     if (pcibr_probe_slot(bridge, cfgw, &idword)) 
 	return(ENODEV);
+#if PROBE_LOCK
+    pcibr_unlock(pcibr_soft, s);
+#endif
 
     slotp = &pcibr_soft->bs_slot[slot];
     slotp->slot_status |= SLOT_POWER_UP;
 
     vendor = 0xFFFF & idword;
+    device = 0xFFFF & (idword >> 16);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl,
+		"pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device));
+
     /* If the vendor id is not valid then the slot is not populated
      * and we are done.
      */
     if (vendor == 0xFFFF) 
 	return(ENODEV);			
     
-    device = 0xFFFF & (idword >> 16);
-    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
-
+    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
     nfunc = 1;
     rfunc = PCIIO_FUNC_NONE;
     pfail = 0;
@@ -599,11 +713,17 @@
 
     if (htype & 0x80) {		/* MULTIFUNCTION */
 	for (func = 1; func < 8; ++func) {
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+#if PROBE_LOCK
+            s = pcibr_lock(pcibr_soft);
+#endif
 	    if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {
 		pfail |= 1 << func;
 		continue;
 	    }
+#if PROBE_LOCK
+            pcibr_unlock(pcibr_soft, s);
+#endif
 	    vendor = 0xFFFF & idwords[func];
 	    if (vendor == 0xFFFF) {
 		pfail |= 1 << func;
@@ -612,7 +732,7 @@
 	    nfunc = func + 1;
 	    rfunc = 0;
 	}
-	cfgw = bridge->b_type0_cfg_dev[slot].l;
+        cfgw = pcibr_slot_config_addr(bridge, slot, 0);
     }
     NEWA(pcibr_infoh, nfunc);
     
@@ -627,39 +747,162 @@
 		continue;
 	    
 	    idword = idwords[func];
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	    
 	    device = 0xFFFF & (idword >> 16);
-	    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
+	    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
 	    rfunc = func;
 	}
 	htype &= 0x7f;
 	if (htype != 0x00) {
-	    printk(KERN_WARNING  "%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
+	    printk(KERN_WARNING 
+		"%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
 		    pcibr_soft->bs_name, slot, func, htype);
-	    continue;
+	    nbars = 2;
+	} else {
+	    nbars = PCI_CFG_BASE_ADDRS;
+	}
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw));
+
+#ifdef PIC_LATER
+        /*
+         * Check for a Quad ATM PCI "card" and return all the PCI bus
+         * memory and I/O space.  This will work-around an apparent
+         * hardware problem with the Quad ATM XIO card handling large
+         * PIO addresses.  Releasing all the space for use by the card
+         * will lower the PIO addresses with the PCI bus address space.
+         * This is OK since the PROM did not assign any BAR addresses. 
+         *
+         * Only release all the PCI bus addresses once.
+         *
+         */
+        if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) {
+            iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;
+            int                     prom_base_size = 0x1000000;
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_mem_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED;
+            }
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_io_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED;
+            }
+        }
+#endif	/* PIC_LATER */
+
+	/* 
+	 * If the latency timer has already been set, by prom or by the
+	 * card itself, use that value.  Otherwise look at the device's
+	 * 'min_gnt' and attempt to calculate a latency time. 
+	 *
+	 * NOTE: For now if the device is on the 'real time' arbitration
+	 * ring we dont set the latency timer.  
+	 *
+	 * WAR: SGI's IOC3 and RAD devices target abort if you write a 
+	 * single byte into their config space.  So don't set the Latency
+	 * Timer for these devices
+	 */
+
+	lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1);
+
+	if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) &&
+	    !((vendor == IOC3_VENDOR_ID_NUM) && 
+	      (
+#ifdef PIC_LATER
+	       (device == IOC3_DEVICE_ID_NUM) ||
+	       (device == LINC_DEVICE_ID_NUM) ||
+#endif
+	       (device == 0x5 /* RAD_DEV */)))) {
+	     unsigned	min_gnt;
+	     unsigned	min_gnt_mult;
+	    
+	    /* 'min_gnt' indicates how long of a burst period a device
+	     * needs in increments of 250ns.  But latency timer is in
+	     * PCI clock cycles, so a conversion is needed.
+	     */
+	    min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1);
+
+	    if (IS_133MHZ(pcibr_soft))
+		min_gnt_mult = 32;	/* 250ns @ 133MHz in clocks */
+	    else if (IS_100MHZ(pcibr_soft))
+		min_gnt_mult = 24;	/* 250ns @ 100MHz in clocks */
+	    else if (IS_66MHZ(pcibr_soft))
+		min_gnt_mult = 16;	/* 250ns @ 66MHz, in clocks */
+	    else
+		min_gnt_mult = 8;	/* 250ns @ 33MHz, in clocks */
+
+	    if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256))
+		lt_time = (min_gnt * min_gnt_mult);
+	    else
+		lt_time = 4 * min_gnt_mult;	  /* 1 micro second */
+
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time);
+
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: set Latency Timer for slot=%d, "
+		    "func=%d, to 0x%x\n", 
+		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time));
+	}
+
+	/* Get the PCI-X capability if running in PCI-X mode.  If the func
+	 * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE
+	 * pcibr_info struct so the device driver for that function is not
+	 * called.
+	 */
+	if (IS_PCIX(pcibr_soft)) {
+	    if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) {
+		printk(KERN_WARNING
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		        "%v: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", pcibr_vhdl, slot, func);
+#else
+		        "0x%lx: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", (unsigned long)pcibr_vhdl, slot, func);
+#endif
+		pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE,
+		               PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE);
+		continue;
+	    }
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: PCI-X capability at 0x%x for "
+		    "slot=%d, func=%d\n", 
+		    pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func));
+	} else {
+	    pcix_cap = NULL;
 	}
-#if DEBUG && ATTACH_DEBUG
-	printk(KERN_NOTICE   
-		"%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x",
-		pcibr_soft->bs_name, slot, func, vendor, device);
-#endif	
 
 	pcibr_info = pcibr_device_info_new
 	    (pcibr_soft, slot, rfunc, vendor, device);
+
+	/* Keep a running total of the number of PIC-X functions on the bus
+         * and the number of max outstanding split trasnactions that they
+	 * have requested.  NOTE: "pcix_cap != NULL" implies IS_PCIX()
+	 */
+	pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap;
+	if (pcibr_info->f_pcix_cap) {
+	    int max_out;      /* max outstanding splittrans from status reg */
+
+	    pcibr_soft->bs_pcix_num_funcs++;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);
 	if (func == 0)
 	    slotp->slot_conn = conn_vhdl;
 
-#ifdef SN1_LITTLE_ENDIAN
-	cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4];
-#else
-	cmd_reg = cfgw[PCI_CFG_COMMAND / 4];
-#endif
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
 	
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
+	for (win = 0; win < nbars; ++win) {
 	    iopaddr_t               base, mask, code;
 	    size_t                  size;
 
@@ -706,11 +949,7 @@
 	     * this could be pushed up into pciio, when we
 	     * start supporting more PCI providers.
 	     */
-#ifdef SN1_LITTLE_ENDIAN
-	    base = wptr[((win*4)^4)/4];
-#else
-	    base = wptr[win];
-#endif
+	    base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4);
 
 	    if (base & PCI_BA_IO_SPACE) {
 		/* BASE is in I/O space. */
@@ -736,11 +975,7 @@
 		} else if (base & 0xC0000000) {
 		    base = 0;	/* outside permissable range */
 		} else if ((code == PCI_BA_MEM_64BIT) &&
-#ifdef SN1_LITTLE_ENDIAN
-			   (wptr[(((win + 1)*4)^4)/4] != 0)) {
-#else 
-			   (wptr[win + 1] != 0)) {
-#endif /* LITTLE_ENDIAN */
+			   (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) {
 		    base = 0;	/* outside permissable range */
 		}
 	    }
@@ -748,13 +983,8 @@
 	    if (base != 0) {	/* estimate size */
 		size = base & -base;
 	    } else {		/* calculate size */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = ~0;	/* turn on all bits */
-		size = wptr[((win*4)^4)/4];	/* get stored bits */
-#else 
-		wptr[win] = ~0;	/* turn on all bits */
-		size = wptr[win];	/* get stored bits */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0);    /* write 1's */
+		size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */
 		size &= mask;	/* keep addr */
 		size &= -size;	/* keep lsbit */
 		if (size == 0)
@@ -765,28 +995,6 @@
 	    pcibr_info->f_window[win].w_base = base;
 	    pcibr_info->f_window[win].w_size = size;
 
-	    /*
-	     * If this window already has PCI space
-	     * allocated for it, "subtract" that space from
-	     * our running freeblocks. Don't worry about
-	     * overlaps in existing allocated windows; we
-	     * may be overstating their sizes anyway.
-	     */
-
-	    if (base && size) {
-		if (space == PCIIO_SPACE_IO) {
-		    pcibr_freeblock_sub(&pci_io_fb,
-					&pci_io_fl,
-					base, size);
-		} else {
-		    pcibr_freeblock_sub(&pci_lo_fb,
-					&pci_lo_fl,
-					base, size);
-		    pcibr_freeblock_sub(&pci_hi_fb,
-					&pci_hi_fl,
-					base, size);
-		}	
-	    }
 #if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM)
 	    /*
 	     * IOC3 BASE_ADDR* BUG WORKAROUND
@@ -825,21 +1033,55 @@
 #endif
 	    if (code == PCI_BA_MEM_64BIT) {
 		win++;		/* skip upper half */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = 0;	/* which must be zero */
-#else 
-		wptr[win] = 0;	/* which must be zero */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0);  /* must be zero */
 	    }
 	}				/* next win */
     }				/* next func */
 
-    /* Store back the values for allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_STORE();
     return(0);
 }					
 
 /*
+ * pcibr_find_capability
+ *	Walk the list of capabilities (if it exists) looking for
+ *	the requested capability.  Return a cfg_p pointer to the
+ *	capability if found, else return NULL
+ */
+cfg_p
+pcibr_find_capability(cfg_p	cfgw,
+		      unsigned	capability)
+{
+    unsigned		cap_nxt;
+    unsigned		cap_id;
+    int			defend_against_circular_linkedlist = 0;
+
+    /* Check to see if there is a capabilities pointer in the cfg header */
+    if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) {
+	return (NULL);
+    }
+
+    /*
+     * Read up the capabilities head pointer from the configuration header.
+     * Capabilities are stored as a linked list in the lower 48 dwords of
+     * config space and are dword aligned. (Note: spec states the least two
+     * significant bits of the next pointer must be ignored,  so we mask
+     * with 0xfc).
+     */
+    cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc);
+
+    while (cap_nxt && (defend_against_circular_linkedlist <= 48)) {
+	cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1);
+	if (cap_id == capability) {
+	    return ((cfg_p)((char *)cfgw + cap_nxt));
+	}
+	cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc);
+	defend_against_circular_linkedlist++;
+    }
+
+    return (NULL);
+}
+
+/*
  * pcibr_slot_info_free
  *	Remove all the PCI infrastructural information associated
  * 	with a particular PCI device.
@@ -854,7 +1096,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
@@ -868,6 +1113,109 @@
     return(0);
 }
 
+/*
+ * pcibr_slot_pcix_rbar_init
+ *	Allocate RBARs to the PCI-X functions on a given device
+ */
+int
+pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,
+			    pciio_slot_t slot)
+{
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
+    char		 tmp_str[256];
+    int		       	 nfunc;
+    int			 func;
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
+
+    if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1)
+	return(EINVAL);
+
+    if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos))
+	return(EINVAL);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"pcibr_slot_pcix_rbar_init for slot %d\n", 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot)));
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"\tslot/func\trequested\tgiven\tinuse\tavail\n"));
+
+    for (func = 0; func < nfunc; ++func) {
+	cap_pcix_type0_t	*pcix_cap_p;
+	cap_pcix_stat_reg_t	*pcix_statreg_p;
+	cap_pcix_cmd_reg_t	*pcix_cmdreg_p;
+	int 			 num_rbar;
+
+	if (!(pcibr_info = pcibr_infoh[func]))
+	    continue;
+
+	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
+	    continue;
+
+	if (!(pcix_cap_p = pcibr_info->f_pcix_cap))
+	    continue;
+
+	pcix_statreg_p = &pcix_cap_p->pcix_type0_status;
+	pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command;
+
+	/* If there are enough RBARs to satify the number of "max outstanding 
+	 * transactions" each function requested (bs_pcix_rbar_percent_allowed
+	 * is 100%), then give each function what it requested, otherwise give 
+	 * the functions a "percentage of what they requested".
+	 */
+	if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) {
+	    pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+	    pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	} else {
+	    int index;	    /* index into max_splittrans_to_numbuf table */
+	    int max_out;    /* max outstanding transactions given to func */
+
+	    /* Calculate the percentage of RBARs this function can have.
+	     * NOTE: Every function gets at least 1 RBAR (thus the "+1").
+	     * bs_pcix_rbar_percent_allowed is the percentage of what was
+	     * requested less this 1 RBAR that all functions automatically 
+	     * gets
+	     */
+	    max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split]
+			* pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1;
+
+	    /* round down the newly caclulated max_out to a valid number in
+	     * max_splittrans_to_numbuf[]
+	     */
+	    for (index = 0; index < MAX_SPLIT_TABLE-1; index++)
+		if (max_splittrans_to_numbuf[index + 1] > max_out)
+		    break;
+
+	    pcix_cmdreg_p->max_split = index;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+            pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	}
+        /*
+         * The kernel only allows functions to have so many variable args,
+         * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf
+         * arguments fails so sprintf() it into a temporary string.
+         */
+	if (pcibr_debug_mask & PCIBR_DEBUG_RBAR) {
+            sprintf(tmp_str,"\t  %d/%d   \t    %d    \t  %d  \t  %d  \t  %d\n",
+	            PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func,
+	            max_splittrans_to_numbuf[pcix_statreg_p->max_out_split],
+	            max_splittrans_to_numbuf[pcix_cmdreg_p->max_split],
+	            pcibr_soft->bs_pcix_rbar_inuse, 
+		    pcibr_soft->bs_pcix_rbar_avail);
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, 
+		        "%s", tmp_str));
+	}
+    }
+    return(0);
+}
+
 int as_debug = 0;
 /*
  * pcibr_slot_addr_space_init
@@ -878,34 +1226,27 @@
 pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,
 			   pciio_slot_t	slot)
 {
-    pcibr_soft_t	pcibr_soft;
-    pcibr_info_h	pcibr_infoh;
-    pcibr_info_t	pcibr_info;
+    pcibr_soft_t	 pcibr_soft;
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    iopaddr_t		pci_io_fb, pci_io_fl;
-    iopaddr_t		pci_lo_fb, pci_lo_fl;
-    iopaddr_t		pci_hi_fb, pci_hi_fl;
-    size_t              align;
-    iopaddr_t           mask;
-    int		    	nbars;
-    int		       	nfunc;
-    int			func;
-    int			win;
+    size_t               align_slot;
+    iopaddr_t            mask;
+    int		       	 nbars;
+    int		       	 nfunc;
+    int			 func;
+    int			 win;
+    int                  rc = 0;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
-
-    /* Get the current values for the allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    if (as_debug)
-#ifdef LATER
-    PCI_ADDR_SPACE_LIMITS_PRINT();
-#endif
+    bridge = pcibr_soft->bs_base;
 
     /* allocate address space,
      * for windows that have not been
@@ -934,10 +1275,7 @@
      * the entire "lo" area is only a
      * megabyte, total ...
      */
-    align = (slot < 2) ? 0x200000 : 0x100000;
-    mask = -align;
-    pci_io_fb = (pci_io_fb + align - 1) & mask;
-    pci_hi_fb = (pci_hi_fb + align - 1) & mask;
+    align_slot = (slot < 2) ? 0x200000 : 0x100000;
 
     for (func = 0; func < nfunc; ++func) {
 	cfg_p                   cfgw;
@@ -945,7 +1283,9 @@
 	pciio_space_t           space;
 	iopaddr_t               base;
 	size_t                  size;
-	cfg_p                   pci_cfg_cmd_reg_p;
+#ifdef PCI_LATER
+	char			tmp_str[256];
+#endif
 	unsigned                pci_cfg_cmd_reg;
 	unsigned                pci_cfg_cmd_reg_add = 0;
 
@@ -957,13 +1297,15 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 	
-	cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+        cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	nbars = PCI_CFG_BASE_ADDRS;
+	if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0)
+	    nbars = 2;
+	else
+	    nbars = PCI_CFG_BASE_ADDRS;
 
 	for (win = 0; win < nbars; ++win) {
-
 	    space = pcibr_info->f_window[win].w_space;
 	    base = pcibr_info->f_window[win].w_base;
 	    size = pcibr_info->f_window[win].w_size;
@@ -972,77 +1314,93 @@
 		continue;
 
 	    if (base >= size) {
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n",
-			slot, func, win, space, base, base + size - 1);
-#endif
+		/*
+         	 * The kernel only allows functions to have so many variable
+                 * args attempting to call PCIBR_DEBUG_ALWAYS() with more than
+         	 * 5 printf arguments fails so sprintf() it into a temporary 
+		 * string (tmp_str).
+         	 */
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+		if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+		    sprintf(tmp_str, "pcibr_slot_addr_space_init: slot=%d, "
+			"func=%d win %d is in %r [0x%x..0x%x], allocated by "
+			"prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+			func, win, space, space_desc, base, base + size - 1);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+		}
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 		continue;		/* already allocated */
 	    }
-	    align = size;		/* ie. 0x00001000 */
-	    if (align < _PAGESZ)
-		align = _PAGESZ;	/* ie. 0x00004000 */
-	    mask = -align;		/* ie. 0xFFFFC000 */
 
 	    switch (space) {
 	    case PCIIO_SPACE_IO:
-		base = (pci_io_fb + align - 1) & mask;
-		if ((base + size) > pci_io_fl) {
-		    base = 0;
-		    break;
-		}
-		pci_io_fb = base + size;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_window[win],
+                                            PCIIO_SPACE_IO,
+                                            0, size, align_slot);
+                if (!base)
+                    rc = ENOSPC;
 		break;
 		
 	    case PCIIO_SPACE_MEM:
-#ifdef SN1_LITTLE_ENDIAN
-		if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) ==
-#else
-		if ((wptr[win] & PCI_BA_MEM_LOCATION) ==
-#endif  /* LITTLE_ENDIAN */
-		    PCI_BA_MEM_1MEG) {
+		if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) &
+		     PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) {
+                    int align = size;           /* ie. 0x00001000 */
+                    
+                    if (align < _PAGESZ)
+                        align = _PAGESZ;        /* ie. 0x00004000 */
+ 
 		    /* allocate from 20-bit PCI space */
-		    base = (pci_lo_fb + align - 1) & mask;
-		    if ((base + size) > pci_lo_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_lo_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM,
+                                                0, size, align);
+                    if (!base)
+                        rc = ENOSPC;
 		} else {
 		    /* allocate from 32-bit or 64-bit PCI space */
-		    base = (pci_hi_fb + align - 1) & mask;
-		    if ((base + size) > pci_hi_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_hi_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM32,
+                                                0, size, align_slot);
+		    if (!base) 
+			rc = ENOSPC;
 		}
 		break;
 		
 	    default:
 		base = 0;
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d window %d had bad space code %d\n",
-			slot, win, space);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+			    "pcibr_slot_addr_space_init: slot=%d, window %d "
+			    "had bad space code %d\n", 
+			    PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space));
 	    }
 	    pcibr_info->f_window[win].w_base = base;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[((win*4)^4)/4] = base;
-#if DEBUG && PCI_DEBUG
-		printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base);
-#endif
-#else
-	    wptr[win] = base;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base);
 
-#if DEBUG && PCI_DEBUG
-	    if (base >= size)
-		printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n",
-			slot, func, win, space, base, base + size - 1);
-	    else
-		printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n",
-			slot, func, win, size, space);
-#endif
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+	    if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+                if (base >= size) {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d is in %r[0x%x..0x%x], "
+				    "allocated by pcibr\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, space, space_desc, base, 
+				    base + size - 1);
+		     PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				 "%s",tmp_str));
+	        }
+		else {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d, unable to alloc 0x%x in %r\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, size, space, space_desc);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+	        }
+	    }
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 	}				/* next base */
 
 	/*
@@ -1055,34 +1413,23 @@
 	    (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) {
 
 	    wptr = cfgw + PCI_EXPANSION_ROM / 4;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[1] = 0xFFFFF000;
-	    mask = wptr[1];
-#else
-	    *wptr = 0xFFFFF000;
-	    mask = *wptr;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000);
+	    mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4);
 	    if (mask & 0xFFFFF000) {
 		size = mask & -mask;
-		align = size;
-		if (align < _PAGESZ)
-		    align = _PAGESZ;
-		mask = -align;
-		base = (pci_hi_fb + align - 1) & mask;
-		if ((base + size) > pci_hi_fl)
-		    base = size = 0;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_rwindow,
+                                            PCIIO_SPACE_MEM32, 
+                                            0, size, align_slot);
+		if (!base)
+		    rc = ENOSPC;
 		else {
-		    pci_hi_fb = base + size;
-#ifdef SN1_LITTLE_ENDIAN
-		    wptr[1] = base;
-#else
-		    *wptr = base;
-#endif  /* LITTLE_ENDIAN */
-#if DEBUG && PCI_DEBUG
-		    printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n",
-			    pcibr_soft->bs_name, slot,
-			    base, base + size - 1);
-#endif
+		    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+				"pcibr_slot_addr_space_init: slot=%d, func=%d, "
+				"ROM in [0x%X..0x%X], allocated by pcibr\n",
+				PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				func, base, base + size - 1));
 		}
 	    }
 	}
@@ -1116,30 +1463,25 @@
 
 	pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER;
 
-	pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4;
-	pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p;
+	pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+
 #if PCI_FBBE	/* XXX- check here to see if dev can do fast-back-to-back */
 	if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP))
 	    fast_back_to_back_enable = 0;
 #endif
 	pci_cfg_cmd_reg &= 0xFFFF;
 	if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg)
-	    *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add;
-	
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, 
+				pci_cfg_cmd_reg | pci_cfg_cmd_reg_add);
     }				/* next func */
-
-    /* Now that we have allocated new chunks of PCI address spaces to this
-     * card we need to update the bookkeeping values which indicate
-     * the current PCI address space allocations.
-     */
-    PCI_ADDR_SPACE_LIMITS_STORE();
-    return(0);
+    return(rc);
 }
 
 /*
  * pcibr_slot_device_init
  * 	Setup the device register in the bridge for this PCI slot.
  */
+
 int
 pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,
 		       pciio_slot_t slot)
@@ -1150,7 +1492,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
@@ -1161,21 +1506,28 @@
      */
     devreg = bridge->b_device[slot].reg;
     devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS;
-    devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
-#ifdef LITTLE_ENDIAN
-    devreg |= BRIDGE_DEV_DEV_SWAP;
-#endif
+
+    /*
+     * PIC WAR. PV# 855271
+     * Don't enable virtual channels in the PIC by default.
+     * Can cause problems with 32-bit devices. (The bit is only intended
+     * for 64-bit devices).  We set the bit in pcibr_try_set_device()
+     * if we're 64-bit and requesting virtual channels.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV855271, pcibr_soft))
+	devreg |= BRIDGE_DEV_COH;
+    else
+	devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
     pcibr_soft->bs_slot[slot].bss_device = devreg;
     bridge->b_device[slot].reg = devreg;
 
-#if DEBUG && PCI_DEBUG
-	printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg);
-#endif
-
-#if DEBUG && PCI_DEBUG
-    printk("pcibr: PCI space allocation done.\n");
+#ifdef PIC_LATER
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl,
+		"pcibr_slot_device_init: Device(%d): %R\n",
+		slot, devreg, device_bits));
+#else
+    printk("pcibr_slot_device_init: Device(%d) 0x%x\n", slot, devreg);
 #endif
-
     return(0);
 }
 
@@ -1194,7 +1546,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     slotp = &pcibr_soft->bs_slot[slot];
@@ -1259,17 +1614,25 @@
     pcibr_info_t	pcibr_info;
     async_attach_t	aa = NULL;
     int			func;
-    devfs_handle_t	xconn_vhdl,conn_vhdl;
+    devfs_handle_t	xconn_vhdl, conn_vhdl;
+#ifdef PIC_LATER
+    devfs_handle_t	scsi_vhdl;
+#endif
     int			nfunc;
     int                 error_func;
     int                 error_slot = 0;
     int                 error = ENODEV;
+#ifdef PIC_LATER
+    int                 hwg_err;
+#endif
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host) {
         return(EPERM);
@@ -1303,6 +1666,40 @@
 
 	error_func = pciio_device_attach(conn_vhdl, drv_flags);
 
+#ifdef PIC_LATER
+        /*
+         * Try to assign well-known SCSI controller numbers for hot-plug
+         * insert
+         */
+        if (drv_flags) {
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/0",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/1",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+        }
+#endif /* PIC_LATER */
+
         pcibr_info->f_att_det_error = error_func;
 
 	if (error_func)
@@ -1313,9 +1710,12 @@
     }				/* next func */
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 	    pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;
+	}
     } else {
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
     }
         
@@ -1344,16 +1744,15 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host)
         return(EPERM);
 
-    /* Make sure that we do not detach a system critical function vertex */
-    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
-        return(EPERM);
-
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
 
@@ -1367,6 +1766,14 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 
+	if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) {
+	    int max_out;
+
+	    pcibr_soft->bs_pcix_num_funcs--;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pcibr_info->f_vertex;
 
 	error_func = pciio_device_detach(conn_vhdl, drv_flags);
@@ -1380,22 +1787,22 @@
 
     }				/* next func */
 
-    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
             pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT;
+	}
     } else {
         if (conn_vhdl != GRAPH_VERTEX_NONE) 
             pcibr_device_unregister(conn_vhdl);
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
     }
         
     return(error);
 }
 
-#ifdef LATER
-
 /*
  * pcibr_slot_attach
  *	This is a place holder routine to keep track of all the
@@ -1411,81 +1818,16 @@
                   int         *sub_errorp)
 {
     pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+#ifdef PIC_LATER
     timespec_t    ts;
-    int		  error;
-
-    if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) { 
-        /* Power-up the slot */
-        error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_L1_ERR);
-        } else {
-            pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK;
-            pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP;
-        }
-
-#ifdef LATER
-        /*
-         * Allow cards like the Alteon Gigabit Ethernet Adapter to complete
-         * on-card initialization following the slot reset
-         */
-         ts.tv_sec = 0;                      /* 0 secs */
-         ts.tv_nsec = 500 * (1000 * 1000);   /* 500 msecs */
-         nano_delay(&ts);
-#else
 #endif
-#if 0
-        /* Reset the slot */
-        error = pcibr_slot_reset(pcibr_vhdl, slot)
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RESET_ERR);
-        }
-#endif
-
-        /* Find out what is out there */
-        error = pcibr_slot_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_INFO_INIT_ERR);
-        }
-
-        /* Set up the address space for this slot in the PCI land */
-        error = pcibr_slot_addr_space_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_ADDR_INIT_ERR);
-        }
-
-        /* Setup the device register */
-        error = pcibr_slot_device_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_DEV_INIT_ERR);
-        }
-
-        /* Setup host/guest relations */
-        error = pcibr_slot_guest_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_GUEST_INIT_ERR);
-        }
-
-        /* Initial RRB management */
-        error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RRB_ALLOC_ERR);
-        }
+    int		  error;
 
+    /* Do not allow a multi-function card to be hot-plug inserted */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        if (sub_errorp)
+            *sub_errorp = EPERM;
+        return(PCI_MULTI_FUNC_ERR);
     }
 
     /* Call the device attach */
@@ -1501,7 +1843,6 @@
 
     return(0);
 }
-#endif	/* LATER */
 
 /*
  * pcibr_slot_detach
@@ -1511,13 +1852,42 @@
 int
 pcibr_slot_detach(devfs_handle_t pcibr_vhdl,
 		  pciio_slot_t slot,
-		  int          drv_flags)
+		  int          drv_flags,
+		  char        *l1_msg,
+                  int         *sub_errorp)
 {
+    pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     int		  error;
     
+    /* Make sure that we do not detach a system critical function vertex */
+    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
+        return(PCI_IS_SYS_CRITICAL);
+
     /* Call the device detach function */
     error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));
-    return (error);
+    if (error) {
+        if (sub_errorp)
+            *sub_errorp = error;       
+        return(PCI_SLOT_DRV_DETACH_ERR);
+    }
+
+    /* Recalculate the RBARs for all the devices on the bus since we've
+     * just freed some up and some of the devices could use them.
+     */
+    if (IS_PCIX(pcibr_soft)) {
+	int tmp_slot;
+
+	pcibr_soft->bs_pcix_rbar_inuse = 0;
+	pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
+	pcibr_soft->bs_pcix_rbar_percent_allowed = 
+					pcibr_pcix_rbars_calc(pcibr_soft);
+
+	for (tmp_slot = pcibr_soft->bs_min_slot;
+			tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot)
+            (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot);
+    }
+
+    return (0);
 
 }
 
@@ -1540,11 +1910,14 @@
     devfs_handle_t        conn_vhdl = GRAPH_VERTEX_NONE;
     int                 nfunc;
     int                 func;
-    boolean_t		is_sys_critical_vertex(devfs_handle_t);
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-        return(0);
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
@@ -1574,57 +1947,112 @@
 }
 
 /*
- * pcibr_probe_slot: read a config space word
- * while trapping any errors; reutrn zero if
+ * pcibr_probe_slot_pic: read a config space word
+ * while trapping any errors; return zero if
  * all went OK, or nonzero if there was an error.
  * The value read, if any, is passed back
  * through the valp parameter.
  */
-int
-pcibr_probe_slot(bridge_t *bridge,
-		 cfg_p cfg,
-		 unsigned *valp)
+static int
+pcibr_probe_slot_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
 {
-    int                     rv;
-    bridgereg_t             old_enable, new_enable;
-    int badaddr_val(volatile void *, int, volatile void *);
-
-    old_enable = bridge->b_int_enable;
-    new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+	int rv;
+	picreg_t p_old_enable = (picreg_t)0, p_new_enable;
+	extern int badaddr_val(volatile void *, int, volatile void *);
+
+	p_old_enable = bridge->p_int_enable_64;
+	p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT);
+	bridge->p_int_enable_64 = p_new_enable;
+
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT))
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+
+	if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) {
+		bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR);
+		(void) bridge->b_wid_tflush;	/* flushbus */
+	}
+	rv = badaddr_val((void *) cfg, 4, valp);
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) {
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+		rv = 1;         /* unoccupied slot */
+	}
+	bridge->p_int_enable_64 = p_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	return(rv);
+}
 
-    bridge->b_int_enable = new_enable;
+/*
+ * pcibr_probe_slot_non_pic: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot_non_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
+{
+	int                     rv;
+	bridgereg_t             b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0;
+	extern int              badaddr_val(volatile void *, int, volatile void *);
+
+        b_old_enable = bridge->b_int_enable;
+        b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+        bridge->b_int_enable = b_new_enable;
 
 	/*
 	 * The xbridge doesn't clear b_err_int_view unless
 	 * multi-err is cleared...
 	 */
-	if (is_xbridge(bridge))
-	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
+	if (is_xbridge(bridge)) {
+	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT)
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
-	    }
-
-    if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
-	bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
-	(void) bridge->b_wid_tflush;	/* flushbus */
-    }
-    rv = badaddr_val((void *) cfg, 4, valp);
+	}
 
+        if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
+	    bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
+	    (void) bridge->b_wid_tflush;	/* flushbus */
+        }
+	rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp);
 	/*
 	 * The xbridge doesn't set master timeout in b_int_status
 	 * here.  Fortunately it's in error_interrupt_view.
 	 */
-	if (is_xbridge(bridge))
+	if (is_xbridge(bridge)) {
 	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
 		rv = 1;		/* unoccupied slot */
 	    }
+	}
+        bridge->b_int_enable = b_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+
+    	return(rv);
+}
 
-    bridge->b_int_enable = old_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 
-    return rv;
+/*
+ * pcibr_probe_slot: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot(bridge_t *bridge,
+		 cfg_p cfg,
+		 unsigned *valp)
+{
+    if ( is_pic(bridge) )
+	return(pcibr_probe_slot_pic(bridge, cfg, valp));
+    else
+	return(pcibr_probe_slot_non_pic(bridge, cfg, valp));
 }
 
+
 void
 pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
 {
@@ -1632,10 +2060,13 @@
     pcibr_info_t	pcibr_info;
     pciio_function_t	func;
     pcibr_soft_slot_t	slotp = &pcibr_soft->bs_slot[slot];
+    bridge_t           *bridge = pcibr_soft->bs_base; 
+    cfg_p               cfgw;
     int			nfunc = slotp->bss_ninfo;
     int                 bar;
     int                 devio_index;
     int                 s;
+    unsigned            cmd_reg;
 
 
     for (func = 0; func < nfunc; func++) {
@@ -1646,10 +2077,19 @@
 
         s = pcibr_lock(pcibr_soft);
 
+        /* Disable memory and I/O BARs */
+	cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+	cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE);
+	do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg);
+
         for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) {
             if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE)
                 continue;
 
+            /* Free the PCI bus space */
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_window[bar]);
+
             /* Get index of the DevIO(x) register used to access this BAR */
             devio_index = pcibr_info->f_window[bar].w_devio_index;
 
@@ -1664,6 +2104,11 @@
             }
         }
 
+        /* Free the Expansion ROM PCI bus space */
+	if(pcibr_info->f_rbase && pcibr_info->f_rsize) {
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_rwindow);
+        }
+
         pcibr_unlock(pcibr_soft, s);
 
 	slotp->bss_infos[func] = 0;
@@ -1690,3 +2135,68 @@
     slotp->bss_cmd_shadow = 0;
 
 }
+
+
+iopaddr_t
+pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p,
+                     pciio_space_t space, int start, int size, int align)
+{
+    pciio_win_map_t win_map_p;
+
+    switch (space) {
+
+        case PCIIO_SPACE_IO:
+            win_map_p = &pcibr_soft->bs_io_win_map;
+            break;
+
+        case PCIIO_SPACE_MEM:
+            win_map_p = &pcibr_soft->bs_swin_map;
+            break;
+
+        case PCIIO_SPACE_MEM32:
+            win_map_p = &pcibr_soft->bs_mem_win_map;
+            break;
+
+        default:
+            return 0;
+
+    }
+    return pciio_device_win_alloc(win_map_p,
+				  win_info_p
+				  ? &win_info_p->w_win_alloc
+				  : NULL,
+				  start, size, align);
+}
+
+
+void
+pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p)
+{
+	pciio_device_win_free(&win_info_p->w_win_alloc);
+}
+
+/*
+ * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number
+ * associated with that vertex_hdl.  The true mapping happens from the
+ * io_brick_tab[] array defined in ml/SN/iograph.c
+ */
+int
+pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) 
+{
+    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    xwidgetnum_t	widget = pcibr_soft->bs_xid;
+    int			bricktype = pcibr_soft->bs_bricktype;
+    int			bus = pcibr_soft->bs_busnum;
+    
+    /* 
+     * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum
+     * will be 0 or 1.  For [X]BRIDGE there is 1 bus per widget and 
+     * pcibr_soft->bs_busnum will always be zero.  So we add bs_busnum
+     * to what io_brick_map_widget returns to get the bus number.
+     */
+    if ((bus += io_brick_map_widget(bricktype, widget)) > 0) {
+	return bus;
+    } else {
+	return 0;
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pciio.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pciio.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pciio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pciio.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,1877 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#define	USRPCI	0
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/ate_utils.h>
+#include <asm/sn/simulator.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
+#define DEBUG_PCIIO
+#undef DEBUG_PCIIO	/* turn this on for yet more console output */
+
+
+#define GET_NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DO_DEL(ptr)	(kfree(ptr))
+
+char                    pciio_info_fingerprint[] = "pciio_info";
+
+cdl_p                   pciio_registry = NULL;
+
+int
+badaddr_val(volatile void *addr, int len, volatile void *ptr)
+{
+	int ret = 0;
+	volatile void *new_addr;
+
+	switch (len) {
+		case 4:
+			new_addr = (void *) addr;
+			ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr);
+			break;
+		default:
+			printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len);
+	}
+
+	if (ret < 0)
+		panic("badaddr_val: unexpected status (%d) in probing", ret);
+	return(ret);
+
+}
+
+
+nasid_t
+get_console_nasid(void)
+{
+	extern nasid_t console_nasid;
+	extern nasid_t master_baseio_nasid;
+
+	if (console_nasid < 0) {
+		console_nasid = ia64_sn_get_console_nasid();
+		if (console_nasid < 0) {
+// ZZZ What do we do if we don't get a console nasid on the hardware????
+			if (IS_RUNNING_ON_SIMULATOR() )
+				console_nasid = master_baseio_nasid;
+		}
+	} 
+	return console_nasid;
+}
+
+nasid_t
+get_master_baseio_nasid(void)
+{
+	extern nasid_t master_baseio_nasid;
+	extern char master_baseio_wid;
+
+	if (master_baseio_nasid < 0) {
+		nasid_t tmp;
+
+		master_baseio_nasid = ia64_sn_get_master_baseio_nasid();
+
+		if ( master_baseio_nasid >= 0 ) {
+        		master_baseio_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_baseio_nasid)->memory_base);
+		}
+	} 
+	return master_baseio_nasid;
+}
+
+int
+hub_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+	return(0);
+}
+
+int
+hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+	return(0);
+}
+
+void
+ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror)
+{
+}
+
+/******
+ ****** end hack defines ......
+ ******/
+
+
+
+
+/* =====================================================================
+ *    PCI Generic Bus Provider
+ * Implement PCI provider operations.  The pciio* layer provides a
+ * platform-independent interface for PCI devices.  This layer
+ * switches among the possible implementations of a PCI adapter.
+ */
+
+/* =====================================================================
+ *    Provider Function Location SHORTCUT
+ *
+ * On platforms with only one possible PCI provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+
+/* =====================================================================
+ *    Function Table of Contents
+ */
+
+#if !defined(DEV_FUNC)
+static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev);
+#endif
+
+pciio_piomap_t          pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);
+void                    pciio_piomap_free(pciio_piomap_t);
+caddr_t                 pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t);
+
+void                    pciio_piomap_done(pciio_piomap_t);
+caddr_t                 pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);
+caddr_t			pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned);
+
+iopaddr_t               pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);
+void                    pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);
+
+pciio_dmamap_t          pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+alenlist_t              pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned);
+void                    pciio_dmamap_done(pciio_dmamap_t);
+iopaddr_t               pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			pciio_dmamap_drain(pciio_dmamap_t);
+void			pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);
+void			pciio_dmalist_drain(devfs_handle_t, alenlist_t);
+iopaddr_t               pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned);
+
+pciio_intr_t            pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
+void                    pciio_intr_free(pciio_intr_t);
+int                     pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t);
+void                    pciio_intr_disconnect(pciio_intr_t);
+devfs_handle_t            pciio_intr_cpu_get(pciio_intr_t);
+
+void			pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t);
+
+void                    pciio_provider_startup(devfs_handle_t);
+void                    pciio_provider_shutdown(devfs_handle_t);
+
+pciio_endian_t          pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);
+pciio_priority_t        pciio_priority_set(devfs_handle_t, pciio_priority_t);
+devfs_handle_t            pciio_intr_dev_get(pciio_intr_t);
+
+devfs_handle_t            pciio_pio_dev_get(pciio_piomap_t);
+pciio_slot_t            pciio_pio_slot_get(pciio_piomap_t);
+pciio_space_t           pciio_pio_space_get(pciio_piomap_t);
+iopaddr_t               pciio_pio_pciaddr_get(pciio_piomap_t);
+ulong                   pciio_pio_mapsz_get(pciio_piomap_t);
+caddr_t                 pciio_pio_kvaddr_get(pciio_piomap_t);
+
+devfs_handle_t            pciio_dma_dev_get(pciio_dmamap_t);
+pciio_slot_t            pciio_dma_slot_get(pciio_dmamap_t);
+
+pciio_info_t            pciio_info_chk(devfs_handle_t);
+pciio_info_t            pciio_info_get(devfs_handle_t);
+void                    pciio_info_set(devfs_handle_t, pciio_info_t);
+devfs_handle_t            pciio_info_dev_get(pciio_info_t);
+pciio_slot_t            pciio_info_slot_get(pciio_info_t);
+pciio_function_t        pciio_info_function_get(pciio_info_t);
+pciio_vendor_id_t       pciio_info_vendor_id_get(pciio_info_t);
+pciio_device_id_t       pciio_info_device_id_get(pciio_info_t);
+devfs_handle_t            pciio_info_master_get(pciio_info_t);
+arbitrary_info_t        pciio_info_mfast_get(pciio_info_t);
+pciio_provider_t       *pciio_info_pops_get(pciio_info_t);
+error_handler_f	       *pciio_info_efunc_get(pciio_info_t);
+error_handler_arg_t    *pciio_info_einfo_get(pciio_info_t);
+pciio_space_t		pciio_info_bar_space_get(pciio_info_t, int);
+iopaddr_t		pciio_info_bar_base_get(pciio_info_t, int);
+size_t			pciio_info_bar_size_get(pciio_info_t, int);
+iopaddr_t		pciio_info_rom_base_get(pciio_info_t);
+size_t			pciio_info_rom_size_get(pciio_info_t);
+
+void                    pciio_init(void);
+int                     pciio_attach(devfs_handle_t);
+
+void                    pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns);
+void                    pciio_provider_unregister(devfs_handle_t);
+pciio_provider_t       *pciio_provider_fns_get(devfs_handle_t);
+
+int                     pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned);
+void                    pciio_driver_unregister(char *driver_prefix);
+
+devfs_handle_t            pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+
+void			pciio_device_unregister(devfs_handle_t);
+pciio_info_t		pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+void			pciio_device_info_free(pciio_info_t);
+devfs_handle_t		pciio_device_info_register(devfs_handle_t, pciio_info_t);
+void			pciio_device_info_unregister(devfs_handle_t, pciio_info_t);
+int                     pciio_device_attach(devfs_handle_t, int);
+int			pciio_device_detach(devfs_handle_t, int);
+void                    pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
+
+int                     pciio_reset(devfs_handle_t);
+int                     pciio_write_gather_flush(devfs_handle_t);
+int                     pciio_slot_inuse(devfs_handle_t);
+
+/* =====================================================================
+ *    Provider Function Location
+ *
+ *      If there is more than one possible provider for
+ *      this platform, we need to examine the master
+ *      vertex of the current vertex for a provider
+ *      function structure, and indirect through the
+ *      appropriately named member.
+ */
+
+#if !defined(DEV_FUNC)
+
+static pciio_provider_t *
+pciio_to_provider_fns(devfs_handle_t dev)
+{
+    pciio_info_t            card_info;
+    pciio_provider_t       *provider_fns;
+
+    /*
+     * We're called with two types of vertices, one is
+     * the bridge vertex (ends with "pci") and the other is the
+     * pci slot vertex (ends with "pci/[0-8]").  For the first type
+     * we need to get the provider from the PFUNCS label.  For
+     * the second we get it from fastinfo/c_pops.
+     */
+    provider_fns = pciio_provider_fns_get(dev);
+    if (provider_fns == NULL) {
+	card_info = pciio_info_get(dev);
+	if (card_info != NULL) {
+		provider_fns = pciio_info_pops_get(card_info);
+	}
+    }
+
+    if (provider_fns == NULL)
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	PRINT_PANIC("%v: provider_fns == NULL", dev);
+#else
+	PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev);
+#endif
+
+    return provider_fns;
+
+}
+
+#define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func
+#define CAST_PIOMAP(x)		((pciio_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pciio_dmamap_t)(x))
+#define CAST_INTR(x)		((pciio_intr_t)(x))
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define PIOMAP_FUNC(map,func)		DEV_FUNC((map)->pp_dev,func)
+#define DMAMAP_FUNC(map,func)		DEV_FUNC((map)->pd_dev,func)
+#define INTR_FUNC(intr_hdl,func)	DEV_FUNC((intr_hdl)->pi_dev,func)
+
+/* =====================================================================
+ *          PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      pciio space on a specified card
+ */
+
+pciio_piomap_t
+pciio_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		   iopaddr_t addr,	/* lowest address (or offset in window) */
+		   size_t byte_count,	/* size of region containing our mappings */
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{					/* defined in sys/pio.h */
+    return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, space, addr, byte_count, byte_count_max, flags);
+}
+
+void
+pciio_piomap_free(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_free)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piomap_addr(pciio_piomap_t pciio_piomap,	/* mapping resources */
+		  iopaddr_t pciio_addr,	/* map for this pciio address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr)
+	(CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count);
+
+    return pciio_piomap->pp_kvaddr;
+}
+
+void
+pciio_piomap_done(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_done)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		    iopaddr_t addr,	/* starting address (or offset in window) */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{					/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, space, addr, byte_count, flags);
+}
+
+caddr_t
+pciio_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       pciio_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_piomap_t          map = 0;
+    int			    errfree = 0;
+    caddr_t                 res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_piotrans_addr
+	(dev, dev_desc, space, addr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_piotrans worked */
+
+    if (!map) {
+	map = pciio_piomap_alloc
+	    (dev, dev_desc, space, addr, byte_count, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_piomap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_piomap_free(map);
+	return res;			/* pciio_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_piomap_addr succeeded */
+}
+
+iopaddr_t
+pciio_piospace_alloc(devfs_handle_t dev,	/* Device requiring space */
+		     device_desc_t dev_desc,	/* Device descriptor */
+		     pciio_space_t space,	/* MEM32/MEM64/IO */
+		     size_t byte_count,	/* Size of mapping */
+		     size_t align)
+{					/* Alignment needed */
+    if (align < NBPP)
+	align = NBPP;
+    return DEV_FUNC(dev, piospace_alloc)
+	(dev, dev_desc, space, byte_count, align);
+}
+
+void
+pciio_piospace_free(devfs_handle_t dev,	/* Device freeing space */
+		    pciio_space_t space,	/* Type of space        */
+		    iopaddr_t pciaddr,	/* starting address */
+		    size_t byte_count)
+{					/* Range of address   */
+    DEV_FUNC(dev, piospace_free)
+	(dev, space, pciaddr, byte_count);
+}
+
+/* =====================================================================
+ *          DMA MANAGEMENT
+ *
+ *      For mapping from pci space to system
+ *      physical space.
+ */
+
+pciio_dmamap_t
+pciio_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{					/* defined in dma.h */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+void
+pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+	(CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+alenlist_t
+pciio_dmamap_list(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_list)
+	(CAST_DMAMAP(pciio_dmamap), alenlist, flags);
+}
+
+void
+pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+alenlist_t
+pciio_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+iopaddr_t
+pciio_dma_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       paddr_t paddr,		/* system physical address */
+	       size_t byte_count,	/* length */
+	       pciio_dmamap_t *mapp,	/* map to use, then map we used */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_dmamap_t          map = 0;
+    int			    errfree = 0;
+    iopaddr_t               res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_dmatrans_addr
+	(dev, dev_desc, paddr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_dmatrans worked */
+
+    if (!map) {
+	map = pciio_dmamap_alloc
+	    (dev, dev_desc, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_dmamap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_dmamap_addr
+	(map, paddr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_dmamap_free(map);
+	return res;			/* pciio_dmamap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_dmamap_addr succeeded */
+}
+
+void
+pciio_dmamap_drain(pciio_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *          INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+pciio_intr_t
+pciio_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 pciio_intr_line_t lines,	/* INTR line(s) to attach */
+		 devfs_handle_t owner_dev)
+{					/* owner of this interrupt */
+    return (pciio_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, lines, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+pciio_intr_free(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Associate resources allocated with a previous pciio_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+pciio_intr_connect(pciio_intr_t intr_hdl,
+		intr_func_t intr_func, intr_arg_t intr_arg)	/* pciio intr resource handle */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), intr_func, intr_arg);
+}
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+pciio_intr_disconnect(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+pciio_intr_cpu_get(pciio_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+void
+pciio_slot_func_to_name(char		       *name,
+			pciio_slot_t		slot,
+			pciio_function_t	func)
+{
+    /*
+     * standard connection points:
+     *
+     * PCIIO_SLOT_NONE:	.../pci/direct
+     * PCIIO_FUNC_NONE: .../pci/<SLOT>			ie. .../pci/3
+     * multifunction:   .../pci/<SLOT><FUNC>		ie. .../pci/3c
+     */
+
+    if (slot == PCIIO_SLOT_NONE)
+	sprintf(name, EDGE_LBL_DIRECT);
+    else if (func == PCIIO_FUNC_NONE)
+	sprintf(name, "%d", slot);
+    else
+	sprintf(name, "%d%c", slot, 'a'+func);
+}
+
+/*
+ * pciio_cardinfo_get
+ *
+ * Get the pciio info structure corresponding to the
+ * specified PCI "slot" (we like it when the same index
+ * number is used for the PCI IDSEL, the REQ/GNT pair,
+ * and the interrupt line being used for INTA. We like
+ * it so much we call it the slot number).
+ */
+static pciio_info_t
+pciio_cardinfo_get(
+		      devfs_handle_t pciio_vhdl,
+		      pciio_slot_t pci_slot)
+{
+    char                    namebuf[16];
+    pciio_info_t	    info = 0;
+    devfs_handle_t	    conn;
+
+    pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE);
+    if (GRAPH_SUCCESS ==
+	hwgraph_traverse(pciio_vhdl, namebuf, &conn)) {
+	info = pciio_info_chk(conn);
+	hwgraph_vertex_unref(conn);
+    }
+
+    return info;
+}
+
+
+/*
+ * pciio_error_handler:
+ * dispatch an error to the appropriate
+ * pciio connection point, or process
+ * it as a generic pci error.
+ * Yes, the first parameter is the
+ * provider vertex at the middle of
+ * the bus; we get to the pciio connect
+ * point using the ioerror widgetdev field.
+ *
+ * This function is called by the
+ * specific PCI provider, after it has figured
+ * out where on the PCI bus (including which slot,
+ * if it can tell) the error came from.
+ */
+/*ARGSUSED */
+int
+pciio_error_handler(
+		       devfs_handle_t pciio_vhdl,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioerror)
+{
+    pciio_info_t            pciio_info;
+    devfs_handle_t            pconn_vhdl;
+#if USRPCI
+    devfs_handle_t            usrpci_v;
+#endif
+    pciio_slot_t            slot;
+
+    int                     retval;
+#ifdef EHE_ENABLE
+    error_state_t	    e_state;
+#endif /* EHE_ENABLE */
+
+#if DEBUG && ERROR_DEBUG
+    printk("%v: pciio_error_handler\n", pciio_vhdl);
+#endif
+
+    IOERR_PRINTF(printk(KERN_NOTICE "%v: PCI Bus Error: Error code: %d Error mode: %d\n",
+			 pciio_vhdl, error_code, mode));
+
+    /* If there is an error handler sitting on
+     * the "no-slot" connection point, give it
+     * first crack at the error. NOTE: it is
+     * quite possible that this function may
+     * do further refining of the ioerror.
+     */
+    pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE);
+    if (pciio_info && pciio_info->c_efunc) {
+	pconn_vhdl = pciio_info_dev_get(pciio_info);
+
+#ifdef EHE_ENABLE
+	e_state = error_state_get(pciio_vhdl);
+
+	if (e_state == ERROR_STATE_ACTION)
+	    (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE);
+
+	if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE)
+	    return(IOERROR_UNHANDLED);
+#endif 
+
+	retval = pciio_info->c_efunc
+	    (pciio_info->c_einfo, error_code, mode, ioerror);
+	if (retval != IOERROR_UNHANDLED)
+	    return retval;
+    }
+
+    /* Is the error associated with a particular slot?
+     */
+    if (IOERROR_FIELDVALID(ioerror, widgetdev)) {
+	short widgetdev;
+	/*
+	 * NOTE : 
+	 * widgetdev is a 4byte value encoded as slot in the higher order
+	 * 2 bytes and function in the lower order 2 bytes.
+	 */
+	IOERROR_GETVALUE(widgetdev, ioerror, widgetdev);
+	slot = pciio_widgetdev_slot_get(widgetdev);
+
+	/* If this slot has an error handler,
+	 * deliver the error to it.
+	 */
+	pciio_info = pciio_cardinfo_get(pciio_vhdl, slot);
+	if (pciio_info != NULL) {
+	    if (pciio_info->c_efunc != NULL) {
+
+		pconn_vhdl = pciio_info_dev_get(pciio_info);
+
+#ifdef EHE_ENABLE
+		e_state = error_state_get(pciio_vhdl);
+
+		if (e_state == ERROR_STATE_ACTION)
+		    (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE);
+
+		if (error_state_set(pconn_vhdl,e_state) ==
+		    ERROR_RETURN_CODE_CANNOT_SET_STATE)
+		    return(IOERROR_UNHANDLED);
+#endif /* EHE_ENABLE */
+
+		retval = pciio_info->c_efunc
+		    (pciio_info->c_einfo, error_code, mode, ioerror);
+		if (retval != IOERROR_UNHANDLED)
+		    return retval;
+	    }
+
+#if USRPCI
+	    /* If the USRPCI driver is available and
+	     * knows about this connection point,
+	     * deliver the error to it.
+	     *
+	     * OK to use pconn_vhdl here, even though we
+	     * have already UNREF'd it, since we know that
+	     * it is not going away.
+	     */
+	    pconn_vhdl = pciio_info_dev_get(pciio_info);
+	    if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) {
+		iopaddr_t busaddr;
+		IOERROR_GETVALUE(busaddr, ioerror, busaddr);
+		retval = usrpci_error_handler (usrpci_v, error_code, busaddr);
+		hwgraph_vertex_unref(usrpci_v);
+		if (retval != IOERROR_UNHANDLED) {
+		    /*
+		     * This unref is not needed.  If this code is called often enough,
+		     * the system will crash, due to vertex reference count reaching 0,
+		     * causing vertex to be unallocated.  -jeremy
+		     * hwgraph_vertex_unref(pconn_vhdl);
+		     */
+		    return retval;
+		}
+	    }
+#endif
+	}
+    }
+
+    return (mode == MODE_DEVPROBE)
+	? IOERROR_HANDLED	/* probes are OK */
+	: IOERROR_UNHANDLED;	/* otherwise, foo! */
+}
+
+/* =====================================================================
+ *          CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+pciio_provider_startup(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_startup)
+	(pciio_provider);
+}
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+pciio_provider_shutdown(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_shutdown)
+	(pciio_provider);
+}
+
+/*
+ * Specify endianness constraints.  The driver tells us what the device
+ * does and how it would like to see things in memory.  We reply with
+ * how things will actually appear in memory.
+ */
+pciio_endian_t
+pciio_endian_set(devfs_handle_t dev,
+		 pciio_endian_t device_end,
+		 pciio_endian_t desired_end)
+{
+    ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE));
+    ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));
+
+#if DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_ALERT  "%v: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#else
+    printk(KERN_ALERT  "0x%x: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#endif
+#endif
+
+    return DEV_FUNC(dev, endian_set)
+	(dev, device_end, desired_end);
+}
+
+/*
+ * Specify PCI arbitration priority.
+ */
+pciio_priority_t
+pciio_priority_set(devfs_handle_t dev,
+		   pciio_priority_t device_prio)
+{
+    ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW));
+
+    return DEV_FUNC(dev, priority_set)
+	(dev, device_prio);
+}
+
+/*
+ * Read value of configuration register
+ */
+uint64_t
+pciio_config_get(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size)
+{
+    uint64_t	value = 0;
+    unsigned	shift = 0;
+
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+
+	value |= DEV_FUNC(dev, config_get)
+	    (dev, reg, biw) << shift;
+
+	shift += 8*biw;
+	reg += biw;
+	size -= biw;
+    }
+    return value;
+}
+
+/*
+ * Change value of configuration register
+ */
+void
+pciio_config_set(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size,
+		 uint64_t	value)
+{
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+	    
+	DEV_FUNC(dev, config_set)
+	    (dev, reg, biw, value);
+	reg += biw;
+	size -= biw;
+	value >>= biw * 8;
+    }
+}
+
+/* =====================================================================
+ *          GENERIC PCI SUPPORT FUNCTIONS
+ */
+
+/*
+ * Issue a hardware reset to a card.
+ */
+int
+pciio_reset(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, reset) (dev);
+}
+
+/*
+ * flush write gather buffers
+ */
+int
+pciio_write_gather_flush(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, write_gather_flush) (dev);
+}
+
+devfs_handle_t
+pciio_intr_dev_get(pciio_intr_t pciio_intr)
+{
+    return (pciio_intr->pi_dev);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+pciio_pio_dev_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_dev);
+}
+
+pciio_slot_t
+pciio_pio_slot_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_slot);
+}
+
+pciio_space_t
+pciio_pio_space_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_space);
+}
+
+iopaddr_t
+pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_pciaddr);
+}
+
+ulong
+pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_mapsz);
+}
+
+caddr_t
+pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_kvaddr);
+}
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_dev);
+}
+
+pciio_slot_t
+pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_slot);
+}
+
+/****** Generic pci slot information interfaces ******/
+
+pciio_info_t
+pciio_info_chk(devfs_handle_t pciio)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo);
+    return (pciio_info_t) ainfo;
+}
+
+pciio_info_t
+pciio_info_get(devfs_handle_t pciio)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio);
+
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pciio, dname, 256);
+	printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    if ((pciio_info != NULL) &&
+	(pciio_info->c_fingerprint != pciio_info_fingerprint)
+	&& (pciio_info->c_fingerprint != NULL)) {
+
+	return((pciio_info_t)-1); /* Should panic .. */
+    }
+	
+
+    return pciio_info;
+}
+
+void
+pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info)
+{
+    if (pciio_info != NULL)
+	pciio_info->c_fingerprint = pciio_info_fingerprint;
+    hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info);
+
+    /* Also, mark this vertex as a PCI slot
+     * and use the pciio_info, so pciio_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO,
+			 (arbitrary_info_t) pciio_info);
+}
+
+devfs_handle_t
+pciio_info_dev_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vertex);
+}
+
+pciio_slot_t
+pciio_info_slot_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_slot);
+}
+
+pciio_function_t
+pciio_info_function_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_func);
+}
+
+pciio_vendor_id_t
+pciio_info_vendor_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vendor);
+}
+
+pciio_device_id_t
+pciio_info_device_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_device);
+}
+
+devfs_handle_t
+pciio_info_master_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_master);
+}
+
+arbitrary_info_t
+pciio_info_mfast_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_mfast);
+}
+
+pciio_provider_t       *
+pciio_info_pops_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_pops);
+}
+
+error_handler_f	       *
+pciio_info_efunc_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_efunc);
+}
+
+error_handler_arg_t    *
+pciio_info_einfo_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_einfo);
+}
+
+pciio_space_t
+pciio_info_bar_space_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_space;
+}
+
+iopaddr_t
+pciio_info_bar_base_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_base;
+}
+
+size_t
+pciio_info_bar_size_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_size;
+}
+
+iopaddr_t
+pciio_info_rom_base_get(pciio_info_t info)
+{
+    return info->c_rbase;
+}
+
+size_t
+pciio_info_rom_size_get(pciio_info_t info)
+{
+    return info->c_rsize;
+}
+
+
+/* =====================================================================
+ *          GENERIC PCI INITIALIZATION FUNCTIONS
+ */
+
+/*
+ *    pciioinit: called once during device driver
+ *      initializtion if this driver is configured into
+ *      the system.
+ */
+void
+pciio_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("pciio_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (pciio_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_PCI, "vendor", "device");
+	if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(pciio_registry != NULL);
+}
+
+/*
+ *    pciioattach: called for each vertex in the graph
+ *      that is a PCI provider.
+ */
+/*ARGSUSED */
+int
+pciio_attach(devfs_handle_t pciio)
+{
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_attach\n", pciio);
+#else
+    printk("0x%x: pciio_attach\n", pciio);
+#endif
+#endif
+    return 0;
+}
+
+/*
+ * Associate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns)
+{
+    hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns);
+}
+
+/*
+ * Disassociate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_unregister(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo;
+
+    hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo);
+}
+
+/*
+ * Obtain a pointer to the pciio_provider functions for a specified Crosstalk
+ * provider.
+ */
+pciio_provider_t       *
+pciio_provider_fns_get(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo);
+    return (pciio_provider_t *) ainfo;
+}
+
+/*ARGSUSED4 */
+int
+pciio_driver_register(
+			 pciio_vendor_id_t vendor_id,
+			 pciio_device_id_t device_id,
+			 char *driver_prefix,
+			 unsigned flags)
+{
+    /* a driver's init routine might call
+     * pciio_driver_register before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    return cdl_add_driver(pciio_registry,
+			  vendor_id, device_id,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Remove an initialization function.
+ */
+void
+pciio_driver_unregister(
+			   char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called register; so
+     * we can assume we have a registry here.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    cdl_del_driver(pciio_registry, driver_prefix, NULL);
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being registered.
+ */
+void
+pciio_driver_reg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being unregistered.
+ */
+void
+pciio_driver_unreg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+pciio_iterate(char *driver_prefix,
+	      pciio_iter_f * func)
+{
+    /* a driver's init routine might call
+     * pciio_iterate before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    ASSERT(pciio_registry != NULL);
+
+    cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func);
+}
+
+devfs_handle_t
+pciio_device_register(
+		devfs_handle_t connectpt,	/* vertex for /hw/.../pciio/%d */
+		devfs_handle_t master,	/* card's master ASIC (PCI provider) */
+		pciio_slot_t slot,	/* card's slot */
+		pciio_function_t func,	/* card's func */
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    return pciio_device_info_register
+	(connectpt, pciio_device_info_new (NULL, master, slot, func,
+					   vendor_id, device_id));
+}
+
+void
+pciio_device_unregister(devfs_handle_t pconn)
+{
+    DEV_FUNC(pconn,device_unregister)(pconn);
+}
+
+pciio_info_t
+pciio_device_info_new(
+		pciio_info_t pciio_info,
+		devfs_handle_t master,
+		pciio_slot_t slot,
+		pciio_function_t func,
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    if (!pciio_info)
+	GET_NEW(pciio_info);
+    ASSERT(pciio_info != NULL);
+
+    pciio_info->c_slot = slot;
+    pciio_info->c_func = func;
+    pciio_info->c_vendor = vendor_id;
+    pciio_info->c_device = device_id;
+    pciio_info->c_master = master;
+    pciio_info->c_mfast = hwgraph_fastinfo_get(master);
+    pciio_info->c_pops = pciio_provider_fns_get(master);
+    pciio_info->c_efunc = 0;
+    pciio_info->c_einfo = 0;
+
+    return pciio_info;
+}
+
+void
+pciio_device_info_free(pciio_info_t pciio_info)
+{
+    /* NOTE : pciio_info is a structure within the pcibr_info
+     *	      and not a pointer to memory allocated on the heap !!
+     */
+    BZERO((char *)pciio_info,sizeof(pciio_info));
+}
+
+devfs_handle_t
+pciio_device_info_register(
+		devfs_handle_t connectpt,		/* vertex at center of bus */
+		pciio_info_t pciio_info)	/* details about the connectpt */
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+    int device_master_set(devfs_handle_t, devfs_handle_t);
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_path_add(connectpt, name, &pconn))
+	return pconn;
+
+    pciio_info->c_vertex = pconn;
+    pciio_info_set(pconn, pciio_info);
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pconn, dname, 256);
+	printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    /*
+     * create link to our pci provider
+     */
+
+    device_master_set(pconn, pciio_info->c_master);
+
+#if USRPCI
+    /*
+     * Call into usrpci provider to let it initialize for
+     * the given slot.
+     */
+    if (pciio_info->c_slot != PCIIO_SLOT_NONE)
+	usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot);
+#endif
+
+    return pconn;
+}
+
+void
+pciio_device_info_unregister(devfs_handle_t connectpt,
+			     pciio_info_t pciio_info)
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+
+    if (!pciio_info)
+	return;
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    hwgraph_edge_remove(connectpt,name,&pconn);
+    pciio_info_set(pconn,0);
+
+    /* Remove the link to our pci provider */
+    hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL);
+
+
+    hwgraph_vertex_unref(pconn);
+    hwgraph_vertex_destroy(pconn);
+    
+}
+/* Add the pci card inventory information to the hwgraph
+ */
+static void
+pciio_device_inventory_add(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t	pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+
+    /* Donot add inventory  for non-existent devices */
+    if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE)	||
+	(pciio_info->c_device == PCIIO_DEVICE_ID_NONE))
+	return;
+    device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP,
+			 pciio_info->c_vendor,pciio_info->c_device,
+			 pciio_info->c_slot);
+}
+
+/*ARGSUSED */
+int
+pciio_device_attach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+
+    pciio_device_inventory_add(pconn);
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));
+}
+
+int
+pciio_device_detach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_del_connpt(pciio_registry, vendor_id, device_id,
+		          pconn, drv_flags));
+
+}
+
+/* SN2 */
+/*
+ * Allocate (if necessary) and initialize a PCI window mapping structure.
+ */
+pciio_win_map_t
+pciio_device_win_map_new(pciio_win_map_t win_map,
+			 size_t region_size,
+			 size_t page_size)
+{
+	ASSERT((page_size & (page_size - 1)) == 0);
+	ASSERT((region_size & (page_size - 1)) == 0);
+
+	if (win_map == NULL)
+		NEW(win_map);
+
+	/*
+	 * The map array tracks the free ``pages'' in the region.  The worst
+	 * case scenario is when every other page in the region is free --
+	 * e.i. maximum fragmentation.  This leads to (max pages + 1) / 2 + 1
+	 * map entries.  The first "+1" handles the divide by 2 rounding; the
+	 * second handles the need for an end marker sentinel.
+	 */
+	win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1);
+	win_map->wm_page_size = page_size;
+	ASSERT(win_map->wm_map != NULL);
+
+	return win_map;
+}
+
+/*
+ * Free resources associated with a PCI window mapping structure.
+ */
+extern void
+pciio_device_win_map_free(pciio_win_map_t win_map)
+{
+	rmfreemap(win_map->wm_map);
+	bzero(win_map, sizeof *win_map);
+}
+
+/*
+ * Populate window map with specified free range.
+ */
+void
+pciio_device_win_populate(pciio_win_map_t win_map,
+                          iopaddr_t ioaddr,
+                          size_t size)
+{
+	ASSERT((size & (win_map->wm_page_size - 1)) == 0);
+	ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0);
+
+	rmfree(win_map->wm_map,
+	       size / win_map->wm_page_size,
+	       (unsigned long)ioaddr / win_map->wm_page_size);
+	       
+}
+/*
+ * Allocate space from the specified PCI window mapping resource.  On
+ * success record information about the allocation in the supplied window
+ * allocation cookie (if non-NULL) and return the address of the allocated
+ * window.  On failure return NULL.
+ *
+ * The "size" parameter is usually from a PCI device's Base Address Register
+ * (BAR) decoder.  As such, the allocation must be aligned to be a multiple of
+ * that.  The "align" parameter acts as a ``minimum alignment'' allocation
+ * constraint.  The alignment contraint reflects system or device addressing
+ * restrictions such as the inability to share higher level ``windows''
+ * between devices, etc.  The returned PCI address allocation will be a
+ * multiple of the alignment constraint both in alignment and size.  Thus, the
+ * returned PCI address block is aligned to the maximum of the requested size
+ * and alignment.
+ */
+iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,
+		       pciio_win_alloc_t win_alloc,
+		       size_t start, size_t size, size_t align)
+{
+	unsigned long base;
+
+#ifdef PIC_LATER
+	ASSERT((size & (size - 1)) == 0);
+	ASSERT((align & (align - 1)) == 0);
+
+	/*
+	 * Convert size and alignment to pages.  If size is greated than the
+	 * requested alignment, we bump the alignment up to size; otherwise
+	 * convert the size into a multiple of the alignment request.
+	 */
+	size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size;
+	align = align / win_map->wm_page_size;
+	if (size > align)
+		align = size;
+	else
+		size = (size + align - 1) & ~(align - 1);
+
+	/* XXXX */
+	base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP);
+	if (base == RMALLOC_FAIL)
+		return((iopaddr_t)NULL);
+#else
+    int                 index_page, index_page_align;
+    int                 align_pages, size_pages;
+    int                 alloc_pages, free_pages;
+    int                 addr_align;
+
+    /* Convert PCI bus alignment from bytes to pages */
+    align_pages = align / win_map->wm_page_size;
+
+    /* Convert PCI request from bytes to pages */
+    size_pages = (size / win_map->wm_page_size) +
+                  ((size % win_map->wm_page_size) ? 1 : 0);
+
+    /* Align address with the larger of the size or the requested slot align */
+    if (size_pages > align_pages)
+        align_pages = size_pages;
+  
+    /*
+     * Avoid wasting space by aligning - 1; this will prevent crossing
+     * another alignment boundary.
+     */
+    alloc_pages = size_pages + (align_pages - 1);
+
+    /* Allocate PCI bus space in pages */
+    index_page = (int) rmalloc(win_map->wm_map,
+                               (size_t) alloc_pages);
+
+    /* Error if no PCI bus address space available */
+    if (!index_page)
+        return 0;
+
+    /* PCI bus address index starts at 0 */
+    index_page--;
+
+    /* Align the page offset as requested */
+    index_page_align = (index_page + (align_pages - 1)) -
+                       ((index_page + (align_pages - 1)) % align_pages);
+
+    free_pages = (align_pages - 1) - (index_page_align - index_page);
+
+    /* Free unused PCI bus pages adjusting the index to start at 1 */
+    rmfree(win_map->wm_map, 
+           free_pages,
+           (index_page_align + 1) + size_pages);
+
+    /* Return aligned PCI bus space in bytes */ 
+    addr_align = (index_page_align * win_map->wm_page_size); 
+    base = index_page;
+    size = alloc_pages - free_pages;
+#endif	/* PIC_LATER */
+
+	/*
+	 * If a window allocation cookie has been supplied, use it to keep
+	 * track of all the allocated space assigned to this window.
+	 */
+	if (win_alloc) {
+		win_alloc->wa_map = win_map;
+		win_alloc->wa_base = base;
+		win_alloc->wa_pages = size;
+	}
+
+	return base * win_map->wm_page_size;
+}
+
+/*
+ * Free the specified window allocation back into the PCI window mapping
+ * resource.  As noted above, we keep page addresses offset by 1 ...
+ */
+void
+pciio_device_win_free(pciio_win_alloc_t win_alloc)
+{
+	if (win_alloc->wa_pages)
+		rmfree(win_alloc->wa_map->wm_map,
+		       win_alloc->wa_pages,
+		       win_alloc->wa_base);
+}
+
+/*
+ * pciio_error_register:
+ * arrange for a function to be called with
+ * a specified first parameter plus other
+ * information when an error is encountered
+ * and traced to the pci slot corresponding
+ * to the connection point pconn.
+ *
+ * may also be called with a null function
+ * pointer to "unregister" the error handler.
+ *
+ * NOTE: subsequent calls silently overwrite
+ * previous data for this vertex. We assume that
+ * cooperating drivers, well, cooperate ...
+ */
+void
+pciio_error_register(devfs_handle_t pconn,
+		     error_handler_f *efunc,
+		     error_handler_arg_t einfo)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = pciio_info_get(pconn);
+    ASSERT(pciio_info != NULL);
+    pciio_info->c_efunc = efunc;
+    pciio_info->c_einfo = einfo;
+}
+
+/*
+ * Check if any device has been found in this slot, and return
+ * true or false
+ * vhdl is the vertex for the slot
+ */
+int
+pciio_slot_inuse(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+    if (pciio_info->c_vendor) {
+	/*
+	 * Non-zero value for vendor indicate
+	 * a board being found in this slot.
+	 */
+	return 1;
+    }
+    return 0;
+}
+
+int
+pciio_dma_enabled(devfs_handle_t pconn_vhdl)
+{
+	return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl);
+}
+
+int
+pciio_info_type1_get(pciio_info_t pci_info)
+{
+	return(0);
+}
+
+
+/*
+ * These are complementary Linux interfaces that takes in a pci_dev * as the 
+ * first arguement instead of devfs_handle_t.
+ */
+iopaddr_t               snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned);
+pciio_dmamap_t          snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned);
+void                    snia_pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+void                    snia_pciio_dmamap_done(pciio_dmamap_t);
+pciio_endian_t          snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end,
+					      pciio_endian_t desired_end);
+
+#include <linux/module.h>
+EXPORT_SYMBOL(snia_pciio_dmatrans_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_alloc);
+EXPORT_SYMBOL(snia_pciio_dmamap_free);
+EXPORT_SYMBOL(snia_pciio_dmamap_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_done);
+EXPORT_SYMBOL(snia_pciio_endian_set);
+
+int
+snia_pcibr_rrb_alloc(struct pci_dev *pci_dev,
+	int *count_vchan0,
+	int *count_vchan1)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+	return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1);
+}
+EXPORT_SYMBOL(snia_pcibr_rrb_alloc);
+
+pciio_endian_t
+snia_pciio_endian_set(struct pci_dev *pci_dev,
+	pciio_endian_t device_end,
+	pciio_endian_t desired_end)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+	
+	return DEV_FUNC(dev, endian_set)
+		(dev, device_end, desired_end);
+}
+
+iopaddr_t
+snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */
+                    device_desc_t dev_desc,     /* device descriptor */
+                    paddr_t paddr,      /* system physical address */
+                    size_t byte_count,  /* length */
+                    unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    /*
+     * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be 
+     * set.  Otherwise, it must not be set.  This applies to SN1 and SN2.
+     */
+    return DEV_FUNC(dev, dmatrans_addr)
+        (dev, dev_desc, paddr, byte_count, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);
+}
+
+pciio_dmamap_t
+snia_pciio_dmamap_alloc(struct pci_dev *pci_dev,  /* set up mappings for this device */
+                   device_desc_t dev_desc,      /* device descriptor */
+                   size_t byte_count_max,       /* max size of a mapping */
+                   unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    /*
+     * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be
+     * set.  Otherwise, it must not be set.  This applies to SN1 and SN2.
+     */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+        (dev, dev_desc, byte_count_max, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);
+}
+
+void
+snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,  /* use these mapping resources */
+                  paddr_t paddr,        /* map for this address */
+                  size_t byte_count)
+{                                       /* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+        (CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+void
+snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pic.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pic.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/pic.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,176 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_defs.h>
+#include <asm/sn/prio.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/ioc3.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+
+
+#define PCI_BUS_NO_1 1
+
+int pic_devflag = D_MP;
+
+extern int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, int, pcibr_soft_t *);
+extern void pcibr_driver_reg_callback(devfs_handle_t, int, int, int);
+extern void pcibr_driver_unreg_callback(devfs_handle_t, int, int, int);
+
+
+void
+pic_init(void)
+{
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pic_init()\n"));	
+
+	xwidget_driver_register(PIC_WIDGET_PART_NUM_BUS0,
+			    PIC_WIDGET_MFGR_NUM,
+			    "pic_",
+			    0);
+}
+
+int
+pic_attach(devfs_handle_t conn_v)
+{
+	int		rc;
+	bridge_t	*bridge0, *bridge1 = (bridge_t *)0;
+	devfs_handle_t	pcibr_vhdl0, pcibr_vhdl1 = (devfs_handle_t)0;
+	pcibr_soft_t	bus0_soft, bus1_soft = (pcibr_soft_t)0;
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n"));
+
+	bridge0 = (bridge_t *) xtalk_piotrans_addr(conn_v, NULL,
+	                        0, sizeof(bridge_t), 0);
+#ifdef	PCI_BUS_NO_1
+	bridge1 = (bridge_t *)((char *)bridge0 + PIC_BUS1_OFFSET);
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: bridge0=0x%x, bridge1=0x%x\n", 
+		    bridge0, bridge1));
+
+	/*
+	 * Create the vertex for the PCI buses, which we
+	 * will also use to hold the pcibr_soft and
+	 * which will be the "master" vertex for all the
+	 * pciio connection points we will hang off it.
+	 * This needs to happen before we call nic_bridge_vertex_info
+	 * as we are some of the *_vmc functions need access to the edges.
+	 *
+	 * Opening this vertex will provide access to
+	 * the Bridge registers themselves.
+	 */
+	/* FIXME: what should the hwgraph path look like ? */
+	rc = hwgraph_path_add(conn_v, EDGE_LBL_PCIX_0, &pcibr_vhdl0);
+	ASSERT(rc == GRAPH_SUCCESS);
+#ifdef	PCI_BUS_NO_1
+	rc = hwgraph_path_add(conn_v, EDGE_LBL_PCIX_1, &pcibr_vhdl1);
+	ASSERT(rc == GRAPH_SUCCESS);
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: pcibr_vhdl0=%v, pcibr_vhdl1=%v\n",
+		    pcibr_vhdl0, pcibr_vhdl1));
+
+	/* register pci provider array */
+	pciio_provider_register(pcibr_vhdl0, &pci_pic_provider);
+#ifdef	PCI_BUS_NO_1
+	pciio_provider_register(pcibr_vhdl1, &pci_pic_provider);
+#endif
+
+	pciio_provider_startup(pcibr_vhdl0);
+#ifdef	PCI_BUS_NO_1
+	pciio_provider_startup(pcibr_vhdl1);
+#endif
+
+	pcibr_attach2(conn_v, bridge0, pcibr_vhdl0, 0, &bus0_soft);
+#ifdef	PCI_BUS_NO_1
+	pcibr_attach2(conn_v, bridge1, pcibr_vhdl1, 1, &bus1_soft);
+#endif
+
+	/* save a pointer to the PIC's other bus's soft struct */
+#ifdef	PCI_BUS_NO_1
+        bus0_soft->bs_peers_soft = bus1_soft;
+        bus1_soft->bs_peers_soft = bus0_soft;
+#else
+        bus0_soft->bs_peers_soft = (pcibr_soft_t)0;
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: bus0_soft=0x%x, bus1_soft=0x%x\n",
+		    bus0_soft, bus1_soft));
+
+	return 0;
+}
+
+/*
+ * pci provider functions
+ *
+ * mostly in pcibr.c but if any are needed here then
+ * this might be a way to get them here.
+ */
+pciio_provider_t        pci_pic_provider =
+{
+    (pciio_piomap_alloc_f *) pcibr_piomap_alloc,
+    (pciio_piomap_free_f *) pcibr_piomap_free,
+    (pciio_piomap_addr_f *) pcibr_piomap_addr,
+    (pciio_piomap_done_f *) pcibr_piomap_done,
+    (pciio_piotrans_addr_f *) pcibr_piotrans_addr,
+    (pciio_piospace_alloc_f *) pcibr_piospace_alloc,
+    (pciio_piospace_free_f *) pcibr_piospace_free,
+
+    (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc,
+    (pciio_dmamap_free_f *) pcibr_dmamap_free,
+    (pciio_dmamap_addr_f *) pcibr_dmamap_addr,
+    (pciio_dmamap_list_f *) pcibr_dmamap_list,
+    (pciio_dmamap_done_f *) pcibr_dmamap_done,
+    (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr,
+    (pciio_dmatrans_list_f *) pcibr_dmatrans_list,
+    (pciio_dmamap_drain_f *) pcibr_dmamap_drain,
+    (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain,
+    (pciio_dmalist_drain_f *) pcibr_dmalist_drain,
+
+    (pciio_intr_alloc_f *) pcibr_intr_alloc,
+    (pciio_intr_free_f *) pcibr_intr_free,
+    (pciio_intr_connect_f *) pcibr_intr_connect,
+    (pciio_intr_disconnect_f *) pcibr_intr_disconnect,
+    (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get,
+
+    (pciio_provider_startup_f *) pcibr_provider_startup,
+    (pciio_provider_shutdown_f *) pcibr_provider_shutdown,
+    (pciio_reset_f *) pcibr_reset,
+    (pciio_write_gather_flush_f *) pcibr_write_gather_flush,
+    (pciio_endian_set_f *) pcibr_endian_set,
+    (pciio_priority_set_f *) pcibr_priority_set,
+    (pciio_config_get_f *) pcibr_config_get,
+    (pciio_config_set_f *) pcibr_config_set,
+    (pciio_error_devenable_f *) 0,
+    (pciio_error_extract_f *) 0,
+    (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback,
+    (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback,
+    (pciio_device_unregister_f 	*) pcibr_device_unregister,
+    (pciio_dma_enabled_f		*) pcibr_dma_enabled,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/sgi_io_init.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/sgi_io_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/sgi_io_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/sgi_io_init.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,230 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pciba.h>
+#include <linux/smp.h>
+
+extern void mlreset(void);
+extern int init_hcl(void);
+extern void klgraph_hack_init(void);
+extern void hubspc_init(void);
+extern void pciio_init(void);
+extern void pcibr_init(void);
+extern void xtalk_init(void);
+extern void xbow_init(void);
+extern void xbmon_init(void);
+extern void pciiox_init(void);
+extern void pic_init(void);
+extern void usrpci_init(void);
+extern void ioc3_init(void);
+extern void initialize_io(void);
+extern void klhwg_add_all_modules(devfs_handle_t);
+extern void klhwg_add_all_nodes(devfs_handle_t);
+
+void sn_mp_setup(void);
+extern devfs_handle_t hwgraph_root;
+extern void io_module_init(void);
+extern void pci_bus_cvlink_init(void);
+extern void temp_hack(void);
+
+extern int pci_bus_to_hcl_cvlink(void);
+
+/* #define DEBUG_IO_INIT 1 */
+#ifdef DEBUG_IO_INIT
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_IO_INIT */
+
+/*
+ * per_hub_init
+ *
+ * 	This code is executed once for each Hub chip.
+ */
+static void
+per_hub_init(cnodeid_t cnode)
+{
+	nasid_t		nasid;
+	nodepda_t	*npdap;
+	ii_icmr_u_t	ii_icmr;
+	ii_ibcr_u_t	ii_ibcr;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+	ASSERT(nasid != INVALID_NASID);
+	ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode);
+
+	npdap = NODEPDA(cnode);
+
+#ifdef BRINGUP2
+#if 0
+	while ((REMOTE_HUB_L(nasid, IIO_IFDR)) != 0x2d2d)
+		REMOTE_HUB_S(nasid, IIO_IFDR, 0xadad);
+#endif
+	printk("IIO_IFDR = 0x%x\n", REMOTE_HUB_L(nasid, IIO_IFDR));
+	REMOTE_HUB_S(nasid, IIO_IWEIM, 0x8000);
+#endif
+	/*
+	 * Set the total number of CRBs that can be used.
+	 */
+	ii_icmr.ii_icmr_regval= 0x0;
+	ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF;
+	REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval);
+
+	/*
+	 * Set the number of CRBs that both of the BTEs combined
+	 * can use minus 1.
+	 */
+	ii_ibcr.ii_ibcr_regval= 0x0;
+	ii_ibcr.ii_ibcr_fld_s.i_count = 0x8;
+	REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval);
+
+	/*
+	 * Set CRB timeout to be 10ms.
+	 */
+#ifdef BRINGUP2
+	REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff );
+	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
+	REMOTE_HUB_S(nasid, IIO_IDBSS, 0x504);
+	REMOTE_HUB_S(nasid, SH_DEBUG_SELECT, 0x0002DF6D74CF2C70);
+#endif
+
+	/* Initialize error interrupts for this hub. */
+	hub_error_init(cnode);
+}
+
+/*
+ * This routine is responsible for the setup of all the IRIX hwgraph style
+ * stuff that's been pulled into linux.  It's called by sn_pci_find_bios which
+ * is called just before the generic Linux PCI layer does its probing (by 
+ * platform_pci_fixup aka sn_pci_fixup).
+ *
+ * It is very IMPORTANT that this call is only made by the Master CPU!
+ *
+ */
+
+void
+sgi_master_io_infr_init(void)
+{
+	int cnode;
+
+	/*
+	 * Do any early init stuff .. einit_tbl[] etc.
+	 */
+	init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */
+
+	/*
+	 * initialize the Linux PCI to xwidget vertexes ..
+	 */
+	pci_bus_cvlink_init();
+
+#ifdef BRINGUP
+	/*
+	 * Hack to provide statically initialzed klgraph entries.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n");
+	klgraph_hack_init();
+#endif /* BRINGUP */
+
+	/*
+	 * This is the Master CPU.  Emulate mlsetup and main.c in Irix.
+	 */
+	mlreset();
+
+	/*
+	 * allowboot() is called by kern/os/main.c in main()
+	 * Emulate allowboot() ...
+	 *   per_cpu_init() - only need per_hub_init()
+	 *   cpu_io_setup() - Nothing to do.
+	 * 
+	 */
+	sn_mp_setup();
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		per_hub_init(cnode);
+	}
+
+	/* We can do headless hub cnodes here .. */
+
+	/*
+	 * io_init[] stuff.
+	 *
+	 * Get SGI IO Infrastructure drivers to init and register with 
+	 * each other etc.
+	 */
+
+	hubspc_init();
+	pciio_init();
+	pcibr_init();
+	pic_init();
+	xtalk_init();
+	xbow_init();
+	xbmon_init();
+	pciiox_init();
+	usrpci_init();
+	ioc3_init();
+
+	/*
+	 *
+	 * Our IO Infrastructure drivers are in place .. 
+	 * Initialize the whole IO Infrastructure .. xwidget/device probes.
+	 *
+	 */
+	initialize_io();
+	pci_bus_to_hcl_cvlink();
+
+#ifdef CONFIG_PCIBA
+	DBG("--> sgi_master_io_infr_init: calling pciba_init()\n");
+#ifndef BRINGUP2
+ 	pciba_init();
+#endif
+#endif
+}
+
+/*
+ * One-time setup for MP SN.
+ * Allocate per-node data, slurp prom klconfig information and
+ * convert it to hwgraph information.
+ */
+void
+sn_mp_setup(void)
+{
+	cpuid_t		cpu;
+
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		/* Skip holes in CPU space */
+		if (cpu_enabled(cpu)) {
+			init_platform_pda(cpu);
+		}
+	}
+
+	/*
+	 * Initialize platform-dependent vertices in the hwgraph:
+	 *	module
+	 *	node
+	 *	cpu
+	 *	memory
+	 *	slot
+	 *	hub
+	 *	router
+	 *	xbow
+	 */
+
+	io_module_init(); /* Use to be called module_init() .. */
+	klhwg_add_all_modules(hwgraph_root);
+	klhwg_add_all_nodes(hwgraph_root);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shub.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shub.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shub.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,233 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#ident  "$Revision: 1.167 $"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sal.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sndrv.h>
+
+/*
+ * Shub WAR for Xbridge Little Endian problem:
+ *	Xbridge has to run in BIG ENDIAN even with Shub.
+ */
+
+
+/*
+ * io_sh_swapper: Turn on Shub byte swapping.
+ *	All data destined to and from Shub to XIO are byte-swapped.
+ */
+void
+io_sh_swapper(nasid_t nasid, int onoff)
+{
+    ii_iwc_u_t      ii_iwc;
+
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+
+    ii_iwc.ii_iwc_fld_s.i_dma_byte_swap = onoff;
+    REMOTE_HUB_S(nasid, IIO_IWC, ii_iwc.ii_iwc_regval);
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+
+}
+
+/*
+ * io_get_sh_swapper: Return current Swap mode.
+ *	1 = Swap on, 0 = Swap off.
+ */
+int
+io_get_sh_swapper(nasid_t nasid)
+{
+    ii_iwc_u_t      ii_iwc;
+
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+    return(ii_iwc.ii_iwc_fld_s.i_dma_byte_swap);
+
+}
+
+#define SHUB_NUM_ECF_REGISTERS 8
+
+static uint32_t	shub_perf_counts[SHUB_NUM_ECF_REGISTERS];
+
+static shubreg_t shub_perf_counts_regs[SHUB_NUM_ECF_REGISTERS] = {
+	SH_PERFORMANCE_COUNTER0,
+	SH_PERFORMANCE_COUNTER1,
+	SH_PERFORMANCE_COUNTER2,
+	SH_PERFORMANCE_COUNTER3,
+	SH_PERFORMANCE_COUNTER4,
+	SH_PERFORMANCE_COUNTER5,
+	SH_PERFORMANCE_COUNTER6,
+	SH_PERFORMANCE_COUNTER7
+};
+
+static inline void
+shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val)
+{
+	int		   nasid = cnodeid_to_nasid(cnode);
+	volatile uint64_t *addr = (uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+
+	*addr = val;
+	__ia64_mf_a();
+}
+
+static inline void
+shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val)
+{
+	int		   nasid = cnodeid_to_nasid(cnode);
+	volatile uint32_t *addr = (uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+
+	*addr = val;
+	__ia64_mf_a();
+}
+
+static inline uint64_t
+shub_mmr_read(cnodeid_t cnode, shubreg_t reg)
+{
+	int		  nasid = cnodeid_to_nasid(cnode);
+	volatile uint64_t val;
+
+	val = *(uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+	__ia64_mf_a();
+
+	return val;
+}
+
+static inline uint32_t
+shub_mmr_read32(cnodeid_t cnode, shubreg_t reg)
+{
+	int		  nasid = cnodeid_to_nasid(cnode);
+	volatile uint32_t val;
+
+	val = *(uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+	__ia64_mf_a();
+
+	return val;
+}
+
+static int
+reset_shub_stats(cnodeid_t cnode)
+{
+	int i;
+
+	for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) {
+		shub_perf_counts[i] = 0;
+		shub_mmr_write32(cnode, shub_perf_counts_regs[i], 0);
+	}
+	return 0;
+}
+
+static int
+configure_shub_stats(cnodeid_t cnode, unsigned long arg)
+{
+	uint64_t	*p = (uint64_t *)arg;
+	uint64_t	i;
+	uint64_t	regcnt;
+	uint64_t	regval[2];
+
+	if (copy_from_user((void *)&regcnt, p, sizeof(regcnt)))
+	    return -EFAULT;
+
+	for (p++, i=0; i < regcnt; i++, p += 2) {
+		if (copy_from_user((void *)regval, (void *)p, sizeof(regval)))
+		    return -EFAULT;
+		if (regval[0] & 0x7) {
+		    printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]);
+		    return -EINVAL;
+		}
+		shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]);
+	}
+	return 0;
+}
+
+static int
+capture_shub_stats(cnodeid_t cnode, uint32_t *counts)
+{
+	int 		i;
+
+	for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) {
+		counts[i] = shub_mmr_read32(cnode, shub_perf_counts_regs[i]);
+	}
+	return 0;
+}
+
+static int
+shubstats_ioctl(struct inode *inode, struct file *file,
+        unsigned int cmd, unsigned long arg)
+{
+        cnodeid_t       cnode;
+        uint64_t        longarg;
+        devfs_handle_t  d;
+	int		nasid;
+
+        if ((d = devfs_get_handle_from_inode(inode)) == NULL)
+                return -ENODEV;
+        cnode = (cnodeid_t)hwgraph_fastinfo_get(d);
+
+        switch (cmd) {
+	case SNDRV_SHUB_CONFIGURE:
+		return configure_shub_stats(cnode, arg);
+		break;
+
+	case SNDRV_SHUB_RESETSTATS:
+		reset_shub_stats(cnode);
+		break;
+
+	case SNDRV_SHUB_INFOSIZE:
+		longarg = sizeof(shub_perf_counts);
+		if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) {
+		    return -EFAULT;
+		}
+		break;
+
+	case SNDRV_SHUB_GETSTATS:
+		capture_shub_stats(cnode, shub_perf_counts);
+		if (copy_to_user((void *)arg, shub_perf_counts,
+				       	sizeof(shub_perf_counts))) {
+		    return -EFAULT;
+		}
+		break;
+
+	case SNDRV_SHUB_GETNASID:
+		nasid = cnodeid_to_nasid(cnode);
+		if (copy_to_user((void *)arg, &nasid,
+				       	sizeof(nasid))) {
+		    return -EFAULT;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct file_operations shub_mon_fops = {
+	        ioctl:          shubstats_ioctl,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shub_intr.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shub_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shub_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shub_intr.c	2003-05-22 22:06:25.000000000 +0000
@@ -25,21 +25,13 @@
 #include <asm/sn/intr.h>
 #include <asm/sn/xtalk/xtalkaddrs.h>
 #include <asm/sn/klconfig.h>
+#include <asm/sn/sn2/shub_mmr.h>
 #include <asm/sn/sn_cpuid.h>
 
-extern void hub_device_desc_update(device_desc_t, ilvl_t, cpuid_t);
-
 /* ARGSUSED */
 void
 hub_intr_init(devfs_handle_t hubv)
 {
-	extern void sn_cpei_handler(int, void *, struct pt_regs *);
-	extern void sn_init_cpei_timer(void);
-
-	if (request_irq(SGI_SHUB_ERROR_VECTOR, sn_cpei_handler, 0, "SN hub error", NULL) ) {
-		printk("hub_intr_init: Couldn't register SGI_SHUB_ERROR_VECTOR = %x\n",SGI_SHUB_ERROR_VECTOR);
-	}
-	sn_init_cpei_timer();
 }
 
 xwidgetnum_t
@@ -82,11 +74,9 @@
 	cnode = cpuid_to_cnodeid(cpu);
 
 	if (slice) {
-		xtalk_addr = SH_II_INT1 | GLOBAL_MMR_SPACE |
-			((unsigned long)nasid << 36) | (1UL << 47);
+		xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47);
 	} else {
-		xtalk_addr = SH_II_INT0 | GLOBAL_MMR_SPACE |
-			((unsigned long)nasid << 36) | (1UL << 47);
+		xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47);
 	}
 
 	intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, cnode);
@@ -107,7 +97,6 @@
 	intr_hdl->i_bit = vector;
 	intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED;
 
-	hub_device_desc_update(dev_desc, intr_swlevel, cpu);
 	return(intr_hdl);
 }
 
@@ -150,6 +139,8 @@
 
 int
 hub_intr_connect(hub_intr_t intr_hdl,
+		intr_func_t intr_func,          /* xtalk intr handler */
+		void *intr_arg,                 /* arg to intr handler */
 		xtalk_intr_setfunc_t setfunc,
 		void *setfunc_arg)
 {
@@ -160,7 +151,6 @@
 	ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);
 
 	rv = intr_connect_level(cpu, vector, intr_hdl->i_swlevel, NULL);
-
 	if (rv < 0) {
 		return rv;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shuberror.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shuberror.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shuberror.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shuberror.c	2003-05-22 22:06:47.000000000 +0000
@@ -10,6 +10,8 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
 #include <asm/smp.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
@@ -34,12 +36,18 @@
 extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep);
 int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo);
 int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo);
-extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe);
+extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop);
 
 extern int maxcpus;
 
 #define HUB_ERROR_PERIOD        (120 * HZ)      /* 2 minutes */
 
+#ifdef BUS_INT_WAR
+void sn_add_polled_interrupt(int irq, int interval);
+void sn_delete_polled_interrupt(int irq);
+extern int bus_int_war_ide_irq;
+#endif
+
 
 void
 hub_error_clear(nasid_t nasid)
@@ -118,9 +126,7 @@
     hubinfo_t		hinfo; 
     cpuid_t		intr_cpu;
     devfs_handle_t 	hub_v;
-    ii_ilcsr_u_t	ilcsr;
     int bit_pos_to_irq(int bit);
-    int synergy_intr_connect(int bit, int cpuid);
 
 
     hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode);
@@ -130,17 +136,6 @@
     ASSERT(hinfo);
     ASSERT(hinfo->h_cnodeid == cnode);
 
-    ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR);
-
-    if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) {
-	/* 
-	 * HUB II link is not up. 
-	 * Just disable LLP, and don't connect any interrupts.
-	 */
-	ilcsr.ii_ilcsr_fld_s.i_llp_en = 0;
-	REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval);
-	return;
-    }
     /* Select a possible interrupt target where there is a free interrupt
      * bit and also reserve the interrupt bit for this IO error interrupt
      */
@@ -152,7 +147,11 @@
     }
 	
     rv = intr_connect_level(intr_cpu, bit, 0, NULL);
-    request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v);
+    request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN_hub_error", (void *)hub_v);
+    irq_desc(bit + (intr_cpu << 8))->status |= SN2_IRQ_PER_HUB;
+#ifdef BUS_INT_WAR                                              
+    sn_add_polled_interrupt(bit + (intr_cpu << 8), (0.01 * HZ));
+#endif
     ASSERT_ALWAYS(rv >= 0);
     hubio_eint.ii_iidsr_regval = 0;
     hubio_eint.ii_iidsr_fld_s.i_enable = 1;
@@ -257,15 +256,16 @@
 void
 hubiio_crb_free(hubinfo_t hinfo, int crbnum)
 {
-	ii_icrb0_a_u_t         icrba;
+	ii_icrb0_b_u_t         icrbb;
 
 	/*
 	* The hardware does NOT clear the mark bit, so it must get cleared
 	* here to be sure the error is not processed twice.
 	*/
-	icrba.ii_icrb0_a_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_A(crbnum));
-	icrba.a_valid   = 0;
-	REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_A(crbnum), icrba.ii_icrb0_a_regval);
+	icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_B(crbnum));
+	icrbb.b_mark   = 0;
+	REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval);
+
 	/*
 	* Deallocate the register.
 	*/
@@ -325,9 +325,11 @@
 	ii_icrb0_b_u_t		icrbb;		/* II CRB Register B */
 	ii_icrb0_c_u_t		icrbc;		/* II CRB Register C */
 	ii_icrb0_d_u_t		icrbd;		/* II CRB Register D */
+	ii_icrb0_e_u_t		icrbe;		/* II CRB Register D */
 	int		i;
 	int		num_errors = 0;	/* Num of errors handled */
 	ioerror_t	ioerror;
+	int		rc;
 
 	nasid = hinfo->h_nasid;
 	cnode = NASID_TO_COMPACT_NODEID(nasid);
@@ -337,16 +339,24 @@
 	 * in any of the CRBs marked.
 	 */
 	for (i = 0; i < IIO_NUM_CRBS; i++) {
+		/* Check this crb entry to see if it is in error. */
+		icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
+
+		if (icrbb.b_mark == 0) {
+			continue;
+		}
+
 		icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
 
 		IOERROR_INIT(&ioerror);
 
 		/* read other CRB error registers. */
-		icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
 		icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
 		icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
+		icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
 
 		IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode);
+
 		/* Check if this error is due to BTE operation,
 		* and handle it separately.
 		*/
@@ -363,8 +373,15 @@
 			else /* b_initiator bit 2 gives BTE number */
 				bte_num = (icrbb.b_initiator & 0x4) >> 2;
 
+			/* >>> bte_crb_error_handler needs to be 
+			 * broken into two parts.  The first should
+			 * cleanup the CRB.  The second should wait
+			 * until all bte related CRB's are complete
+			 * and then do the error reset.
+			 */
 			bte_crb_error_handler(hub_v, bte_num,
-					i, &ioerror);
+					      i, &ioerror,
+					      icrbd.d_bteop);
 			hubiio_crb_free(hinfo, i);
 			num_errors++;
 			continue;
@@ -401,13 +418,144 @@
 			 */
 			IOERROR_SETVALUE(&ioerror,widgetdev,
 					 TNUM_TO_WIDGET_DEV(icrba.a_tnum));
+			/*
+			* The encoding of TNUM (see comments above) is
+			* different for PIC. So we'll save TNUM here and
+			* deal with the differences later when we can
+			* determine if we're using a Bridge or the PIC.
+			*
+			* XXX:  We may be able to remove saving the widgetdev
+			* above and just sort it out of TNUM later.
+			*/
+			IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum);
+
+		}
+
+		if (icrbb.b_error) {
+		/* 
+		 * CRB 'i' has some error. Identify the type of error,
+		 * and try to handle it.
+		 */
+		switch(icrbb.b_ecode) {
+		case IIO_ICRB_ECODE_PERR:
+		case IIO_ICRB_ECODE_WERR:
+		case IIO_ICRB_ECODE_AERR:
+		case IIO_ICRB_ECODE_PWERR:
+
+			printk("%s on hub cnodeid: %d",
+				hubiio_crb_errors[icrbb.b_ecode], cnode);
+			/*
+			 * Any sort of write error is mostly due
+			 * bad programming (Note it's not a timeout.)
+			 * So, invoke hub_iio_error_handler with
+			 * appropriate information.
+			 */
+			IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode);
+
+			rc = hub_ioerror_handler(
+					hub_v, 
+					DMA_WRITE_ERROR, 
+					MODE_DEVERROR, 
+					&ioerror);
+
+                        if (rc == IOERROR_HANDLED) {
+                                rc = hub_ioerror_handler(
+                                        hub_v,
+                                        DMA_WRITE_ERROR,
+                                        MODE_DEVREENABLE,
+                                        &ioerror);
+                                ASSERT(rc == IOERROR_HANDLED);
+                        }else {
+
+				panic("Unable to handle %s on hub %d",
+					hubiio_crb_errors[icrbb.b_ecode],
+					cnode);
+				/*NOTREACHED*/
+			}
+			/* Go to Next error */
+			hubiio_crb_free(hinfo, i);
+			continue;
+
+		case IIO_ICRB_ECODE_PRERR:
+
+                case IIO_ICRB_ECODE_TOUT:
+                case IIO_ICRB_ECODE_XTERR:
+
+		case IIO_ICRB_ECODE_DERR:
+			panic("Fatal %s on hub : %d",
+				hubiio_crb_errors[icrbb.b_ecode], cnode);
+			/*NOTREACHED*/
+		
+		default:
+			panic("Fatal error (code : %d) on hub : %d",
+				cnode);
+			/*NOTREACHED*/
+
+		}
+		} 	/* if (icrbb.b_error) */	
 
+		/*
+		 * Error is not indicated via the errcode field 
+		 * Check other error indications in this register.
+		 */
+		
+		if (icrbb.b_xerr) {
+			panic("Xtalk Packet with error bit set to hub %d",
+				cnode);
+			/*NOTREACHED*/
+		}
+
+		if (icrbb.b_lnetuce) {
+			panic("Uncorrectable data error detected on data "
+				" from Craylink to node %d",
+				cnode);
+			/*NOTREACHED*/
 		}
 
 	}
 	return	num_errors;
 }
 
+/*
+ * hubii_check_widget_disabled
+ *
+ *	Check if PIO access to the specified widget is disabled due
+ *	to any II errors that are currently set.
+ *
+ *	The specific error bits checked are:
+ *		IPRBx register: SPUR_RD (51)
+ *				SPUR_WR (50)
+ *				RD_TO (49)
+ *				ERROR (48)
+ *
+ *		WSTAT register: CRAZY (32)
+ */
+
+int
+hubii_check_widget_disabled(nasid_t nasid, int wnum)
+{
+	iprb_t		iprb;
+	ii_wstat_u_t	wstat;
+
+	iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum));
+	if (iprb.iprb_regval & (IIO_PRB_SPUR_RD | IIO_PRB_SPUR_WR |
+		IIO_PRB_RD_TO | IIO_PRB_ERROR)) {
+#ifdef DEBUG
+	    printk(KERN_WARNING "II error, IPRB%x=0x%lx\n", wnum, iprb.iprb_regval);
+#endif
+	    return(1);
+	}
+
+	wstat.ii_wstat_regval = REMOTE_HUB_L(nasid, IIO_WSTAT);
+	if (wstat.ii_wstat_regval & IIO_WSTAT_ECRAZY) {
+#ifdef DEBUG
+	    printk(KERN_WARNING "II error, WSTAT=0x%lx\n", wstat.ii_wstat_regval);
+#endif
+	    return(1);
+	}
+	return(0);
+}
+
 /*ARGSUSED*/
 /*
  * hubii_prb_handler
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shubio.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shubio.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shubio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/shubio.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,510 @@
+/* $Id: shubio.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/smp.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/ioerror.h>
+#include <asm/sn/sn2/shubio.h>
+
+
+error_state_t error_state_get(devfs_handle_t v);
+error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state);
+
+
+/*
+ * Get the xtalk provider function pointer for the
+ * specified hub.
+ */
+
+/*ARGSUSED*/
+int
+hub_xp_error_handler(
+	devfs_handle_t 	hub_v, 
+	nasid_t		nasid, 
+	int		error_code, 
+	ioerror_mode_t	mode, 
+	ioerror_t	*ioerror)
+{
+	/*REFERENCED*/
+	hubreg_t	iio_imem;
+	devfs_handle_t	xswitch;
+	error_state_t	e_state;
+	cnodeid_t	cnode;
+
+	/*
+	 * Before walking down to the next level, check if
+	 * the I/O link is up. If it's been disabled by the 
+	 * hub ii for some reason, we can't even touch the
+	 * widget registers.
+	 */
+	iio_imem = REMOTE_HUB_L(nasid, IIO_IMEM);
+
+	if (!(iio_imem & (IIO_IMEM_B0ESD|IIO_IMEM_W0ESD))){
+		/* 
+		 * IIO_IMEM_B0ESD getting set, indicates II shutdown
+		 * on HUB0 parts.. Hopefully that's not true for 
+		 * Hub1 parts..
+		 *
+		 *
+		 * If either one of them is shut down, can't
+		 * go any further.
+		 */
+		return IOERROR_XTALKLEVEL;
+	}
+
+	/* Get the error state of the hub */
+	e_state = error_state_get(hub_v);
+
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+	xswitch = NODEPDA(cnode)->basew_xc;
+
+	/* Set the error state of the crosstalk device to that of
+	 * hub.
+	 */
+	if (error_state_set(xswitch , e_state) == 
+	    ERROR_RETURN_CODE_CANNOT_SET_STATE)
+		return(IOERROR_UNHANDLED);
+
+	/* Clean the error state of the hub if we are in the action handling
+	 * phase.
+	 */
+	if (e_state == ERROR_STATE_ACTION)
+		(void)error_state_set(hub_v, ERROR_STATE_NONE);
+	/* hand the error off to the switch or the directly
+	 * connected crosstalk device.
+	 */
+	return  xtalk_error_handler(xswitch,
+				    error_code, mode, ioerror);
+
+}
+
+/* 
+ * Check if the widget in error has been enabled for PIO accesses
+ */
+int
+is_widget_pio_enabled(ioerror_t *ioerror)
+{
+	cnodeid_t	src_node;
+	nasid_t		src_nasid;
+	hubreg_t	ii_iowa;
+	xwidgetnum_t	widget;
+	iopaddr_t	p;
+
+	/* Get the node where the PIO error occurred */
+	IOERROR_GETVALUE(p,ioerror, srcnode);
+	src_node = p;
+	if (src_node == CNODEID_NONE)
+		return(0);
+
+	/* Get the nasid for the cnode */
+	src_nasid = COMPACT_TO_NASID_NODEID(src_node);
+	if (src_nasid == INVALID_NASID)
+		return(0);
+
+	/* Read the Outbound widget access register for this hub */
+	ii_iowa = REMOTE_HUB_L(src_nasid, IIO_IOWA);
+	IOERROR_GETVALUE(p,ioerror, widgetnum);
+	widget = p;
+
+	/* Check if the PIOs to the widget with PIO error have been
+	 * enabled.
+	 */
+	if (ii_iowa & IIO_IOWA_WIDGET(widget))
+		return(1);
+
+	return(0);
+}
+
+/*
+ * Hub IO error handling.
+ *
+ *	Gets invoked for different types of errors found at the hub. 
+ *	Typically this includes situations from bus error or due to 
+ *	an error interrupt (mostly generated at the hub).
+ */
+int
+hub_ioerror_handler(
+	devfs_handle_t 	hub_v, 
+	int		error_code,
+	int		mode,
+	struct io_error_s	*ioerror)
+{
+	hubinfo_t 	hinfo; 		/* Hub info pointer */
+	nasid_t		nasid;
+	int		retval = 0;
+	/*REFERENCED*/
+	iopaddr_t 	p;
+
+	IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror);
+
+	hubinfo_get(hub_v, &hinfo);
+
+	if (!hinfo){
+		/* Print an error message and return */
+		goto end;
+	}
+	nasid = hinfo->h_nasid;
+
+	switch(error_code) {
+
+	case PIO_READ_ERROR:
+		/* 
+		 * Cpu got a bus error while accessing IO space.
+		 * hubaddr field in ioerror structure should have
+		 * the IO address that caused access error.
+		 */
+
+		/*
+		 * Identify if  the physical address in hub_error_data
+		 * corresponds to small/large window, and accordingly,
+		 * get the xtalk address.
+		 */
+
+		/*
+		 * Evaluate the widget number and the widget address that
+		 * caused the error. Use 'vaddr' if it's there.
+		 * This is typically true either during probing
+		 * or a kernel driver getting into trouble. 
+		 * Otherwise, use paddr to figure out widget details
+		 * This is typically true for user mode bus errors while
+		 * accessing I/O space.
+		 */
+		 IOERROR_GETVALUE(p,ioerror,vaddr);
+		 if (p){
+		    /* 
+		     * If neither in small window nor in large window range,
+		     * outright reject it.
+		     */
+		    IOERROR_GETVALUE(p,ioerror,vaddr);
+		    if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+			widgetnum = SWIN_WIDGETNUM(hubaddr);
+			xtalkaddr = SWIN_WIDGETADDR(hubaddr);
+			/* 
+			 * differentiate local register vs IO space access
+			 */
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+
+
+		    } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){
+			/* 
+			 * Address corresponds to large window space. 
+			 * Convert it to xtalk address.
+			 */
+			int		bigwin;
+			hub_piomap_t    bw_piomap;
+			xtalk_piomap_t	xt_pmap = NULL;
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+
+			/*
+			 * Have to loop to find the correct xtalk_piomap 
+			 * because the're not allocated on a one-to-one
+			 * basis to the window number.
+			 */
+			for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
+				bw_piomap = hubinfo_bwin_piomap_get(hinfo,
+								    bigwin);
+
+				if (bw_piomap->hpio_bigwin_num ==
+				    (BWIN_WINDOWNUM(hubaddr) - 1)) {
+					xt_pmap = hub_piomap_xt_piomap(bw_piomap);
+					break;
+				}
+			}
+
+			ASSERT(xt_pmap);
+
+			widgetnum = xtalk_pio_target_get(xt_pmap);
+			xtalkaddr = xtalk_pio_xtalk_addr_get(xt_pmap) + BWIN_WIDGETADDR(hubaddr);
+
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+
+			/* 
+			 * Make sure that widgetnum doesnot map to hub 
+			 * register widget number, as we never use
+			 * big window to access hub registers. 
+			 */
+			ASSERT(widgetnum != HUB_REGISTER_WIDGET);
+		    }
+		} else if (IOERROR_FIELDVALID(ioerror,hubaddr)) {
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+			if (BWIN_WINDOWNUM(hubaddr)){
+				int 	window = BWIN_WINDOWNUM(hubaddr) - 1;
+				hubreg_t itte;
+				itte = (hubreg_t)HUB_L(IIO_ITTE_GET(nasid, window));
+				widgetnum =  (itte >> IIO_ITTE_WIDGET_SHIFT) & 
+						IIO_ITTE_WIDGET_MASK;
+				xtalkaddr = (((itte >> IIO_ITTE_OFFSET_SHIFT) &
+					IIO_ITTE_OFFSET_MASK) << 
+					     BWIN_SIZE_BITS) +
+					BWIN_WIDGETADDR(hubaddr);
+			} else {
+				widgetnum = SWIN_WIDGETNUM(hubaddr);
+				xtalkaddr = SWIN_WIDGETADDR(hubaddr);
+			}
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+		} else {
+			IOERROR_DUMP("hub_ioerror_handler", error_code, 
+						mode, ioerror);
+			IOERR_PRINTF(printk(
+				"hub_ioerror_handler: Invalid address passed"));
+
+			return IOERROR_INVALIDADDR;
+		}
+
+
+		IOERROR_GETVALUE(p,ioerror,widgetnum);
+		if ((p) == HUB_REGISTER_WIDGET) {
+			/* 
+			 * Error in accessing Hub local register
+			 * This should happen mostly in SABLE mode..
+			 */
+			retval = 0;
+		} else {
+			/* Make sure that the outbound widget access for this
+			 * widget is enabled.
+			 */
+			if (!is_widget_pio_enabled(ioerror)) {
+				if (error_state_get(hub_v) == 
+				    ERROR_STATE_ACTION)
+					ioerror_dump("No outbound widget"
+						     " access - ", 
+						     error_code, mode, ioerror);
+				return(IOERROR_HANDLED);
+			}
+		  
+
+			retval = hub_xp_error_handler(
+				hub_v, nasid, error_code, mode, ioerror);
+
+		}
+
+		IOERR_PRINTF(printk(
+			"hub_ioerror_handler:PIO_READ_ERROR return: %d",
+				retval));
+
+		break;
+
+	case PIO_WRITE_ERROR:
+		/*
+		 * This hub received an interrupt indicating a widget 
+		 * attached to this hub got a timeout. 
+		 * widgetnum field should be filled to indicate the
+		 * widget that caused error.
+		 *
+		 * NOTE: This hub may have nothing to do with this error.
+		 * We are here since the widget attached to the xbow 
+		 * gets its PIOs through this hub.
+		 *
+		 * There is nothing that can be done at this level. 
+		 * Just invoke the xtalk error handling mechanism.
+		 */
+		IOERROR_GETVALUE(p,ioerror,widgetnum);
+		if ((p) == HUB_REGISTER_WIDGET) {
+		} else {
+			/* Make sure that the outbound widget access for this
+			 * widget is enabled.
+			 */
+
+			if (!is_widget_pio_enabled(ioerror)) {
+				if (error_state_get(hub_v) == 
+				    ERROR_STATE_ACTION)
+					ioerror_dump("No outbound widget"
+						     " access - ", 
+						     error_code, mode, ioerror);
+				return(IOERROR_HANDLED);
+			}
+		  
+			retval = hub_xp_error_handler(
+				hub_v, nasid, error_code, mode, ioerror);
+		}
+		break;
+	
+	case DMA_READ_ERROR:
+		/* 
+		 * DMA Read error always ends up generating an interrupt
+		 * at the widget level, and never at the hub level. So,
+		 * we don't expect to come here any time
+		 */
+		ASSERT(0);
+		retval = IOERROR_UNHANDLED;
+		break;
+
+	case DMA_WRITE_ERROR:
+		/*
+		 * DMA Write error is generated when a write by an I/O 
+		 * device could not be completed. Problem is, device is
+		 * totally unaware of this problem, and would continue
+		 * writing to system memory. So, hub has a way to send
+		 * an error interrupt on the first error, and bitbucket
+		 * all further write transactions.
+		 * Coming here indicates that hub detected one such error,
+		 * and we need to handle it.
+		 *
+		 * Hub interrupt handler would have extracted physaddr, 
+		 * widgetnum, and widgetdevice from the CRB 
+		 *
+		 * There is nothing special to do here, since gathering
+		 * data from crb's is done elsewhere. Just pass the 
+		 * error to xtalk layer.
+		 */
+		retval = hub_xp_error_handler(hub_v, nasid, error_code, mode,
+					      ioerror);
+		break;
+	
+	default:
+		ASSERT(0);
+		return IOERROR_BADERRORCODE;
+	
+	}
+	
+	/*
+	 * If error was not handled, we may need to take certain action
+	 * based on the error code.
+	 * For e.g. in case of PIO_READ_ERROR, we may need to release the
+	 * PIO Read entry table (they are sticky after errors).
+	 * Similarly other cases. 
+	 *
+	 * Further Action TBD 
+	 */
+end:	
+	if (retval == IOERROR_HWGRAPH_LOOKUP) {
+		/*
+		 * If we get errors very early, we can't traverse
+		 * the path using hardware graph. 
+		 * To handle this situation, we need a functions
+		 * which don't depend on the hardware graph vertex to 
+		 * handle errors. This break the modularity of the
+		 * existing code. Instead we print out the reason for
+		 * not handling error, and return. On return, all the
+		 * info collected would be dumped. This should provide 
+		 * sufficient info to analyse the error.
+		 */
+		printk("Unable to handle IO error: hardware graph not setup\n");
+	}
+
+	return retval;
+}
+
+#define L_BITSMINOR 18
+#define L_MAXMAJ 0x1ff
+#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ)
+#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0)
+
+#define INFO_LBL_ERROR_STATE    "error_state"
+
+#define v_error_state_get(v,s)                                          \
+(hwgraph_info_get_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t *)&s))
+
+#define v_error_state_set(v,s,replace)                                  \
+(replace ?                                                              \
+hwgraph_info_replace_LBL(v,INFO_LBL_ERROR_STATE,(arbitrary_info_t)s,0) :\
+hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s))
+
+
+#define v_error_state_clear(v)                                          \
+(hwgraph_info_remove_LBL(v,INFO_LBL_ERROR_STATE,0))
+
+/*
+ * error_state_get
+ *              Get the state of the vertex.
+ *              Returns ERROR_STATE_INVALID on failure
+ *                      current state otherwise
+ */
+error_state_t
+error_state_get(devfs_handle_t v)
+{
+        error_state_t   s;
+
+        /* Check if we have a valid hwgraph vertex */
+        if (!dev_is_vertex(v))
+                return(ERROR_STATE_NONE);
+
+        /* Get the labelled info hanging off the vertex which corresponds
+         * to the state.
+         */
+        if (v_error_state_get(v, s) != GRAPH_SUCCESS) {
+                return(ERROR_STATE_NONE);
+        }
+        return(s);
+}
+
+
+/*
+ * error_state_set
+ *              Set the state of the vertex
+ *              Returns ERROR_RETURN_CODE_CANNOT_SET_STATE on failure
+ *                      ERROR_RETURN_CODE_SUCCESS otherwise
+ */
+error_return_code_t
+error_state_set(devfs_handle_t v,error_state_t new_state)
+{
+        error_state_t   old_state;
+        boolean_t       replace = B_TRUE;
+
+        /* Check if we have a valid hwgraph vertex */
+        if (!dev_is_vertex(v))
+                return(ERROR_RETURN_CODE_GENERAL_FAILURE);
+
+
+        /* This means that the error state needs to be cleaned */
+        if (new_state == ERROR_STATE_NONE) {
+                /* Make sure that we have an error state */
+                if (v_error_state_get(v,old_state) == GRAPH_SUCCESS)
+                        v_error_state_clear(v);
+                return(ERROR_RETURN_CODE_SUCCESS);
+        }
+
+        /* Check if the state information has been set at least once
+         * for this vertex.
+         */
+        if (v_error_state_get(v,old_state) != GRAPH_SUCCESS)
+                replace = B_FALSE;
+
+        if (v_error_state_set(v,new_state,replace) != GRAPH_SUCCESS) {
+                return(ERROR_RETURN_CODE_CANNOT_SET_STATE);
+        }
+        return(ERROR_RETURN_CODE_SUCCESS);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/xbow.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/xbow.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/xbow.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/xbow.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,1642 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/sn2/shubio.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/simulator.h>
+
+/* #define DEBUG		1 */
+/* #define XBOW_DEBUG	1 */
+/* #define DEBUG_ERROR	1 */
+
+
+/*
+ * Files needed to get the device driver entry points
+ */
+
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+
+#include <asm/sn/prio.h>
+#include <asm/sn/hcl_util.h>
+
+
+#define NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DEL(ptr)	(kfree(ptr))
+
+int                     xbow_devflag = D_MP;
+
+/*
+ * This file supports the Xbow chip.  Main functions: initializtion,
+ * error handling, and GBR.
+ */
+
+/*
+ * each vertex corresponding to an xbow chip
+ * has a "fastinfo" pointer pointing at one
+ * of these things.
+ */
+typedef struct xbow_soft_s *xbow_soft_t;
+
+struct xbow_soft_s {
+    devfs_handle_t            conn;	/* our connection point */
+    devfs_handle_t            vhdl;	/* xbow's private vertex */
+    devfs_handle_t            busv;	/* the xswitch vertex */
+    xbow_t                 *base;	/* PIO pointer to crossbow chip */
+    char                   *name;	/* hwgraph name */
+
+    xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
+    xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
+    xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
+    spinlock_t              xbow_perf_lock;
+    int                     link_monitor;
+    widget_cfg_t	   *wpio[MAX_XBOW_PORTS];	/* cached PIO pointer */
+
+    /* Bandwidth allocation state. Bandwidth values are for the
+     * destination port since contention happens there.
+     * Implicit mapping from xbow ports (8..f) -> (0..7) array indices.
+     */
+    spinlock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
+    unsigned long long	    bw_hiwm[MAX_XBOW_PORTS];	/* hiwater mark values */
+    unsigned long long      bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */
+};
+
+#define xbow_soft_set(v,i)	hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))
+#define xbow_soft_get(v)	((xbow_soft_t)hwgraph_fastinfo_get((v)))
+
+/*
+ * Function Table of Contents
+ */
+
+void                    xbow_mlreset(xbow_t *);
+void                    xbow_init(void);
+int                     xbow_attach(devfs_handle_t);
+
+int                     xbow_open(devfs_handle_t *, int, int, cred_t *);
+int                     xbow_close(devfs_handle_t, int, int, cred_t *);
+
+int                     xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
+int                     xbow_unmap(devfs_handle_t, vhandl_t *);
+int                     xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
+
+int                     xbow_widget_present(xbow_t *, int);
+static int              xbow_link_alive(xbow_t *, int);
+devfs_handle_t            xbow_widget_lookup(devfs_handle_t, int);
+
+void                    xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
+
+
+
+void                    xbow_update_perf_counters(devfs_handle_t);
+xbow_perf_link_t       *xbow_get_perf_counters(devfs_handle_t);
+int                     xbow_enable_perf_counter(devfs_handle_t, int, int, int);
+xbow_link_status_t     *xbow_get_llp_status(devfs_handle_t);
+void                    xbow_update_llp_status(devfs_handle_t);
+
+int                     xbow_disable_llp_monitor(devfs_handle_t);
+int                     xbow_enable_llp_monitor(devfs_handle_t);
+int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
+                                unsigned long long, unsigned long long);
+static void		xbow_setwidint(xtalk_intr_t);
+void                    idbg_xbowregs(int64_t);
+
+xswitch_reset_link_f    xbow_reset_link;
+
+xswitch_provider_t      xbow_provider =
+{
+    xbow_reset_link,
+};
+
+/*
+ *    xbow_mlreset: called at mlreset time if the
+ *      platform specific code determines that there is
+ *      a crossbow in a critical path that must be
+ *      functional before the driver would normally get
+ *      the device properly set up.
+ *
+ *      what do we need to do, that the boot prom can
+ *      not be counted on to have already done, that is
+ *      generic across all platforms using crossbows?
+ */
+/*ARGSUSED */
+void
+xbow_mlreset(xbow_t * xbow)
+{
+}
+
+/*
+ *    xbow_init: called with the rest of the device
+ *      driver XXX_init routines. This platform *might*
+ *      have a Crossbow chip, or even several, but it
+ *      might have none. Register with the crosstalk
+ *      generic provider so when we encounter the chip
+ *      the right magic happens.
+ */
+void
+xbow_init(void)
+{
+
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_init\n");
+#endif
+
+    xwidget_driver_register(PXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+
+    xwidget_driver_register(XXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+    xwidget_driver_register(XBOW_WIDGET_PART_NUM,
+			    XBOW_WIDGET_MFGR_NUM,
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+}
+
+#ifdef XBRIDGE_REGS_SIM
+/*    xbow_set_simulated_regs: sets xbow regs as needed
+ *	for powering through the boot
+ */
+void
+xbow_set_simulated_regs(xbow_t *xbow, int port)
+{
+    /*
+     * turn on link
+     */
+    xbow->xb_link(port).link_status = (1<<31);
+    /*
+     * and give it a live widget too
+     */
+    xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT;
+    /*
+     * zero the link control reg
+     */
+    xbow->xb_link(port).link_control = 0x0;
+}
+#endif /* XBRIDGE_REGS_SIM */
+
+/*
+ *    xbow_attach: the crosstalk provider has
+ *      determined that there is a crossbow widget
+ *      present, and has handed us the connection
+ *      point for that vertex.
+ *
+ *      We not only add our own vertex, but add
+ *      some "xtalk switch" data to the switch
+ *      vertex (at the connect point's parent) if
+ *      it does not have any.
+ */
+
+/*ARGSUSED */
+int
+xbow_attach(devfs_handle_t conn)
+{
+    /*REFERENCED */
+    devfs_handle_t            vhdl;
+    devfs_handle_t            busv;
+    xbow_t                 *xbow;
+    xbow_soft_t             soft;
+    int                     port;
+    xswitch_info_t          info;
+    xtalk_intr_t            intr_hdl;
+    char                    devnm[MAXDEVNAME], *s;
+    xbowreg_t               id;
+    int                     rev;
+    int			    i;
+    int			    xbow_num;
+    static void xbow_errintr_handler(int, void *, struct pt_regs *);
+
+	
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: xbow_attach\n", conn);
+#else
+    printk("0x%x: xbow_attach\n", conn);
+#endif
+#endif
+
+    /*
+     * Get a PIO pointer to the base of the crossbow
+     * chip.
+     */
+#ifdef XBRIDGE_REGS_SIM
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t));
+    xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL);
+    /*
+     * turn on ports e and f like in a real live ibrick
+     */
+    xbow_set_simulated_regs(xbow, 0xe);
+    xbow_set_simulated_regs(xbow, 0xf);
+#else
+    xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0);
+#endif /* XBRIDGE_REGS_SIM */
+
+    /*
+     * Locate the "switch" vertex: it is the parent
+     * of our connection point.
+     */
+    busv = hwgraph_connectpt_get(conn);
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);
+#endif
+
+    ASSERT(busv != GRAPH_VERTEX_NONE);
+
+    /*
+     * Create our private vertex, and connect our
+     * driver information to it. This makes it possible
+     * for diagnostic drivers to open the crossbow
+     * vertex for access to registers.
+     */
+
+    /*
+     * We need to teach xbow drivers to provide the right set of
+     * file ops.
+     */
+    vhdl = NULL;
+    vhdl = hwgraph_register(conn, EDGE_LBL_XBOW,
+                        0, DEVFS_FL_AUTO_DEVNUM,
+                        0, 0,
+                        S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                        /* &hcl_fops */ (void *)&vhdl, NULL);
+    if (!vhdl) {
+        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
+                (void *)conn);
+    }
+
+    /*
+     * Allocate the soft state structure and attach
+     * it to the xbow's vertex
+     */
+    NEW(soft);
+    soft->conn = conn;
+    soft->vhdl = vhdl;
+    soft->busv = busv;
+    soft->base = xbow;
+    /* does the universe really need another macro?  */
+    /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */
+    hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft);
+
+#define XBOW_NUM_SUFFIX_FORMAT	"[xbow# %d]"
+
+    /* Add xbow number as a suffix to the hwgraph name of the xbow.
+     * This is helpful while looking at the error/warning messages.
+     */
+    xbow_num = 0;
+
+    /*
+     * get the name of this xbow vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(vhdl, devnm, MAXDEVNAME);
+    soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, 
+			    GFP_KERNEL);
+    sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num);
+
+#ifdef XBRIDGE_REGS_SIM
+    /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined
+     * as 0xd000, so I'm using that for the partnum bitfield.
+     */
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n");
+    id = 0x2d000049;
+#else
+    id = xbow->xb_wid_id;
+#endif /* XBRIDGE_REGS_SIM */
+    rev = XWIDGET_PART_REV_NUM(id);
+
+    mutex_spinlock_init(&soft->xbow_perf_lock);
+    soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
+    soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;
+
+    /* Initialization for GBR bw allocation */
+    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);
+
+#define	XBOW_8_BIT_PORT_BW_MAX		(400 * 1000 * 1000)	/* 400 MB/s */
+#define XBOW_16_BIT_PORT_BW_MAX		(800 * 1000 * 1000)	/* 800 MB/s */
+
+    /* Set bandwidth hiwatermark and current values */
+    for (i = 0; i < MAX_XBOW_PORTS; i++) {
+	soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX;	/* for now */
+	soft->bw_cur_used[i] = 0;
+    }
+
+     /*
+      * attach the crossbow error interrupt.
+      */
+     intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl);
+     ASSERT(intr_hdl != NULL);
+ 
+     xtalk_intr_connect(intr_hdl,
+                        (intr_func_t) xbow_errintr_handler,
+                        (intr_arg_t) soft,
+                        (xtalk_intr_setfunc_t) xbow_setwidint,
+                        (void *) xbow);
+
+#ifdef BUS_INT_WAR_NOT_YET
+     request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid,
+			((hub_intr_t)intr_hdl)->i_bit),
+			(intr_func_t)xbow_errintr_handler, 0, "XBOW error",
+			(intr_arg_t) soft);
+
+    {
+	void sn_add_polled_interrupt(int, int);
+        sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid,
+                                ((hub_intr_t)intr_hdl)->i_bit), 5000);
+    }
+#endif
+
+ 
+    /*
+     * Enable xbow error interrupts
+     */
+    xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE);
+
+    /*
+     * take a census of the widgets present,
+     * leaving notes at the switch vertex.
+     */
+    info = xswitch_info_new(busv);
+
+    for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	 port < MAX_PORT_NUM; ++port) {
+	if (!xbow_link_alive(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is not alive\n",
+		    (void *)busv, port);
+#endif
+	    continue;
+	}
+	if (!xbow_widget_present(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", (void *)busv, port);
+#endif
+	    continue;
+	}
+#if DEBUG && XBOW_DEBUG
+	printk(KERN_INFO "0x%p link %d has a widget\n",
+		(void *)busv, port);
+#endif
+
+	xswitch_info_link_is_ok(info, port);
+	/*
+	 * Turn some error interrupts on
+	 * and turn others off. The PROM has
+	 * some things turned on we don't
+	 * want to see (bandwidth allocation
+	 * errors for instance); so if it
+	 * is not listed here, it is not on.
+	 */
+	xbow->xb_link(port).link_control =
+	    ( (xbow->xb_link(port).link_control
+	/*
+	 * Turn off these bits; they are non-fatal,
+	 * but we might want to save some statistics
+	 * on the frequency of these errors.
+	 * XXX FIXME XXX
+	 */
+	    & ~XB_CTRL_RCV_CNT_OFLOW_IE
+	    & ~XB_CTRL_XMT_CNT_OFLOW_IE
+	    & ~XB_CTRL_BNDWDTH_ALLOC_IE
+	    & ~XB_CTRL_RCV_IE)
+	/*
+	 * These are the ones we want to turn on.
+	 */
+	    | (XB_CTRL_ILLEGAL_DST_IE
+	    | XB_CTRL_OALLOC_IBUF_IE
+	    | XB_CTRL_XMT_MAX_RTRY_IE
+	    | XB_CTRL_MAXREQ_TOUT_IE
+	    | XB_CTRL_XMT_RTRY_IE
+	    | XB_CTRL_SRC_TOUT_IE) );
+    }
+
+    xswitch_provider_register(busv, &xbow_provider);
+
+    return 0;				/* attach successful */
+}
+
+/*ARGSUSED */
+int
+xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
+{
+    devfs_handle_t            vhdl = dev_to_vhdl(dev);
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    int                     error;
+
+    ASSERT(soft);
+    len = ctob(btoc(len));
+    /* XXX- this ignores the offset!!! */
+    error = v_mapphys(vt, (void *) soft->base, len);
+    return error;
+}
+
+/*ARGSUSED */
+int
+xbow_unmap(devfs_handle_t dev, vhandl_t *vt)
+{
+    return 0;
+}
+
+/* This contains special-case code for grio. There are plans to make
+ * this general sometime in the future, but till then this should
+ * be good enough.
+ */
+xwidgetnum_t
+xbow_widget_num_get(devfs_handle_t dev)
+{
+	devfs_handle_t	tdev;
+	char		devname[MAXDEVNAME];
+	xwidget_info_t	xwidget_info;
+	int		i;
+
+	vertex_to_name(dev, devname, MAXDEVNAME);
+
+	/* If this is a pci controller vertex, traverse up using
+	 * the ".." links to get to the widget.
+	 */
+	if (strstr(devname, EDGE_LBL_PCI) &&
+			strstr(devname, EDGE_LBL_CONTROLLER)) {
+		tdev = dev;
+		for (i=0; i< 2; i++) {
+			if (hwgraph_edge_get(tdev,
+				HWGRAPH_EDGELBL_DOTDOT, &tdev) !=
+					GRAPH_SUCCESS)
+				return XWIDGET_NONE;
+		}
+
+		if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) {
+			return (xwidget_info_id_get(xwidget_info));
+		} else {
+			return XWIDGET_NONE;
+		}
+	}
+
+	return XWIDGET_NONE;
+}
+
+int
+xbow_ioctl(devfs_handle_t dev,
+	   int cmd,
+	   void *arg,
+	   int flag,
+	   struct cred *cr,
+	   int *rvalp)
+{
+    devfs_handle_t            vhdl;
+    int                     error = 0;
+
+#if defined (DEBUG)
+    int                     rc;
+    devfs_handle_t            conn;
+    struct xwidget_info_s  *xwidget_info;
+    xbow_soft_t             xbow_soft;
+#endif
+    *rvalp = 0;
+
+    vhdl = dev_to_vhdl(dev);
+#if defined (DEBUG)
+    xbow_soft = xbow_soft_get(vhdl);
+    conn = xbow_soft->conn;
+
+    xwidget_info = xwidget_info_get(conn);
+    ASSERT_ALWAYS(xwidget_info != NULL);
+
+    rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid);
+    ASSERT_ALWAYS(rc != 0);
+#endif
+    switch (cmd) {
+
+    case XBOWIOC_LLP_ERROR_ENABLE:
+	if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    case XBOWIOC_LLP_ERROR_DISABLE:
+
+	if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    default:
+	break;
+
+    }
+    return error;
+}
+
+/*
+ * xbow_widget_present: See if a device is present
+ * on the specified port of this crossbow.
+ */
+int
+xbow_widget_present(xbow_t *xbow, int port)
+{
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		if ( (port == 14) || (port == 15) ) {
+			return 1;
+		}
+		else {
+			return 0;
+		}
+	}
+	else {
+		/* WAR: port 0xf on PIC is missing present bit */
+		if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) &&
+					IS_PIC_XBOW(xbow->xb_wid_id) && port==0xf) {
+			return 1;
+		}
+		return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT;
+	}
+}
+
+static int
+xbow_link_alive(xbow_t * xbow, int port)
+{
+    xbwX_stat_t             xbow_linkstat;
+
+    xbow_linkstat.linkstatus = xbow->xb_link(port).link_status;
+    return (xbow_linkstat.link_alive);
+}
+
+/*
+ * xbow_widget_lookup
+ *      Lookup the edges connected to the xbow specified, and
+ *      retrieve the handle corresponding to the widgetnum
+ *      specified.
+ *      If not found, return 0.
+ */
+devfs_handle_t
+xbow_widget_lookup(devfs_handle_t vhdl,
+		   int widgetnum)
+{
+    xswitch_info_t          xswitch_info;
+    devfs_handle_t            conn;
+
+    xswitch_info = xswitch_info_get(vhdl);
+    conn = xswitch_info_vhdl_get(xswitch_info, widgetnum);
+    return conn;
+}
+
+/*
+ * xbow_setwidint: called when xtalk
+ * is establishing or migrating our
+ * interrupt service.
+ */
+static void
+xbow_setwidint(xtalk_intr_t intr)
+{
+    xwidgetnum_t            targ = xtalk_intr_target_get(intr);
+    iopaddr_t               addr = xtalk_intr_addr_get(intr);
+    xtalk_intr_vector_t     vect = xtalk_intr_vector_get(intr);
+    xbow_t                 *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr);
+
+    xbow_intr_preset((void *) xbow, 0, targ, addr, vect);
+}
+
+/*
+ * xbow_intr_preset: called during mlreset time
+ * if the platform specific code needs to route
+ * an xbow interrupt before the xtalk infrastructure
+ * is available for use.
+ *
+ * Also called from xbow_setwidint, so we don't
+ * replicate the guts of the routine.
+ *
+ * XXX- probably should be renamed xbow_wid_intr_set or
+ * something to reduce confusion.
+ */
+/*ARGSUSED3 */
+void
+xbow_intr_preset(void *which_widget,
+		 int which_widget_intr,
+		 xwidgetnum_t targ,
+		 iopaddr_t addr,
+		 xtalk_intr_vector_t vect)
+{
+    xbow_t                 *xbow = (xbow_t *) which_widget;
+
+    xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) |
+			      (0x000F0000 & (targ << 16)) |
+			      XTALK_ADDR_TO_UPPER(addr));
+    xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
+
+#ifdef BRINGUP2
+printk("xbow_intr_preset: xb_wid_int_upper 0x%lx xb_wid_int_lower 0x%lx\n",
+	(long)(((0xFF000000 & (vect << 24)) | (0x000F0000 & (targ << 16)) |XTALK_ADDR_TO_UPPER(addr))), (long)XTALK_ADDR_TO_LOWER(addr));
+#endif
+}
+
+#define	XEM_ADD_STR(s)		printk("%s", (s))
+#define	XEM_ADD_NVAR(n,v)	printk("\t%20s: 0x%llx\n", (n), ((unsigned long long)v))
+#define	XEM_ADD_VAR(v)		XEM_ADD_NVAR(#v,(v))
+#define XEM_ADD_IOEF(p,n)	if (IOERROR_FIELDVALID(ioe,n)) {	\
+				    IOERROR_GETVALUE(p,ioe,n);		\
+				    XEM_ADD_NVAR("ioe." #n, p);		\
+				}
+
+#ifdef LATER
+static void
+xem_add_ioe(ioerror_t *ioe)
+{
+    union tmp {
+	ushort stmp;
+	unsigned long long lltmp;
+	cpuid_t cputmp;
+	cnodeid_t cntmp;
+	iopaddr_t iotmp;
+	caddr_t catmp;
+	paddr_t patmp;
+    } tmp;
+
+    XEM_ADD_IOEF(tmp.stmp, errortype);
+    XEM_ADD_IOEF(tmp.stmp, widgetnum);
+    XEM_ADD_IOEF(tmp.stmp, widgetdev);
+    XEM_ADD_IOEF(tmp.cputmp, srccpu);
+    XEM_ADD_IOEF(tmp.cntmp, srcnode);
+    XEM_ADD_IOEF(tmp.cntmp, errnode);
+    XEM_ADD_IOEF(tmp.iotmp, sysioaddr);
+    XEM_ADD_IOEF(tmp.iotmp, xtalkaddr);
+    XEM_ADD_IOEF(tmp.iotmp, busspace);
+    XEM_ADD_IOEF(tmp.iotmp, busaddr);
+    XEM_ADD_IOEF(tmp.catmp, vaddr);
+    XEM_ADD_IOEF(tmp.patmp, memaddr);
+    XEM_ADD_IOEF(tmp.catmp, epc);
+    XEM_ADD_IOEF(tmp.catmp, ef);
+    XEM_ADD_IOEF(tmp.stmp, tnum);
+}
+
+#define XEM_ADD_IOE()   (xem_add_ioe(ioe))
+#endif	/* LATER */
+
+int                     xbow_xmit_retry_errors = 0;
+
+int
+xbow_xmit_retry_error(xbow_soft_t soft,
+		      int port)
+{
+    xswitch_info_t          info;
+    devfs_handle_t            vhdl;
+    widget_cfg_t           *wid;
+    widgetreg_t             id;
+    int                     part;
+    int                     mfgr;
+
+    wid = soft->wpio[port - BASE_XBOW_PORT];
+    if (wid == NULL) {
+	/* If we can't track down a PIO
+	 * pointer to our widget yet,
+	 * leave our caller knowing that
+	 * we are interested in this
+	 * interrupt if it occurs in
+	 * the future.
+	 */
+	info = xswitch_info_get(soft->busv);
+	if (!info)
+	    return 1;
+	vhdl = xswitch_info_vhdl_get(info, port);
+	if (vhdl == GRAPH_VERTEX_NONE)
+	    return 1;
+	wid = (widget_cfg_t *) xtalk_piotrans_addr
+	    (vhdl, 0, 0, sizeof *wid, 0);
+	if (!wid)
+	    return 1;
+	soft->wpio[port - BASE_XBOW_PORT] = wid;
+    }
+    id = wid->w_id;
+    part = XWIDGET_PART_NUM(id);
+    mfgr = XWIDGET_MFG_NUM(id);
+
+    /* If this thing is not a Bridge,
+     * do not activate the WAR, and
+     * tell our caller we do not need
+     * to be called again.
+     */
+    if ((part != BRIDGE_WIDGET_PART_NUM) ||
+	(mfgr != BRIDGE_WIDGET_MFGR_NUM)) {
+		/* FIXME: add Xbridge to the WAR.
+		 * Shouldn't hurt anything.  Later need to
+		 * check if we can remove this.
+                 */
+    		if ((part != XBRIDGE_WIDGET_PART_NUM) ||
+		    (mfgr != XBRIDGE_WIDGET_MFGR_NUM))
+			return 0;
+    }
+
+    /* count how many times we
+     * have picked up after
+     * LLP Transmit problems.
+     */
+    xbow_xmit_retry_errors++;
+
+    /* rewrite the control register
+     * to fix things up.
+     */
+    wid->w_control = wid->w_control;
+    wid->w_control;
+
+    return 1;
+}
+
+/*
+ * xbow_errintr_handler will be called if the xbow
+ * sends an interrupt request to report an error.
+ */
+static void
+xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep)
+{
+    ioerror_t               ioe[1];
+    xbow_soft_t             soft = (xbow_soft_t) arg;
+    xbow_t                 *xbow = soft->base;
+    xbowreg_t               wid_control;
+    xbowreg_t               wid_stat;
+    xbowreg_t               wid_err_cmdword;
+    xbowreg_t               wid_err_upper;
+    xbowreg_t               wid_err_lower;
+    w_err_cmd_word_u        wid_err;
+    unsigned long long      wid_err_addr;
+
+    int                     fatal = 0;
+    int                     dump_ioe = 0;
+    static int xbow_error_handler(void *, int, ioerror_mode_t, ioerror_t *);
+
+    wid_control = xbow->xb_wid_control;
+    wid_stat = xbow->xb_wid_stat_clr;
+    wid_err_cmdword = xbow->xb_wid_err_cmdword;
+    wid_err_upper = xbow->xb_wid_err_upper;
+    wid_err_lower = xbow->xb_wid_err_lower;
+    xbow->xb_wid_err_cmdword = 0;
+
+    wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32);
+
+    if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) {
+	int                     port;
+
+	wid_err.r = wid_err_cmdword;
+
+	for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	     port < MAX_PORT_NUM; port++) {
+	    if (wid_stat & XB_WID_STAT_LINK_INTR(port)) {
+		xb_linkregs_t          *link = &(xbow->xb_link(port));
+		xbowreg_t               link_control = link->link_control;
+		xbowreg_t               link_status = link->link_status_clr;
+		xbowreg_t               link_aux_status = link->link_aux_status;
+		xbowreg_t               link_pend;
+
+		link_pend = link_status & link_control &
+		    (XB_STAT_ILLEGAL_DST_ERR
+		     | XB_STAT_OALLOC_IBUF_ERR
+		     | XB_STAT_RCV_CNT_OFLOW_ERR
+		     | XB_STAT_XMT_CNT_OFLOW_ERR
+		     | XB_STAT_XMT_MAX_RTRY_ERR
+		     | XB_STAT_RCV_ERR
+		     | XB_STAT_XMT_RTRY_ERR
+		     | XB_STAT_MAXREQ_TOUT_ERR
+		     | XB_STAT_SRC_TOUT_ERR
+		    );
+
+		if (link_pend & XB_STAT_ILLEGAL_DST_ERR) {
+		    if (wid_err.f.sidn == port) {
+			IOERROR_INIT(ioe);
+			IOERROR_SETVALUE(ioe, widgetnum, port);
+			IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr);
+			if (IOERROR_HANDLED ==
+			    xbow_error_handler(soft,
+					       IOECODE_DMA,
+					       MODE_DEVERROR,
+					       ioe)) {
+			    link_pend &= ~XB_STAT_ILLEGAL_DST_ERR;
+			} else {
+			    dump_ioe++;
+			}
+		    }
+		}
+		/* Xbow/Bridge WAR:
+		 * if the bridge signals an LLP Transmitter Retry,
+		 * rewrite its control register.
+		 * If someone else triggers this interrupt,
+		 * ignore (and disable) the interrupt.
+		 */
+		if (link_pend & XB_STAT_XMT_RTRY_ERR) {
+		    if (!xbow_xmit_retry_error(soft, port)) {
+			link_control &= ~XB_CTRL_XMT_RTRY_IE;
+			link->link_control = link_control;
+			link->link_control;	/* stall until written */
+		    }
+		    link_pend &= ~XB_STAT_XMT_RTRY_ERR;
+		}
+		if (link_pend) {
+		    devfs_handle_t	xwidget_vhdl;
+		    char		*xwidget_name;
+		    
+		    /* Get the widget name corresponding to the current
+		     * xbow link.
+		     */
+		    xwidget_vhdl = xbow_widget_lookup(soft->busv,port);
+		    xwidget_name = xwidget_name_get(xwidget_vhdl);
+
+		    printk("%s port %X[%s] XIO Bus Error",
+			    soft->name, port, xwidget_name);
+		    if (link_status & XB_STAT_MULTI_ERR)
+			XEM_ADD_STR("\tMultiple Errors\n");
+		    if (link_status & XB_STAT_ILLEGAL_DST_ERR)
+			XEM_ADD_STR("\tInvalid Packet Destination\n");
+		    if (link_status & XB_STAT_OALLOC_IBUF_ERR)
+			XEM_ADD_STR("\tInput Overallocation Error\n");
+		    if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR)
+			XEM_ADD_STR("\tLLP receive error counter overflow\n");
+		    if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR)
+			XEM_ADD_STR("\tLLP transmit retry counter overflow\n");
+		    if (link_status & XB_STAT_XMT_MAX_RTRY_ERR)
+			XEM_ADD_STR("\tLLP Max Transmitter Retry\n");
+		    if (link_status & XB_STAT_RCV_ERR)
+			XEM_ADD_STR("\tLLP Receiver error\n");
+		    if (link_status & XB_STAT_XMT_RTRY_ERR)
+			XEM_ADD_STR("\tLLP Transmitter Retry\n");
+		    if (link_status & XB_STAT_MAXREQ_TOUT_ERR)
+			XEM_ADD_STR("\tMaximum Request Timeout\n");
+		    if (link_status & XB_STAT_SRC_TOUT_ERR)
+			XEM_ADD_STR("\tSource Timeout Error\n");
+
+		    {
+			int                     other_port;
+
+			for (other_port = 8; other_port < 16; ++other_port) {
+			    if (link_aux_status & (1 << other_port)) {
+				/* XXX- need to go to "other_port"
+				 * and clean up after the timeout?
+				 */
+				XEM_ADD_VAR(other_port);
+			    }
+			}
+		    }
+
+#if !DEBUG
+		    if (kdebug) {
+#endif
+			XEM_ADD_VAR(link_control);
+			XEM_ADD_VAR(link_status);
+			XEM_ADD_VAR(link_aux_status);
+
+#ifdef LATER
+			if (dump_ioe) {
+			    XEM_ADD_IOE();
+			    dump_ioe = 0;
+			}
+#endif
+#if !DEBUG
+		    }
+#endif
+		    fatal++;
+		}
+	    }
+	}
+    }
+    if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) {
+	/* we have a "widget zero" problem */
+
+	if (wid_stat & (XB_WID_STAT_MULTI_ERR
+			| XB_WID_STAT_XTALK_ERR
+			| XB_WID_STAT_REG_ACC_ERR)) {
+
+	    printk("%s Port 0 XIO Bus Error",
+		    soft->name);
+	    if (wid_stat & XB_WID_STAT_MULTI_ERR)
+		XEM_ADD_STR("\tMultiple Error\n");
+	    if (wid_stat & XB_WID_STAT_XTALK_ERR)
+		XEM_ADD_STR("\tXIO Error\n");
+	    if (wid_stat & XB_WID_STAT_REG_ACC_ERR)
+		XEM_ADD_STR("\tRegister Access Error\n");
+
+	    fatal++;
+	}
+    }
+    if (fatal) {
+	XEM_ADD_VAR(wid_stat);
+	XEM_ADD_VAR(wid_control);
+	XEM_ADD_VAR(wid_err_cmdword);
+	XEM_ADD_VAR(wid_err_upper);
+	XEM_ADD_VAR(wid_err_lower);
+	XEM_ADD_VAR(wid_err_addr);
+	PRINT_PANIC("XIO Bus Error");
+    }
+}
+
+/*
+ * XBOW ERROR Handling routines.
+ * These get invoked as part of walking down the error handling path
+ * from hub/heart towards the I/O device that caused the error.
+ */
+
+/*
+ * xbow_error_handler
+ *      XBow error handling dispatch routine.
+ *      This is the primary interface used by external world to invoke
+ *      in case of an error related to a xbow.
+ *      Only functionality in this layer is to identify the widget handle
+ *      given the widgetnum. Otherwise, xbow does not gathers any error
+ *      data.
+ */
+static int
+xbow_error_handler(
+		      void *einfo,
+		      int error_code,
+		      ioerror_mode_t mode,
+		      ioerror_t *ioerror)
+{
+    int                     retval = IOERROR_WIDGETLEVEL;
+
+    xbow_soft_t             soft = (xbow_soft_t) einfo;
+    int                     port;
+    devfs_handle_t          conn;
+    devfs_handle_t          busv;
+
+    xbow_t                 *xbow = soft->base;
+    xbowreg_t               wid_stat;
+    xbowreg_t               wid_err_cmdword;
+    xbowreg_t               wid_err_upper;
+    xbowreg_t               wid_err_lower;
+    unsigned long long      wid_err_addr;
+
+    xb_linkregs_t          *link;
+    xbowreg_t               link_control;
+    xbowreg_t               link_status;
+    xbowreg_t               link_aux_status;
+
+    ASSERT(soft != 0);
+    busv = soft->busv;
+
+#if DEBUG && ERROR_DEBUG
+    printk("%s: xbow_error_handler\n", soft->name, busv);
+#endif
+
+    IOERROR_GETVALUE(port, ioerror, widgetnum);
+
+    if (port == 0) {
+	/* error during access to xbow:
+	 * do NOT attempt to access xbow regs.
+	 */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on Crossbow at %s\n"
+		    "\tbut Crosbow never initiates DMA!",
+		    soft->name);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO controller\n"
+		    "\twith offset 0x%lx",
+		    soft->name, tmp);
+	}
+	/* caller will dump contents of ioerror
+	 * in DEBUG and kdebug kernels.
+	 */
+
+	return retval;
+    }
+    /*
+     * error not on port zero:
+     * safe to read xbow registers.
+     */
+    wid_stat = xbow->xb_wid_stat;
+    wid_err_cmdword = xbow->xb_wid_err_cmdword;
+    wid_err_upper = xbow->xb_wid_err_upper;
+    wid_err_lower = xbow->xb_wid_err_lower;
+
+    wid_err_addr =
+	wid_err_lower
+	| (((iopaddr_t) wid_err_upper
+	    & WIDGET_ERR_UPPER_ADDR_ONLY)
+	   << 32);
+
+    if ((port < BASE_XBOW_PORT) ||
+	(port >= MAX_PORT_NUM)) {
+
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on XIO port at %s/%d\n"
+		    "\tbut Crossbow does not support that port",
+		    soft->name, port);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT
+		    "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO port %d\n"
+		    "\t(which Crossbow does not support)"
+		    "\twith offset 0x%lx",
+		    soft->name, port, tmp);
+	}
+#if !DEBUG
+	if (kdebug) {
+#endif
+	    XEM_ADD_STR("Raw status values for Crossbow:\n");
+	    XEM_ADD_VAR(wid_stat);
+	    XEM_ADD_VAR(wid_err_cmdword);
+	    XEM_ADD_VAR(wid_err_upper);
+	    XEM_ADD_VAR(wid_err_lower);
+	    XEM_ADD_VAR(wid_err_addr);
+#if !DEBUG
+	}
+#endif
+
+	/* caller will dump contents of ioerror
+	 * in DEBUG and kdebug kernels.
+	 */
+
+	return retval;
+    }
+    /* access to valid port:
+     * ok to check port status.
+     */
+
+    link = &(xbow->xb_link(port));
+    link_control = link->link_control;
+    link_status = link->link_status;
+    link_aux_status = link->link_aux_status;
+
+    /* Check that there is something present
+     * in that XIO port.
+     */
+    /* WAR: PIC widget 0xf is missing prescense bit */
+    if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) &&
+		IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xf))
+		;
+    else
+    if (!(link_aux_status & XB_AUX_STAT_PRESENT)) {
+	/* nobody connected. */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on XIO port at %s/%d\n"
+		    "\tbut there is no device connected there.",
+		    soft->name, port);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT
+		    "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO port %d\n"
+		    "\t(which has no device connected)"
+		    "\twith offset 0x%lx",
+		    soft->name, port, tmp);
+	}
+#if !DEBUG
+	if (kdebug) {
+#endif
+	    XEM_ADD_STR("Raw status values for Crossbow:\n");
+	    XEM_ADD_VAR(wid_stat);
+	    XEM_ADD_VAR(wid_err_cmdword);
+	    XEM_ADD_VAR(wid_err_upper);
+	    XEM_ADD_VAR(wid_err_lower);
+	    XEM_ADD_VAR(wid_err_addr);
+	    XEM_ADD_VAR(port);
+	    XEM_ADD_VAR(link_control);
+	    XEM_ADD_VAR(link_status);
+	    XEM_ADD_VAR(link_aux_status);
+#if !DEBUG
+	}
+#endif
+	return retval;
+
+    }
+    /* Check that the link is alive.
+     */
+    if (!(link_status & XB_STAT_LINKALIVE)) {
+	iopaddr_t tmp;
+	/* nobody connected. */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	printk(KERN_ALERT
+		"%s%sError on XIO Bus %s port %d",
+		(error_code & IOECODE_DMA) ? "DMA " : "",
+		(error_code & IOECODE_PIO) ? "PIO " : "",
+		soft->name, port);
+
+	IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	if ((error_code & IOECODE_PIO) &&
+	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
+		printk("\tAccess attempted to offset 0x%lx\n", tmp);
+	}
+	if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD)
+	    XEM_ADD_STR("\tLink never came out of reset\n");
+	else
+	    XEM_ADD_STR("\tLink failed while transferring data\n");
+
+    }
+    /* get the connection point for the widget
+     * involved in this error; if it exists and
+     * is not our connectpoint, cycle back through
+     * xtalk_error_handler to deliver control to
+     * the proper handler (or to report a generic
+     * crosstalk error).
+     *
+     * If the downstream handler won't handle
+     * the problem, we let our upstream caller
+     * deal with it, after (in DEBUG and kdebug
+     * kernels) dumping the xbow state for this
+     * port.
+     */
+    conn = xbow_widget_lookup(busv, port);
+    if ((conn != GRAPH_VERTEX_NONE) &&
+	(conn != soft->conn)) {
+	retval = xtalk_error_handler(conn, error_code, mode, ioerror);
+	if (retval == IOERROR_HANDLED)
+	    return IOERROR_HANDLED;
+    }
+    if (mode == MODE_DEVPROBE)
+	return IOERROR_HANDLED;
+
+    if (retval == IOERROR_UNHANDLED) {
+	iopaddr_t tmp;
+	retval = IOERROR_PANIC;
+
+	printk(KERN_ALERT
+		"%s%sError on XIO Bus %s port %d",
+		(error_code & IOECODE_DMA) ? "DMA " : "",
+		(error_code & IOECODE_PIO) ? "PIO " : "",
+		soft->name, port);
+
+	IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	if ((error_code & IOECODE_PIO) &&
+	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
+	    printk("\tAccess attempted to offset 0x%lx\n", tmp);
+	}
+    }
+
+#if !DEBUG
+    if (kdebug) {
+#endif
+	XEM_ADD_STR("Raw status values for Crossbow:\n");
+	XEM_ADD_VAR(wid_stat);
+	XEM_ADD_VAR(wid_err_cmdword);
+	XEM_ADD_VAR(wid_err_upper);
+	XEM_ADD_VAR(wid_err_lower);
+	XEM_ADD_VAR(wid_err_addr);
+	XEM_ADD_VAR(port);
+	XEM_ADD_VAR(link_control);
+	XEM_ADD_VAR(link_status);
+	XEM_ADD_VAR(link_aux_status);
+#if !DEBUG
+    }
+#endif
+    /* caller will dump raw ioerror data
+     * in DEBUG and kdebug kernels.
+     */
+
+    return retval;
+}
+
+void
+xbow_update_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     link, i;
+
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
+	if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
+	    continue;
+
+	s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+	perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+
+	link = perf_reg.xb_perf.link_select;
+
+	(xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] +=
+	    ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK);
+	xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    }
+}
+
+xbow_perf_link_t       *
+xbow_get_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_link_t       *xbow_perf_link = xbow_soft->xbow_perflink;
+
+    return xbow_perf_link;
+}
+
+int
+xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_linkctrl_t         xbow_link_ctrl;
+    xbow_t                 *xbow = xbow_soft->base;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     i;
+
+    link -= BASE_XBOW_PORT;
+    if ((link < 0) || (link >= MAX_XBOW_PORTS))
+	return -1;
+
+    if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK))
+	return -1;
+
+    if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS))
+	return -1;
+
+    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+    if ((xbow_perf + counter)->xp_mode && mode) {
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	return -1;
+    }
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++) {
+	if (i == counter)
+	    continue;
+	if (((xbow_perf + i)->xp_link == link) &&
+	    ((xbow_perf + i)->xp_mode)) {
+	    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	    return -1;
+	}
+    }
+    xbow_perf += counter;
+
+    xbow_perf->xp_curlink = xbow_perf->xp_link = link;
+    xbow_perf->xp_curmode = xbow_perf->xp_mode = mode;
+
+    xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control;
+    xbow_link_ctrl.xb_linkcontrol.perf_mode = mode;
+    xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword;
+
+    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+    perf_reg.xb_perf.link_select = link;
+    *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
+    xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    return 0;
+}
+
+xbow_link_status_t     *
+xbow_get_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+
+    return xbow_llp_status;
+}
+
+void
+xbow_update_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+    xbow_t                 *xbow;
+    xbwX_stat_t             lnk_sts;
+    xbow_aux_link_status_t  aux_sts;
+    int                     link;
+    devfs_handle_t	    xwidget_vhdl;
+    char		   *xwidget_name;	
+
+    xbow = (xbow_t *) xbow_soft->base;
+    for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) {
+	/* Get the widget name corresponding the current link.
+	 * Note : 0 <= link < MAX_XBOW_PORTS(8).
+	 * 	  BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10)
+	 */
+	xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT);
+	xwidget_name = xwidget_name_get(xwidget_vhdl);
+	aux_sts.aux_linkstatus
+	    = xbow->xb_link_raw[link].link_aux_status;
+	lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr;
+
+	if (lnk_sts.link_alive == 0)
+	    continue;
+
+	xbow_llp_status->rx_err_count +=
+	    aux_sts.xb_aux_linkstatus.rx_err_cnt;
+
+	xbow_llp_status->tx_retry_count +=
+	    aux_sts.xb_aux_linkstatus.tx_retry_cnt;
+
+	if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
+#ifdef	LATER
+	    printk(KERN_WARNING  "link %d[%s]: bad status 0x%x\n",
+		    link, xwidget_name, lnk_sts.linkstatus);
+#endif
+	}
+    }
+}
+
+int
+xbow_disable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    int                     port;
+
+    for (port = 0; port < MAX_XBOW_PORTS; port++) {
+	xbow_soft->xbow_link_status[port].rx_err_count = 0;
+	xbow_soft->xbow_link_status[port].tx_retry_count = 0;
+    }
+
+    xbow_soft->link_monitor = 0;
+    return 0;
+}
+
+int
+xbow_enable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+
+    xbow_soft->link_monitor = 1;
+    return 0;
+}
+
+
+int
+xbow_reset_link(devfs_handle_t xconn_vhdl)
+{
+    xwidget_info_t          widget_info;
+    xwidgetnum_t            port;
+    xbow_t                 *xbow;
+    xbowreg_t               ctrl;
+    xbwX_stat_t             stat;
+    unsigned                itick;
+    unsigned                dtick;
+    static int              ticks_per_ms = 0;
+
+    if (!ticks_per_ms) {
+	itick = get_timestamp();
+	us_delay(1000);
+	ticks_per_ms = get_timestamp() - itick;
+    }
+    widget_info = xwidget_info_get(xconn_vhdl);
+    port = xwidget_info_id_get(widget_info);
+
+#ifdef XBOW_K1PTR			/* defined if we only have one xbow ... */
+    xbow = XBOW_K1PTR;
+#else
+    {
+	devfs_handle_t            xbow_vhdl;
+	xbow_soft_t             xbow_soft;
+
+	hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl);
+	xbow_soft = xbow_soft_get(xbow_vhdl);
+	xbow = xbow_soft->base;
+    }
+#endif
+
+    /*
+     * This requires three PIOs (reset the link, check for the
+     * reset, restore the control register for the link) plus
+     * 10us to wait for the reset. We allow up to 1ms for the
+     * widget to come out of reset before giving up and
+     * returning a failure.
+     */
+    ctrl = xbow->xb_link(port).link_control;
+    xbow->xb_link(port).link_reset = 0;
+    itick = get_timestamp();
+    while (1) {
+	stat.linkstatus = xbow->xb_link(port).link_status;
+	if (stat.link_alive)
+	    break;
+	dtick = get_timestamp() - itick;
+	if (dtick > ticks_per_ms) {
+	    return -1;			/* never came out of reset */
+	}
+	DELAY(2);			/* don't beat on link_status */
+    }
+    xbow->xb_link(port).link_control = ctrl;
+    return 0;
+}
+
+/*
+ * Dump xbow registers.
+ * input parameter is either a pointer to
+ * the xbow chip or the vertex handle for
+ * an xbow vertex.
+ */
+void
+idbg_xbowregs(int64_t regs)
+{
+    xbow_t                 *xbow;
+    int                     i;
+    xb_linkregs_t          *link;
+
+    xbow = (xbow_t *) regs;
+
+#ifdef LATER
+    qprintf("Printing xbow registers starting at 0x%x\n", xbow);
+    qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
+	    xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
+	    xbow->xb_wid_err_lower, xbow->xb_wid_control,
+	    xbow->xb_wid_req_timeout);
+    qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n",
+	    xbow->xb_wid_int_upper, xbow->xb_wid_int_lower,
+	    xbow->xb_wid_err_cmdword, xbow->xb_wid_llp,
+	    xbow->xb_wid_arb_reload);
+#endif
+
+    for (i = 8; i <= 0xf; i++) {
+	link = &xbow->xb_link(i);
+#ifdef LATER
+	qprintf("Link %d registers\n", i);
+	qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
+		link->link_control, link->link_status,
+		link->link_arb_upper, link->link_arb_lower,
+		link->link_aux_status);
+#endif
+    }
+}
+
+
+#define XBOW_ARB_RELOAD_TICKS		25
+					/* granularity: 4 MB/s, max: 124 MB/s */
+#define GRANULARITY			((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)
+
+#define XBOW_BYTES_TO_GBR(BYTES_per_s)	(int) (BYTES_per_s / GRANULARITY)
+
+#define XBOW_GBR_TO_BYTES(cnt)		(bandwidth_t) ((cnt) * GRANULARITY)
+
+#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec)	\
+			((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)
+
+#define XBOW_ARB_GBR_MAX		31
+
+#define ABS(x)				((x > 0) ? (x) : (-1 * x))
+					/* absolute value */
+
+int
+xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec)
+{
+    int                     gbr_granted;
+    int                     new_total_gbr;
+    int                     change_gbr;
+    bandwidth_t             new_total_bw;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n",
+		old_bytes_per_sec, bytes_per_sec);
+#endif	/* GRIO_DEBUG */
+
+    gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)),
+			old_bytes_per_sec);
+    new_total_bw = old_bytes_per_sec + bytes_per_sec;
+    new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)),
+			new_total_bw);
+
+    change_gbr = new_total_gbr - gbr_granted;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n",
+		gbr_granted, new_total_gbr, change_gbr);
+#endif	/* GRIO_DEBUG */
+
+    return (change_gbr);
+}
+
+/* Conversion from GBR to bytes */
+bandwidth_t
+xbow_gbr_to_bytes(int gbr)
+{
+    return (XBOW_GBR_TO_BYTES(gbr));
+}
+
+/* Given the vhdl for the desired xbow, the src and dest. widget ids
+ * and the req_bw value, this xbow driver entry point accesses the
+ * xbow registers and allocates the desired bandwidth if available.
+ *
+ * If bandwidth allocation is successful, return success else return failure.
+ */
+int
+xbow_prio_bw_alloc(devfs_handle_t vhdl,
+		xwidgetnum_t src_wid,
+		xwidgetnum_t dest_wid,
+		unsigned long long old_alloc_bw,
+		unsigned long long req_bw)
+{
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    volatile xbowreg_t     *xreg;
+    xbowreg_t               mask;
+    unsigned long           s;
+    int                     error = 0;
+    bandwidth_t             old_bw_BYTES, req_bw_BYTES;
+    xbowreg_t               old_xreg;
+    int                     old_bw_GBR, req_bw_GBR, new_bw_GBR;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n",
+		(int) vhdl, (int) src_wid, (int) dest_wid, req_bw);
+#endif
+
+    ASSERT(XBOW_WIDGET_IS_VALID(src_wid));
+    ASSERT(XBOW_WIDGET_IS_VALID(dest_wid));
+
+    s = mutex_spinlock(&soft->xbow_bw_alloc_lock);
+
+    /* Get pointer to the correct register */
+    xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid);
+
+    /* Get mask for GBR count value */
+    mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid);
+
+    req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw);
+    req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR)))
+		: xbow_gbr_to_bytes(req_bw_GBR);
+
+#ifdef GRIO_DEBUG
+    printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n",
+		req_bw, req_bw_BYTES, req_bw_GBR);
+#endif	/* GRIO_DEBUG */
+
+    old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS];
+    old_xreg = *xreg;
+    old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));
+
+#ifdef GRIO_DEBUG
+    ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR);
+
+    printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR);
+
+    printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n",
+		req_bw_BYTES, old_bw_BYTES,
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]);
+	   
+#endif				/* GRIO_DEBUG */
+
+    /* Accept the request only if we don't exceed the destination
+     * port HIWATER_MARK *AND* the max. link GBR arbitration count
+     */
+    if (((old_bw_BYTES + req_bw_BYTES) <=
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) &&
+		(req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) {
+
+	new_bw_GBR = (old_bw_GBR + req_bw_GBR);
+
+	/* Set this in the xbow link register */
+	*xreg = (old_xreg & ~mask) | \
+	    (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask);
+
+	soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] =
+			xbow_gbr_to_bytes(new_bw_GBR);
+    } else {
+	error = 1;
+    }
+
+    mutex_spinunlock(&soft->xbow_bw_alloc_lock, s);
+
+    return (error);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/xtalk.c linux-2.4.21-rc3/arch/ia64/sn/io/sn2/xtalk.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/xtalk.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/sn2/xtalk.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,1087 @@
+/* $Id$
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+
+/*
+ * Implement crosstalk provider operations.  The xtalk* layer provides a
+ * platform-independent interface for crosstalk devices.  This layer
+ * switches among the possible implementations of a crosstalk adapter.
+ *
+ * On platforms with only one possible xtalk provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+#define	NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define	DEL(ptr)	(kfree(ptr))
+
+char                    widget_info_fingerprint[] = "widget_info";
+
+cdl_p                   xtalk_registry = NULL;
+
+#define	DEV_FUNC(dev,func)	hub_##func
+#define	CAST_PIOMAP(x)		((hub_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((hub_dmamap_t)(x))
+#define	CAST_INTR(x)		((hub_intr_t)(x))
+
+/* =====================================================================
+ *            Function Table of Contents
+ */
+xtalk_piomap_t          xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned);
+void                    xtalk_piomap_free(xtalk_piomap_t);
+caddr_t                 xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t);
+void                    xtalk_piomap_done(xtalk_piomap_t);
+caddr_t                 xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned);
+caddr_t                 xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned);
+void                    xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *);
+caddr_t                 xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+static caddr_t          null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+xtalk_dmamap_t          xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    xtalk_dmamap_free(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t);
+alenlist_t              xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned);
+void                    xtalk_dmamap_done(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			xtalk_dmamap_drain(xtalk_dmamap_t);
+void			xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t);
+void			xtalk_dmalist_drain(devfs_handle_t, alenlist_t);
+xtalk_intr_t            xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t);
+xtalk_intr_t            xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t);
+void                    xtalk_intr_free(xtalk_intr_t);
+int                     xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *);
+void                    xtalk_intr_disconnect(xtalk_intr_t);
+devfs_handle_t            xtalk_intr_cpu_get(xtalk_intr_t);
+int                     xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);
+int                     xtalk_error_devenable(devfs_handle_t, int, int);
+void                    xtalk_provider_startup(devfs_handle_t);
+void                    xtalk_provider_shutdown(devfs_handle_t);
+devfs_handle_t            xtalk_intr_dev_get(xtalk_intr_t);
+xwidgetnum_t            xtalk_intr_target_get(xtalk_intr_t);
+xtalk_intr_vector_t     xtalk_intr_vector_get(xtalk_intr_t);
+iopaddr_t               xtalk_intr_addr_get(struct xtalk_intr_s *);
+void                   *xtalk_intr_sfarg_get(xtalk_intr_t);
+devfs_handle_t            xtalk_pio_dev_get(xtalk_piomap_t);
+xwidgetnum_t            xtalk_pio_target_get(xtalk_piomap_t);
+iopaddr_t               xtalk_pio_xtalk_addr_get(xtalk_piomap_t);
+ulong                   xtalk_pio_mapsz_get(xtalk_piomap_t);
+caddr_t                 xtalk_pio_kvaddr_get(xtalk_piomap_t);
+devfs_handle_t            xtalk_dma_dev_get(xtalk_dmamap_t);
+xwidgetnum_t            xtalk_dma_target_get(xtalk_dmamap_t);
+xwidget_info_t          xwidget_info_chk(devfs_handle_t);
+xwidget_info_t          xwidget_info_get(devfs_handle_t);
+void                    xwidget_info_set(devfs_handle_t, xwidget_info_t);
+devfs_handle_t            xwidget_info_dev_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_id_get(xwidget_info_t);
+devfs_handle_t            xwidget_info_master_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_masterid_get(xwidget_info_t);
+xwidget_part_num_t      xwidget_info_part_num_get(xwidget_info_t);
+xwidget_mfg_num_t       xwidget_info_mfg_num_get(xwidget_info_t);
+char 			*xwidget_info_name_get(xwidget_info_t);
+void                    xtalk_init(void);
+void                    xtalk_provider_register(devfs_handle_t, xtalk_provider_t *);
+void                    xtalk_provider_unregister(devfs_handle_t);
+xtalk_provider_t       *xtalk_provider_fns_get(devfs_handle_t);
+int                     xwidget_driver_register(xwidget_part_num_t, 
+						xwidget_mfg_num_t, 
+						char *, unsigned);
+void                    xwidget_driver_unregister(char *);
+int                     xwidget_register(xwidget_hwid_t, devfs_handle_t, 
+					 xwidgetnum_t, devfs_handle_t, 
+					 xwidgetnum_t, async_attach_t);
+int			xwidget_unregister(devfs_handle_t);
+void                    xwidget_reset(devfs_handle_t);
+char			*xwidget_name_get(devfs_handle_t);
+#if !defined(DEV_FUNC)
+/*
+ * There is more than one possible provider
+ * for this platform. We need to examine the
+ * master vertex of the current vertex for
+ * a provider function structure, and indirect
+ * through the appropriately named member.
+ */
+#define	DEV_FUNC(dev,func)	xwidget_to_provider_fns(dev)->func
+#define	CAST_PIOMAP(x)		((xtalk_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((xtalk_dmamap_t)(x))
+#define	CAST_INTR(x)		((xtalk_intr_t)(x))
+
+static xtalk_provider_t *
+xwidget_to_provider_fns(devfs_handle_t xconn)
+{
+    xwidget_info_t          widget_info;
+    xtalk_provider_t       *provider_fns;
+
+    widget_info = xwidget_info_get(xconn);
+    ASSERT(widget_info != NULL);
+
+    provider_fns = xwidget_info_pops_get(widget_info);
+    ASSERT(provider_fns != NULL);
+
+    return (provider_fns);
+}
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define	PIOMAP_FUNC(map,func)	DEV_FUNC(map->xp_dev,func)
+#define	DMAMAP_FUNC(map,func)	DEV_FUNC(map->xd_dev,func)
+#define	INTR_FUNC(intr,func)	DEV_FUNC(intr_hdl->xi_dev,func)
+
+/* =====================================================================
+ *                    PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      xtalk space on a specified widget
+ */
+
+xtalk_piomap_t
+xtalk_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   iopaddr_t xtalk_addr,	/* map for this xtalk_addr range */
+		   size_t byte_count,
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{				/* defined in sys/pio.h */
+    return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags);
+}
+
+
+void
+xtalk_piomap_free(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_free)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap,	/* mapping resources */
+		  iopaddr_t xtalk_addr,		/* map for this xtalk address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return PIOMAP_FUNC(xtalk_piomap, piomap_addr)
+	(CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count);
+}
+
+
+void
+xtalk_piomap_done(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_done)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    iopaddr_t xtalk_addr,	/* Crosstalk address */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{				/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, xtalk_addr, byte_count, flags);
+}
+
+caddr_t
+xtalk_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       xtalk_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    xtalk_piomap_t          map = 0;
+    caddr_t                 res;
+
+    if (mapp)
+	*mapp = 0;			/* record "no map used" */
+
+    res = xtalk_piotrans_addr
+	(dev, dev_desc, addr, byte_count, flags);
+    if (res)
+	return res;			/* xtalk_piotrans worked */
+
+    map = xtalk_piomap_alloc
+	(dev, dev_desc, addr, byte_count, byte_count, flags);
+    if (!map)
+	return res;			/* xtalk_piomap_alloc failed */
+
+    res = xtalk_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	xtalk_piomap_free(map);
+	return res;			/* xtalk_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* xtalk_piomap_addr succeeded */
+}
+
+/* =====================================================================
+ *            EARLY PIOTRANS SUPPORT
+ *
+ *      There are places where drivers (mgras, for instance)
+ *      need to get PIO translations before the infrastructure
+ *      is extended to them (setting up textports, for
+ *      instance). These drivers should call
+ *      xtalk_early_piotrans_addr with their xtalk ID
+ *      information, a sequence number (so we can use the second
+ *      mgras for instance), and the usual piotrans parameters.
+ *
+ *      Machine specific code should provide an implementation
+ *      of early_piotrans_addr, and present a pointer to this
+ *      function to xtalk_set_early_piotrans_addr so it can be
+ *      used by clients without the clients having to know what
+ *      platform or what xtalk provider is in use.
+ */
+
+static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr;
+
+xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr;
+
+/* xtalk_set_early_piotrans_addr:
+ * specify the early_piotrans_addr implementation function.
+ */
+void
+xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl)
+{
+    impl_early_piotrans_addr = impl;
+}
+
+/* xtalk_early_piotrans_addr:
+ * figure out a PIO address for the "nth" crosstalk widget that
+ * matches the specified part and mfgr number. Returns NULL if
+ * there is no such widget, or if the requested mapping can not
+ * be constructed.
+ * Limitations on which crosstalk slots (and busses) are
+ * checked, and definitions of the ordering of the search across
+ * the crosstalk slots, are defined by the platform.
+ */
+caddr_t
+xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			  xwidget_mfg_num_t mfg_num,
+			  int which,
+			  iopaddr_t xtalk_addr,
+			  size_t byte_count,
+			  unsigned flags)
+{
+    return impl_early_piotrans_addr
+	(part_num, mfg_num, which, xtalk_addr, byte_count, flags);
+}
+
+/* null_xtalk_early_piotrans_addr:
+ * used as the early_piotrans_addr implementation until and
+ * unless a real implementation is provided. In DEBUG kernels,
+ * we want to know who is calling before the implementation is
+ * registered; in non-DEBUG kernels, return NULL representing
+ * lack of mapping support.
+ */
+/*ARGSUSED */
+static caddr_t
+null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			       xwidget_mfg_num_t mfg_num,
+			       int which,
+			       iopaddr_t xtalk_addr,
+			       size_t byte_count,
+			       unsigned flags)
+{
+#if DEBUG
+    PRINT_PANIC("null_xtalk_early_piotrans_addr");
+#endif
+    return NULL;
+}
+
+/* =====================================================================
+ *                    DMA MANAGEMENT
+ *
+ *      For mapping from crosstalk space to system
+ *      physical space.
+ */
+
+xtalk_dmamap_t
+xtalk_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{				/* defined in dma.h */
+    return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+
+void
+xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_free)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr)
+	(CAST_DMAMAP(xtalk_dmamap), paddr, byte_count);
+}
+
+
+alenlist_t
+xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_list)
+	(CAST_DMAMAP(xtalk_dmamap), alenlist, flags);
+}
+
+
+void
+xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_done)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+
+alenlist_t
+xtalk_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+void
+xtalk_dmamap_drain(xtalk_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *                    INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 devfs_handle_t owner_dev)
+{				/* owner of this interrupt */
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Unconditionally setup resources to be non-threaded.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc_nothd(devfs_handle_t dev,	/* which Crosstalk device */
+		 	device_desc_t dev_desc,	/* device descriptor */
+		 	devfs_handle_t owner_dev)	/* owner of this interrupt */
+{
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+xtalk_intr_free(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Associate resources allocated with a previous xtalk_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+xtalk_intr_connect(xtalk_intr_t intr_hdl,	/* xtalk intr resource handle */
+		   intr_func_t intr_func,       /* xtalk intr handler */
+		   intr_arg_t intr_arg,         /* arg to intr handler */
+		   xtalk_intr_setfunc_t setfunc,	/* func to set intr hw */
+		   void *setfunc_arg)	/* arg to setfunc */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), intr_func, intr_arg, setfunc, setfunc_arg);
+}
+
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+xtalk_intr_disconnect(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+xtalk_intr_cpu_get(xtalk_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * =====================================================================
+ *                      ERROR MANAGEMENT
+ */
+
+/*
+ * xtalk_error_handler:
+ * pass this error on to the handler registered
+ * at the specified xtalk connecdtion point,
+ * or complain about it here if there is no handler.
+ *
+ * This routine plays two roles during error delivery
+ * to most widgets: first, the external agent (heart,
+ * hub, or whatever) calls in with the error and the
+ * connect point representing the crosstalk switch,
+ * or whatever crosstalk device is directly connected
+ * to the agent.
+ *
+ * If there is a switch, it will generally look at the
+ * widget number stashed in the ioerror structure; and,
+ * if the error came from some widget other than the
+ * switch, it will call back into xtalk_error_handler
+ * with the connection point of the offending port.
+ */
+int
+xtalk_error_handler(
+		       devfs_handle_t xconn,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioerror)
+{
+    xwidget_info_t          xwidget_info;
+
+    xwidget_info = xwidget_info_get(xconn);
+    /* Make sure that xwidget_info is a valid pointer before derefencing it.
+     * We could come in here during very early initialization. 
+     */
+    if (xwidget_info && xwidget_info->w_efunc)
+	return xwidget_info->w_efunc
+	    (xwidget_info->w_einfo,
+	     error_code, mode, ioerror);
+    /*
+     * no error handler registered for
+     * the offending port. it's not clear
+     * what needs to be done, but reporting
+     * it would be a good thing, unless it
+     * is a mode that requires nothing.
+     */
+    if ((mode == MODE_DEVPROBE) || (mode == MODE_DEVUSERERROR) ||
+	(mode == MODE_DEVREENABLE))
+	return IOERROR_HANDLED;
+
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_WARNING "Xbow at %v encountered Fatal error", xconn);
+#else
+    printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", xconn);
+#endif
+    ioerror_dump("xtalk", error_code, mode, ioerror);
+
+    return IOERROR_UNHANDLED;
+}
+
+int
+xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+    return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code);
+}
+
+
+/* =====================================================================
+ *                    CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+xtalk_provider_startup(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_startup)
+	(xtalk_provider);
+}
+
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+xtalk_provider_shutdown(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_shutdown)
+	(xtalk_provider);
+}
+
+/* 
+ * Enable a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum);
+}
+
+/* 
+ * Shutdown a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum);
+}
+
+int
+xtalk_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+    return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl);
+}
+/*
+ * Generic crosstalk functions, for use with all crosstalk providers
+ * and all crosstalk devices.
+ */
+
+/****** Generic crosstalk interrupt interfaces ******/
+devfs_handle_t
+xtalk_intr_dev_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_dev);
+}
+
+xwidgetnum_t
+xtalk_intr_target_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_target);
+}
+
+xtalk_intr_vector_t
+xtalk_intr_vector_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_vector);
+}
+
+iopaddr_t
+xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr)
+{
+    return (xtalk_intr->xi_addr);
+}
+
+void                   *
+xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_sfarg);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_dev);
+}
+
+xwidgetnum_t
+xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_target);
+}
+
+iopaddr_t
+xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_xtalk_addr);
+}
+
+ulong
+xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_mapsz);
+}
+
+caddr_t
+xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_kvaddr);
+}
+
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_dev);
+}
+
+xwidgetnum_t
+xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_target);
+}
+
+
+/****** Generic crosstalk widget information interfaces ******/
+
+/* xwidget_info_chk:
+ * check to see if this vertex is a widget;
+ * if so, return its widget_info (if any).
+ * if not, return NULL.
+ */
+xwidget_info_t
+xwidget_info_chk(devfs_handle_t xwidget)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo);
+    return (xwidget_info_t) ainfo;
+}
+
+
+xwidget_info_t
+xwidget_info_get(devfs_handle_t xwidget)
+{
+    xwidget_info_t          widget_info;
+
+    widget_info = (xwidget_info_t)
+	hwgraph_fastinfo_get(xwidget);
+
+#ifdef	LATER
+    if ((widget_info != NULL) &&
+	(widget_info->w_fingerprint != widget_info_fingerprint))
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v bad xwidget_info", xwidget);
+#else
+	PRINT_PANIC("%x bad xwidget_info", xwidget);
+#endif
+#endif	/* LATER */
+
+    return (widget_info);
+}
+
+void
+xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info)
+{
+    if (widget_info != NULL)
+	widget_info->w_fingerprint = widget_info_fingerprint;
+
+    hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info);
+
+    /* Also, mark this vertex as an xwidget,
+     * and use the widget_info, so xwidget_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET,
+			 (arbitrary_info_t) widget_info);
+}
+
+devfs_handle_t
+xwidget_info_dev_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_vertex);
+}
+
+xwidgetnum_t
+xwidget_info_id_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_id);
+}
+
+
+devfs_handle_t
+xwidget_info_master_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_master);
+}
+
+xwidgetnum_t
+xwidget_info_masterid_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_masterid);
+}
+
+xwidget_part_num_t
+xwidget_info_part_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.part_num);
+}
+
+xwidget_mfg_num_t
+xwidget_info_mfg_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.mfg_num);
+}
+/* Extract the widget name from the widget information
+ * for the xtalk widget.
+ */
+char *
+xwidget_info_name_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget info");
+    return(xwidget_info->w_name);
+}
+/****** Generic crosstalk initialization interfaces ******/
+
+/*
+ * One-time initialization needed for systems that support crosstalk.
+ */
+void
+xtalk_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("xtalk_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (xtalk_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr");
+	if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(xtalk_registry != NULL);
+}
+
+/*
+ * Associate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns);
+}
+
+/*
+ * Disassociate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_unregister(devfs_handle_t provider)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL);
+}
+
+/*
+ * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk
+ * provider.
+ */
+xtalk_provider_t       *
+xtalk_provider_fns_get(devfs_handle_t provider)
+{
+    return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider));
+}
+
+/*
+ * Announce a driver for a particular crosstalk part.
+ * Returns 0 on success or -1 on failure.  Failure occurs if the
+ * specified hardware already has a driver.
+ */
+/*ARGSUSED4 */
+int
+xwidget_driver_register(xwidget_part_num_t part_num,
+			xwidget_mfg_num_t mfg_num,
+			char *driver_prefix,
+			unsigned flags)
+{
+    /* a driver's init routine could call
+     * xwidget_driver_register before the
+     * system calls xtalk_init; so, we
+     * make the call here.
+     */
+    if (xtalk_registry == NULL)
+	xtalk_init();
+
+    return cdl_add_driver(xtalk_registry,
+			  part_num, mfg_num,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Inform xtalk infrastructure that a driver is no longer available for
+ * handling any widgets.
+ */
+void
+xwidget_driver_unregister(char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called registger; so we
+     * can assume we have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_del_driver(xtalk_registry, driver_prefix, NULL);
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+xtalk_iterate(char *driver_prefix,
+	      xtalk_iter_f *func)
+{
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func);
+}
+
+/*
+ * xwidget_register:
+ *	Register a xtalk device (xwidget) by doing the following.
+ *      -allocate and initialize xwidget_info data
+ *      -allocate a hwgraph vertex with name based on widget number (id)
+ *      -look up the widget's initialization function and call it,
+ *      or remember the vertex for later initialization.
+ *
+ */
+int
+xwidget_register(xwidget_hwid_t hwid,		/* widget's hardware ID */
+		 devfs_handle_t 	widget,		/* widget to initialize */
+		 xwidgetnum_t 	id,		/* widget's target id (0..f) */
+		 devfs_handle_t 	master,		/* widget's master vertex */
+		 xwidgetnum_t 	targetid,	/* master's target id (9/a) */
+		 async_attach_t aa)
+{			
+    xwidget_info_t          widget_info;
+    char		    *s,devnm[MAXDEVNAME];
+
+    /* Allocate widget_info and associate it with widget vertex */
+    NEW(widget_info);
+
+    /* Initialize widget_info */
+    widget_info->w_vertex = widget;
+    widget_info->w_id = id;
+    widget_info->w_master = master;
+    widget_info->w_masterid = targetid;
+    widget_info->w_hwid = *hwid;	/* structure copy */
+    widget_info->w_efunc = 0;
+    widget_info->w_einfo = 0;
+    /*
+     * get the name of this xwidget vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(widget,devnm,MAXDEVNAME);
+    widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
+    strcpy(widget_info->w_name,s);
+    
+    xwidget_info_set(widget, widget_info);
+
+    device_master_set(widget, master);
+
+    /* All the driver init routines (including
+     * xtalk_init) are called before we get into
+     * attaching devices, so we can assume we
+     * have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    /* 
+     * Add pointer to async attach info -- tear down will be done when
+     * the particular descendant is done with the info.
+     */
+    if (aa)
+	    async_attach_add_info(widget, aa);
+
+    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                          widget, 0);
+}
+
+/*
+ * xwidget_unregister :
+ *	Unregister the xtalk device and detach all its hwgraph namespace.
+ */
+int
+xwidget_unregister(devfs_handle_t widget)
+{
+    xwidget_info_t	widget_info;
+    xwidget_hwid_t	hwid;
+
+    /* Make sure that we have valid widget information initialized */
+    if (!(widget_info = xwidget_info_get(widget)))
+	return(1);
+
+    /* Remove the inventory information associated
+     * with the widget.
+     */
+    hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1);
+    
+    hwid = &(widget_info->w_hwid);
+
+    cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                   widget, 0);
+
+    /* Clean out the xwidget information */
+    (void)kfree(widget_info->w_name);
+    BZERO((void *)widget_info, sizeof(widget_info));
+    DEL(widget_info);
+    
+    return(0);
+}
+
+void
+xwidget_error_register(devfs_handle_t xwidget,
+		       error_handler_f *efunc,
+		       error_handler_arg_t einfo)
+{
+    xwidget_info_t          xwidget_info;
+
+    xwidget_info = xwidget_info_get(xwidget);
+    ASSERT(xwidget_info != NULL);
+    xwidget_info->w_efunc = efunc;
+    xwidget_info->w_einfo = einfo;
+}
+
+/*
+ * Issue a link reset to a widget.
+ */
+void
+xwidget_reset(devfs_handle_t xwidget)
+{
+    xswitch_reset_link(xwidget);
+
+}
+
+
+void
+xwidget_gfx_reset(devfs_handle_t xwidget)
+{
+    xwidget_info_t info;
+
+    xswitch_reset_link(xwidget);
+    info = xwidget_info_get(xwidget);
+#ifdef LATER
+    ASSERT_ALWAYS(info != NULL);
+#endif
+
+    /*
+     * Enable this for other architectures once we add widget_reset to the
+     * xtalk provider interface.
+     */
+    DEV_FUNC(xtalk_provider, widget_reset)
+	(xwidget_info_master_get(info), xwidget_info_id_get(info));
+}
+
+#define ANON_XWIDGET_NAME	"No Name"	/* Default Widget Name */
+
+/* Get the canonical hwgraph  name of xtalk widget */
+char *
+xwidget_name_get(devfs_handle_t xwidget_vhdl)
+{
+	xwidget_info_t  info;
+
+	/* If we have a bogus widget handle then return
+	 * a default anonymous widget name.
+	 */
+	if (xwidget_vhdl == GRAPH_VERTEX_NONE)
+	    return(ANON_XWIDGET_NAME);
+	/* Read the widget name stored in the widget info
+	 * for the widget setup during widget initialization.
+	 */
+	info = xwidget_info_get(xwidget_vhdl);
+	ASSERT(info != NULL);
+	return(xwidget_info_name_get(info));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/stubs.c linux-2.4.21-rc3/arch/ia64/sn/io/stubs.c
--- linux-2.4.20/arch/ia64/sn/io/stubs.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/stubs.c	2003-05-22 22:06:51.000000000 +0000
@@ -28,8 +28,8 @@
 
 int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev;
 int default_intr_pri;
-int force_fire_and_forget;
-int ignore_conveyor_override;
+int force_fire_and_forget = 1;
+int ignore_conveyor_override = 0;
 
 devfs_handle_t dummy_vrtx;	/* Needed for cpuid_to_vertex() in hack.h */
 
@@ -53,36 +53,6 @@
 	return(0);
 }
 
-char *
-nic_bridge_vertex_info(devfs_handle_t v, nic_data_t mcr)
-{
-	FIXME("nic_bridge_vertex_info : returns NULL");
-	return((char *)0);
-}
-
-void *
-snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node)
-{
-        /* Allocates on node 'node' */
-	FIXME("snia_kmem_alloc_node : use kmalloc");
-	return(kmalloc(size, GFP_KERNEL));
-}
-
-void *
-snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node)
-{
-	FIXME("snia_kmem_zalloc_node : use kmalloc");
-	return(kmalloc(size, GFP_KERNEL));
-}
-
-void
-snia_kmem_free(void *where, int size)
-{
-	FIXME("snia_kmem_free : use kfree");
-	return(kfree(where));
-}
-
-
 void *
 snia_kmem_zone_alloc(register zone_t *zone, int flags)
 {
@@ -115,13 +85,6 @@
 		return(0);
 }
 
-void *
-swap_ptr(void **loc, void *new)
-{
-	FIXME("swap_ptr : returns null");
-	return((void *)0);
-}
-
 /* For ml/SN/SN1/slots.c */
 /* ARGSUSED */
 slotid_t get_widget_slotnum(int xbow, int widget)
@@ -153,10 +116,8 @@
 char *
 nic_vertex_info_get(devfs_handle_t v)
 {
-
 	FIXME("nic_vertex_info_get\n");
 	return(NULL);
-
 }
 
 int
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/xswitch.c linux-2.4.21-rc3/arch/ia64/sn/io/xswitch.c
--- linux-2.4.20/arch/ia64/sn/io/xswitch.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/io/xswitch.c	2003-05-22 22:06:28.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/Makefile linux-2.4.21-rc3/arch/ia64/sn/kernel/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/Makefile	2003-05-22 22:06:38.000000000 +0000
@@ -1,4 +1,4 @@
-# arch/ia64/sn/Makefile
+# arch/ia64/sn/kernel/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
 #
@@ -40,9 +40,7 @@
 
 O_TARGET        = sn.o
 
-ifeq ($(CONFIG_MODULES),y)
-export-objs = sn_ksyms.o
-endif
+export-objs = sn_ksyms.o iomv.o
 
 subdir-$(CONFIG_IA64_SGI_SN1)	= sn1
 subdir-$(CONFIG_IA64_SGI_SN2)	= sn2
@@ -51,12 +49,12 @@
 obj-$(CONFIG_IA64_SGI_SN1)      += irq.o mca.o
 obj-$(CONFIG_IA64_SGI_SN2)      += irq.o mca.o
 
-obj-$(CONFIG_IA64_SGI_SN1)      += sn1/sn1.a  
-obj-$(CONFIG_IA64_SGI_SN2)      += sn2/sn2.a  
+obj-$(CONFIG_IA64_SGI_SN1)      += sn1/sn1.o  
+obj-$(CONFIG_IA64_SGI_SN2)      += sn2/sn2.o  
 
 obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o
 obj-$(CONFIG_IA64_GENERIC)      += machvec.o
 obj-$(CONFIG_MODULES)           += sn_ksyms.o
-
+obj-$(CONFIG_IA64_SGI_SN_BRT)	+= bte_regr_test.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/bte.c linux-2.4.21-rc3/arch/ia64/sn/kernel/bte.c
--- linux-2.4.20/arch/ia64/sn/kernel/bte.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/bte.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,16 +1,46 @@
 /*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
+ *
+ *
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
  * 
- * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
+#include <linux/config.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/pda.h>
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/sn2/shubio.h>
+#endif
 #include <asm/nodedata.h>
 
 #include <linux/bootmem.h>
@@ -22,29 +52,20 @@
 int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 };
 
 /*
- * bte_init_node(nodepda, cnode, cmdline_p)
+ * bte_init_node(nodepda, cnode)
  *
  * Initialize the nodepda structure with BTE base addresses and
  * spinlocks.
  *
+ * NOTE: The kernel parameter btetest will cause the initialization
+ * code to reserve blocks of physically contiguous memory to be
+ * used by the bte test module.
  */
 void
-bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode, char **cmdline_p)
+bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
 {
-	int bteTestMode = 0;
-	int cmdoffset = 0;
 	int i;
 
-#ifdef ZZZ
-	if (!cmdoffset) {
-		for (;cmdline_p[cmdoffset]; cmdoffset++) {
-			if (strstr(cmdline_p[cmdoffset], "btetest")) {
-				bteTestMode = 1;
-				break;
-			}
-		}
-	}
-#endif
 
 	/*
 	 * Indicate that all the block transfer engines on this node
@@ -53,32 +74,76 @@
 	for (i = 0; i < BTES_PER_NODE; i++) {
 #ifdef CONFIG_IA64_SGI_SN2
 		/* >>> Don't know why the 0x1800000L is here.  Robin */
-		mynodepda->node_bte_info[i].bte_base_addr =
+		mynodepda->bte_if[i].bte_base_addr =
 		    (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L);
+
 #elif CONFIG_IA64_SGI_SN1
-		mynodepda->node_bte_info[i].bte_base_addr =
+		mynodepda->bte_if[i].bte_base_addr =
 		    (char *)LOCAL_HUB_ADDR(bte_offsets[i]);
 #else
 #error BTE Not defined for this hardware platform.
 #endif
 
+		/*
+		 * Initialize the notification and spinlock
+		 * so the first transfer can occur.
+		 */
+		mynodepda->bte_if[i].most_rcnt_na =
+		    &(mynodepda->bte_if[i].notify);
+		mynodepda->bte_if[i].notify = 0L;
 #ifdef CONFIG_IA64_SGI_BTE_LOCKING
-		/* Initialize the notification and spinlock */
-		/* so the first transfer can occur. */
-		mynodepda->node_bte_info[i].mostRecentNotification =
-		    &(mynodepda->node_bte_info[i].notify);
-		mynodepda->node_bte_info[i].notify = 0L;
-		spin_lock_init(&mynodepda->node_bte_info[i].spinlock);
+		spin_lock_init(&mynodepda->bte_if[i].spinlock);
 #endif				/* CONFIG_IA64_SGI_BTE_LOCKING */
 
-		if (bteTestMode) {
-			mynodepda->node_bte_info[i].bteTestBuf =
-				alloc_bootmem_node(NODE_DATA(cnode),
-						   BTE_MAX_XFER);
-		}
+		mynodepda->bte_if[i].bte_test_buf =
+			alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER);
+	}
+
+}
+
+
+/*
+ * bte_reset_nasid(nasid_t)
+ *
+ * Does a soft reset of the BTEs on the specified nasid.
+ * This is followed by a one-line transfer from each of the
+ * virtual interfaces.
+ */
+void
+bte_reset_nasid(nasid_t n)
+{
+	ii_ibcr_u_t	ibcr;
+
+	ibcr.ii_ibcr_regval  = REMOTE_HUB_L(n, IIO_IBCR);
+	ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
+	REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval);
+
+	/* One line transfer on virtual interface 0 */
+	REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1);
+	REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup)));
+	REMOTE_HUB_S(n, IIO_IBDA_0,
+		     TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBNA_0,
+		     TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY);
+	while (REMOTE_HUB_L(n, IIO_IBLS0)) {
+		/* >>> Need some way out in case of hang... */
+	}
+
+	/* One line transfer on virtual interface 1 */
+	REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1);
+	REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup)));
+	REMOTE_HUB_S(n, IIO_IBDA_1,
+		     TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBNA_1,
+		     TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY);
+	while (REMOTE_HUB_L(n, IIO_IBLS1)) {
+		/* >>> Need some way out in case of hang... */
 	}
 }
 
+
 /*
  * bte_init_cpu()
  *
@@ -91,11 +156,11 @@
 {
 	/* Called by setup.c as each cpu is being added to the nodepda */
 	if (local_node_data->active_cpu_count & 0x1) {
-		pda.cpubte[0] = &(nodepda->node_bte_info[0]);
-		pda.cpubte[1] = &(nodepda->node_bte_info[1]);
+		pda.cpu_bte_if[0] = &(nodepda->bte_if[0]);
+		pda.cpu_bte_if[1] = &(nodepda->bte_if[1]);
 	} else {
-		pda.cpubte[0] = &(nodepda->node_bte_info[1]);
-		pda.cpubte[1] = &(nodepda->node_bte_info[0]);
+		pda.cpu_bte_if[0] = &(nodepda->bte_if[1]);
+		pda.cpu_bte_if[1] = &(nodepda->bte_if[0]);
 	}
 }
 
@@ -112,14 +177,12 @@
  *   len - number of bytes to transfer from source to dest.
  *   mode - hardware defined.  See reference information
  *          for IBCT0/1 in the SGI documentation.
- *   bteBlock - kernel virtual address of a temporary
- *              buffer used during unaligned transfers.
  *
  * NOTE: If the source, dest, and len are all cache line aligned,
  * then it would be _FAR_ preferrable to use bte_copy instead.
  */
 bte_result_t
-bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode, char *bteBlock)
+bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode)
 {
 	int destFirstCacheOffset;
 	u64 headBteSource;
@@ -132,11 +195,19 @@
 	u64 footBcopyDest;
 	u64 footBcopyLen;
 	bte_result_t rv;
+	char *bteBlock;
 
 	if (len == 0) {
 		return (BTE_SUCCESS);
 	}
 
+#ifdef CONFIG_IA64_SGI_BTE_LOCKING
+#error bte_unaligned_copy() assumes single BTE selection in bte_copy().
+#else
+	/* temporary buffer used during unaligned transfers */
+	bteBlock = pda.cpu_bte_if[0]->bte_test_buf;
+#endif
+
 	headBcopySrcOffset = src & L1_CACHE_MASK;
 	destFirstCacheOffset = dest & L1_CACHE_MASK;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/bte_regr_test.c linux-2.4.21-rc3/arch/ia64/sn/kernel/bte_regr_test.c
--- linux-2.4.20/arch/ia64/sn/kernel/bte_regr_test.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/bte_regr_test.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,1062 @@
+/*
+ *
+ *
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+
+/***********************************************************************
+ * Block Transfer Engine regression tests.
+ *
+ *	The following set of tests can be used to test for regressions.
+ *	It is implemented as a loadable module.
+ *
+ *	To enable the tests, the kernel must be booted with the
+ *	"btetest" command line flag.  If the tests are compiled into the
+ *	kernel, additional values may be passed with
+ *	"bte_test=t,v,ht,tn,tx,ti,ta,tc"
+ *	where:
+ *	    t = Bitmask of tests to run.
+ *	    v = Level of verbosity.
+ *	    ht = Number of seconds to try to force a notification hang.
+ *          hu = Number of uSecs to wait until warning of hang.
+ *	    tn = Min number of lines to rate test with (2 raised to).
+ *	    tx = Max number of lines to rate test with (2 raised to).
+ *	    ti = Number of iterations per timing.
+ *          ta = Aternate through cpus on each pass.
+ *	    tc = Use/Don't Use memcopy
+ *
+ *	When loaded as a module, each of those values has a seperate
+ *	parameter.  Just do a modinfo bte_test.o to get those names
+ *	and valid ranges.
+ *
+ *	Tests are performed in the following order.
+ *
+ *	Standard Transfer Test - Just transfers a block of initialized
+ *	data to a cleared block and ensures that memory before and after
+ *	is untouched, but that the body has all the correct values.
+ *
+ *	Transfer Rate Test - Data is transfered from node to node
+ *	to ensure every node is able to BTE data.  Timings are created
+ *	for each node.
+ *
+ *	Notification Hang Test - Attempts to force the Notification
+ *	hang problem to arise.  A hang occurs when the BTE fails
+ *	to invalidate a processors cache line for the notification
+ *	word, resulting in the processor not seeing the updated
+ *	value.
+ *
+ *	Invalid Transfer Test - In this test, we attempt to transfer
+ *	data from a valid address to a nasid which does not exist.
+ *
+ **********************************************************************/
+
+
+#define BTE_TIME 1		/* Needed to ensure bte_copy records
+				 * timings */
+// #define BTE_DEBUG
+// #define BTE_DEBUG_VERBOSE
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/nodepda.h>
+#include <asm/processor.h>
+
+#include <asm/sn/bte_copy.h>
+
+
+/***********************************************************************
+ * Local defines, structs, and typedefs.
+ *
+ **********************************************************************/
+
+
+/*
+ * The following struct defines standard transfers to use while
+ * testing.
+ */
+typedef struct brt_xfer_entry_s {
+	int source_offset;
+	int dest_offset;
+	int length;
+} brt_xfer_entry_t;
+
+/*
+ * BRT_TEST_BLOCK_SIZE needs to accomodate the largest transfer that
+ * is found in brt_xfer_tests.
+ */
+#define BRT_TEST_BLOCK_SIZE 1024
+
+/* Flags for selecting tests to run. */
+#define TEST_REGRESSION		0x00000001	/* Standard Transfer */
+#define TEST_TIME		0x00000002	/* Timed Transfer */
+#define TEST_NOTIFY		0x00000004	/* Notification Hang */
+#define TEST_NONODE		0x00000008	/* Invalid Nasid Xfer */
+
+
+/***********************************************************************
+ * Global variables.
+ * 
+ **********************************************************************/
+
+
+/*
+ * bte_setup_time - Time it takes for bte_copy to get locks
+ * 		    acquired and values into SHUB registers to start the
+ * 		    xfer.
+ *
+ * bte_transfer_time - Time where hardware is doing the xfer.
+ *
+ * bte_tear_down_time - Time to unlock and return.
+ *
+ * bte_execute_time - Time from first call until return.
+ */
+volatile static u64 bte_setup_time;
+volatile static u64 bte_transfer_time;
+volatile static u64 bte_tear_down_time;
+volatile static u64 bte_execute_time;
+
+/* Tests to run during standard transfer tests. */
+static brt_xfer_entry_t brt_xfer_tests[] = {
+	{0, 0, 2 * L1_CACHE_BYTES},	/* The ideal case. */
+
+	{0, 0, 35},		/* Symetrical aligned test. */
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, 35},
+	{0, 0, L1_CACHE_BYTES + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, L1_CACHE_BYTES + 35},
+	{0, 0, (2 * L1_CACHE_BYTES) + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, (2 * L1_CACHE_BYTES) + 35},
+	{0, 0, (4 * L1_CACHE_BYTES) + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, (4 * L1_CACHE_BYTES) + 35},
+
+	{(0 + 25), (0 + 25), 35},	/* Symetrical unaligned test. */
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), 35},
+	{(0 + 25), (0 + 25), L1_CACHE_BYTES + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (L1_CACHE_BYTES + 25) + 35},
+	{(0 + 25), (0 + 25), (2 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (2 * L1_CACHE_BYTES) + 35},
+	{(0 + 25), (0 + 25), (4 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (4 * L1_CACHE_BYTES) + 35},
+
+	{(0 + 25), (0 + 26), 35},	/* Asymetrical unaligned test. */
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), 35},
+	{(0 + 25), (0 + 26), L1_CACHE_BYTES + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (L1_CACHE_BYTES + 25) + 35},
+	{(0 + 25), (0 + 26), (2 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (2 * L1_CACHE_BYTES) + 35},
+	{(0 + 25), (0 + 26), (4 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (4 * L1_CACHE_BYTES) + 35},
+
+	{0, 0, 0}		/* Terminator */
+};
+
+static atomic_t brt_thread_cnt;	/* Threads in test. */
+volatile static int brt_exit_flag;	/* Flag termination of hang test */
+
+/* command line/module parameters */
+static int selected_tests = 0;
+static int verbose = 0;
+static int hang_timeout = 10;
+static int hang_usec = 12;
+static int tm_min_lines = 1;
+static int tm_max_lines = 3;
+static int tm_iterations = 1;
+static int tm_alternate = 0;
+static int tm_memcpy = 1;
+static int ix_iterations = 1000;
+static int ix_srcnasid = -1;
+
+
+/***********************************************************************
+ * Local Function Prototypes.
+ * 
+ **********************************************************************/
+
+
+static int __init brt_test_init(void);
+static void __exit brt_test_exit(void);
+
+/* Standard Transfer Test related functions. */
+static int brt_tst_std_xfer(void);
+static int brt_std_xfer(char *, char *, int, int, int, int);
+static void brt_hex_dump(char *, int);
+
+/* Timed Transfer Test related functions. */
+static int brt_tst_time_xfers(void);
+static void brt_time_xfer(int, int, int);
+
+/* Notification Hang Test related functions. */
+static int brt_tst_notify_hang(void);
+static int brt_notify_thrd(void *);
+
+/* Transfers to Invalid Nasid Test related functions. */
+static int brt_tst_invalid_xfers(void);
+
+#if !defined(MODULE)
+/* Kernel command line handler. */
+static int __init brt_setup(char *);
+#endif				/* !defined(MODULE) */
+
+
+/***********************************************************************
+ * Module Load/Unload.
+ * 
+ **********************************************************************/
+
+
+#define brt_marker() \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n"); \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n"); \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n");
+
+
+static int __init
+brt_test_init(void)
+{
+	int some_tests_removed;
+
+	if (numnodes < 2) {
+		printk("These tests are best run on multinode "
+		       "systems.\n");
+	}
+
+	if (!pda.cpu_bte_if[0]->bte_test_buf) {
+		some_tests_removed = 0;
+
+		/* Timed Transfers go node-to-node. */
+		if (selected_tests & TEST_TIME) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_TIME);
+		}
+
+		/* Notification Hang runs on all cpus simultaneously */
+		if (selected_tests & TEST_NOTIFY) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_NOTIFY);
+		}
+
+		/* Invalid Tests */
+		if (selected_tests & TEST_NONODE) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_NONODE);
+		}
+
+		if (some_tests_removed) {
+			printk("Test Buffers were not allocated.\n");
+			printk("Please reboot the system and supply "
+			       "the \"btetest\" kernel flag\n");
+			printk("Some tests were removed.\n");
+		}
+	}
+
+	brt_marker();
+
+	printk("brt_test(): Starting.\n");
+
+	if (selected_tests & TEST_REGRESSION) {
+		if (brt_tst_std_xfer()) {
+			printk("Standard Transfers had errors.\n");
+		}
+
+	}
+
+	if (selected_tests & TEST_TIME) {
+		if (tm_min_lines < 0) {
+			tm_min_lines = 0;
+		}
+		if (tm_max_lines < 0) {
+			tm_max_lines = 0;
+		}
+
+		if (tm_max_lines > BTE_LEN_MASK) {
+			tm_max_lines = BTE_LEN_MASK;
+		}
+		if (tm_min_lines > tm_max_lines) {
+			tm_min_lines = tm_max_lines;
+		}
+
+		if (brt_tst_time_xfers()) {
+			printk("Timed transfers had errors.\n");
+		}
+
+	}
+
+	if (selected_tests & TEST_NOTIFY) {
+		if (hang_usec < 8) {
+			hang_usec = 8;
+		}
+		if (hang_usec > 256) {
+			hang_usec = 256;
+		}
+
+		if (brt_tst_notify_hang()) {
+			printk("Notification Hang test had errors.\n");
+		}
+	}
+
+	if (selected_tests & TEST_NONODE) {
+		if (brt_tst_invalid_xfers()) {
+			printk("Invalid Nasid test had errors.\n");
+		}
+	}
+
+	return (1);		/* Prevent module load. */
+}
+
+
+static void __exit
+brt_test_exit(void)
+{
+}
+
+
+/***********************************************************************
+ * Standard Transfer Test.
+ *	
+ *	This test has a table of transfers defined above.  For each
+ *	transfer, it calls bte_unaligned_copy.  It compares the actual
+ *	result with the expected result.  If they differ, it prints out
+ *	information about the transfer and hex dumps the actual block
+ *
+ **********************************************************************/
+
+
+/*
+ * Allocate the needed buffers and then initiate each xfer specified
+ * by brt_xfer_tests.
+ */
+static int
+brt_tst_std_xfer(void)
+{
+	char *block_1;
+	char *block_2;
+	int iteration = 0;
+	brt_xfer_entry_t *cur_test;
+	int cpu;
+	int err_cnt;
+
+	block_1 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL);
+	ASSERT(!((u64) block_1 & L1_CACHE_MASK));
+	block_2 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL);
+	ASSERT(!((u64) block_2 & L1_CACHE_MASK));
+
+	cur_test = brt_xfer_tests;
+
+	err_cnt = 0;
+	while (cur_test->length) {
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			set_cpus_allowed(current, (1UL << cpu));
+
+			if (verbose > 1) {
+				printk("Cpu %d Transfering %d from "
+				       "%d to %d.\n",
+				       smp_processor_id(),
+				       cur_test->length,
+				       cur_test->source_offset,
+				       cur_test->dest_offset);
+			}
+
+			err_cnt += brt_std_xfer(block_1, block_2,
+						cur_test->source_offset,
+						cur_test->dest_offset,
+						cur_test->length,
+						++iteration);
+
+		}
+		cur_test++;
+	}
+
+	kfree(block_2);
+	kfree(block_1);
+
+	return ((err_cnt ? 1 : 0));
+}
+
+
+/*
+ * Perform a single transfer and ensure the result matches
+ * the expected.  Returns the number of differences found.
+ *
+ * Testing is performed by setting the source buffer to a
+ * known value, and zeroing out the destination.
+ *
+ * After the copy, if the destination has only the known
+ * source values at the correct place, we know we had a
+ * good transfer.
+ *
+ */
+static int
+brt_std_xfer(char *src, char *dst,
+	     int src_offset, int dst_offset, int len,
+	     int magic)
+{
+	int i, ret;
+	int err_cnt = 0;
+
+	if (verbose > 3) {
+		printk("brt_test(src=0x%lx, dst=0x%lx, src_offset=%d, "
+		       "dst_offset=%d, len=%d, magic=%d\n",
+		       (u64) src, (u64) dst, src_offset,
+		       dst_offset, len, magic);
+	}
+
+	memset(src, ((magic + 1) & 0xff), BRT_TEST_BLOCK_SIZE);
+	memset((src + src_offset), magic, len);
+	if (verbose > 8) {
+		printk("Before transfer: Source is\n");
+		brt_hex_dump(src, BRT_TEST_BLOCK_SIZE);
+	}
+	memset(dst, 0, BRT_TEST_BLOCK_SIZE);
+	if (verbose > 8) {
+		printk("Before transfer: dest is\n");
+		brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE);
+	}
+
+	ret = BTE_UNALIGNED_COPY(__pa(src + src_offset),
+				 __pa(dst + dst_offset),
+				 len, BTE_NOTIFY);
+	if (ret != BTE_SUCCESS) {
+		printk("brt_test: BTE_UNALIGNED_COPY() error: %d\n", ret);
+		return (1);
+	}
+
+	/* Check head */
+	for (i = 0; i < dst_offset; i++) {
+		if ((dst[i] & 0xff) != 0) {
+			err_cnt++;
+		}
+	}
+	/* Check body */
+	for (i = 0; i < len; i++) {
+		if ((dst[dst_offset + i] & 0xff) != (magic & 0xff)) {
+			err_cnt++;
+		}
+	}
+	/* Check foot */
+	for (i = (dst_offset + len); i < BRT_TEST_BLOCK_SIZE; i++) {
+		if ((dst[i] & 0xff) != 0) {
+			err_cnt++;
+		}
+	}
+
+	if ((verbose > 3) || err_cnt) {
+		printk("brt_test: %d errors during basic "
+		       "transfer test.\n", err_cnt);
+		brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE);
+	}
+
+	return (err_cnt);
+}
+
+
+/*
+ * Dump a block of data to console as hex.
+ */
+static void
+brt_hex_dump(char *block_to_dump, int block_len)
+{
+	int i;
+	char fmt_line[128];
+	char *fmt_eol = fmt_line;
+
+	for (i = 0; i < block_len; i++) {
+		if (!(i % 16)) {
+			if (i > 0) {
+				printk("%s\n", fmt_line);
+			}
+			sprintf(fmt_line, "0x%lx %05d ",
+				__pa(&block_to_dump[i]), i);
+			fmt_eol = fmt_line;
+		}
+		while (*fmt_eol++) {	/* empty */
+		};
+		fmt_eol--;
+		sprintf(fmt_eol, "%s%02x",
+			(!(i % 4) ? " " : ""), (block_to_dump[i] & 0xff));
+	}
+	printk("%s\n", fmt_line);
+}
+
+
+/***********************************************************************
+ * Transfer Rate Test.
+ * 
+ *	This test migrates to each cpu one at a time.  This is done to
+ *	get a complete view of how each of the bte engines is performing
+ *	and help ensure that each virtual interface is being used.
+ *	NOTE: All virtual interfaces will not necessarily be used.
+ *
+ *	Now that we have migrated to the desired cpu, we transfer from
+ *	our node to all the other nodes (including ourself).  We
+ *	accomplish this with both a memcpy and a bte_copy.  Timings
+ *	for both are printed.
+ *
+ **********************************************************************/
+
+
+#define NSEC(x) ((x) * (1000000000UL / local_cpu_data->itc_freq))
+
+
+/*
+ * Migrate to each cpu. When on the desired cpu, time transfers to
+ * each node by calling brt_time_xfer.
+ */
+static int
+brt_tst_time_xfers(void)
+{
+	int tst_cpu;
+	int dest_node;
+	int xfer_lines;
+	int i;
+
+	if (tm_memcpy) {
+		printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute,"
+		       "Overall,Memcpy\n");
+	} else {
+		printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute,"
+		       "Overall\n");
+	}
+
+	if (tm_alternate) {
+		/* Now transfer from this node to all the others. */
+		for (dest_node = 0; dest_node < numnodes; dest_node++) {
+			for (xfer_lines = tm_min_lines;
+			     xfer_lines <= tm_max_lines;) {
+
+				for (i = 0; i < tm_iterations; i++) {
+					for (tst_cpu = 0;
+					     tst_cpu < smp_num_cpus;
+					     tst_cpu++) {
+						/* Move to the desired CPU. */
+						set_cpus_allowed(current,
+						    (1UL << tst_cpu));
+
+						brt_time_xfer(dest_node,
+							      1,
+							      xfer_lines);
+
+					}
+				}
+				/* Handle a min of 0 */
+				if (xfer_lines < 1) {
+					xfer_lines = 1;
+				} else {
+					xfer_lines *= 2;
+				}
+			}
+		}
+	} else {
+		for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) {
+			/* Move to the desired CPU. */
+			set_cpus_allowed(current, (1UL << tst_cpu));
+
+			/* Now transfer from this node to all the others. */
+			for (dest_node = 0; dest_node < numnodes;
+			     dest_node++) {
+				for (xfer_lines = tm_min_lines;
+				     xfer_lines <= tm_max_lines;) {
+
+					brt_time_xfer(dest_node,
+						      tm_iterations,
+						      xfer_lines);
+
+					/* Handle a min of 0 */
+					if (xfer_lines < 1) {
+						xfer_lines = 1;
+					} else {
+						xfer_lines *= 2;
+					}
+				}
+			}
+		}
+	}
+	return (0);
+}
+
+
+/*
+ * Transfer the bte_test_buffer from our node to the specified
+ * destination and print out timing results.
+ */
+static void
+brt_time_xfer(int dest_node, int iterations, int xfer_lines)
+{
+	int iteration;
+	char *src, *dst;
+	u64 xfer_len, src_phys, dst_phys;
+	u64 itc_before, itc_after, mem_intvl, bte_intvl;
+
+
+	xfer_len = xfer_lines * L1_CACHE_BYTES;
+
+	src = nodepda->bte_if[0].bte_test_buf;
+	src_phys = __pa(src);
+	dst = NODEPDA(dest_node)->bte_if[1].bte_test_buf;
+	dst_phys = __pa(dst);
+	mem_intvl = 0;
+
+	for (iteration = 0; iteration < iterations; iteration++) {
+		if (tm_memcpy) {
+			itc_before = ia64_get_itc();
+			memcpy(dst, src, xfer_len);
+			itc_after = ia64_get_itc();
+			mem_intvl = itc_after - itc_before;
+		}
+
+		itc_before = ia64_get_itc();
+		bte_copy(src_phys, dst_phys, xfer_len, BTE_NOTIFY, NULL);
+		itc_after = ia64_get_itc();
+		bte_intvl = itc_after - itc_before;
+
+		if (tm_memcpy) {
+			printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld,"
+			       "%7ld,%7ld,%7ld\n",
+			       smp_processor_id(), NASID_GET(src),
+			       NASID_GET(dst), xfer_lines,
+			       NSEC(bte_setup_time),
+			       NSEC(bte_transfer_time),
+			       NSEC(bte_tear_down_time),
+			       NSEC(bte_execute_time), NSEC(bte_intvl),
+			       NSEC(mem_intvl));
+		} else {
+			printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld,"
+			       "%7ld,%7ld\n",
+			       smp_processor_id(), NASID_GET(src),
+			       NASID_GET(dst), xfer_lines,
+			       NSEC(bte_setup_time),
+			       NSEC(bte_transfer_time),
+			       NSEC(bte_tear_down_time),
+			       NSEC(bte_execute_time), NSEC(bte_intvl));
+		}
+	}
+
+}
+
+
+/***********************************************************************
+ * Notification Hang Test. -- NOTE: Has never actually caused a hang.
+ *
+ *	The next set of code checks to see if the Notification Hang
+ *	occurs.  It does this by starting one thread per cpu, pinning
+ *	the thread to its assigned cpu.  After it is pinned, we lock
+ *	the associated bte.  Source, Dest, and Notification are
+ *	assigned.
+ *
+ *	Inside of a loop, we set the length and trigger the
+ *	transfer. We use the ITC to determine when the transfer should
+ *	complete. Whenever the IBLS_BUSY bit is cleared, the transfer
+ *	has completed. We occasionally call schedule (Since all CPUs
+ *	have a pinned process The machine will be doing nothing but
+ *	out tranfers) and loop.
+ *
+ *	If twice max normal time has passed without seeing the
+ *	notification, we check the Length/Status register to see if
+ *	IBLS_BUSY is still asserted and length is zero.  This is an
+ *	indication of the hang.
+ *
+ **********************************************************************/
+
+
+/*
+ * Launch one thread per cpu.  When all threads are started, sleep
+ * the specified timeout and then notify the other threads that it
+ * is time to exit.
+ */
+static int
+brt_tst_notify_hang(void)
+{
+	int tst_cpu;
+
+	printk("Waiting %d seconds to complete test.\n", hang_timeout);
+
+	atomic_set(&brt_thread_cnt, 0);
+	brt_exit_flag = 0;
+
+	for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) {
+		if ((kernel_thread(brt_notify_thrd,
+				   (void *)(long)tst_cpu, 0)) < 0) {
+			printk("Failed to start thread.\n");
+		}
+	}
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(hang_timeout * HZ);
+	set_current_state(TASK_RUNNING);
+
+	printk("Flagging an exit.\n");
+	brt_exit_flag = 1;
+
+	while (atomic_read(&brt_thread_cnt)) {
+		/* Wait until everyone else is done. */
+		schedule();
+	}
+
+	printk("All threads have exited.\n");
+	return (0);
+}
+
+
+/*
+ * One of these threads is started per cpu.  Each thread is responsible
+ * for loading that cpu's bte interface and then writing to the
+ * test buffer.  The transfers are set in a round-robin fashion.
+ * The end result is that each test buffer is being written into
+ * by the previous node and both cpu's at the same time as the
+ * local bte is transferring it to the next node.
+ */
+static int
+brt_notify_thrd(void *__bind_cpu)
+{
+	int bind_cpu = (long int)__bind_cpu;
+	int cpu = cpu_logical_map(bind_cpu);
+	nodepda_t *nxt_node;
+	long tmout_itc_intvls;
+	long tmout;
+	long passes;
+	long good_xfer_cnt;
+	u64 src_phys, dst_phys;
+	int i;
+	volatile char *src_buf;
+	u64 *notify;
+
+	atomic_inc(&brt_thread_cnt);
+	daemonize();
+	set_user_nice(current, 19);
+	sigfillset(&current->blocked);
+
+	/* Migrate to the right CPU */
+	set_cpus_allowed(current, 1UL << cpu);
+
+	/* Calculate the uSec timeout itc offset. */
+	tmout_itc_intvls = local_cpu_data->cyc_per_usec * hang_usec;
+
+	if (local_cnodeid() == (numnodes - 1)) {
+		nxt_node = NODEPDA(0);
+	} else {
+		nxt_node = NODEPDA(local_cnodeid() + 1);
+	}
+
+	src_buf = nodepda->bte_if[0].bte_test_buf;
+	src_phys = __pa(src_buf);
+	dst_phys = __pa(nxt_node->bte_if[0].bte_test_buf);
+
+	notify = kmalloc(L1_CACHE_BYTES, GFP_KERNEL);
+	ASSERT(!((u64) notify & L1_CACHE_MASK));
+
+	printk("BTE Hang %d xfer 0x%lx -> 0x%lx, Notify=0x%lx\n",
+	       smp_processor_id(), src_phys, dst_phys, (u64) notify);
+
+	passes = 0;
+	good_xfer_cnt = 0;
+
+	/* Loop until signalled to exit. */
+	while (!brt_exit_flag) {
+		/*
+		 * A hang will prevent further transfers.
+		 * NOTE: Sometimes, it appears like a hang occurred and
+		 * then transfers begin again.  This just means that
+		 * there is NUMA congestion and the hang_usec param
+		 * should be increased.
+		 */
+		if (!(*notify & IBLS_BUSY)) {
+			if ((bte_copy(src_phys,
+				      dst_phys,
+				      4UL * L1_CACHE_BYTES,
+				      BTE_NOTIFY,
+				      (void *)notify)) != BTE_SUCCESS) {
+				printk("<0>Cpu %d Could not "
+				       "allocate a bte.\n",
+				       smp_processor_id());
+				continue;
+			}
+
+			tmout = ia64_get_itc() + tmout_itc_intvls;
+
+			while ((*notify & IBLS_BUSY) &&
+			       (ia64_get_itc() < tmout)) {
+
+
+				/* Push data out with the processor. */
+				for (i = 0; i < (4 * L1_CACHE_BYTES);
+				     i += L1_CACHE_BYTES) {
+					src_buf[i] = (passes % 128);
+				}
+			};
+
+			if (*notify & IBLS_BUSY) {
+				printk("<0>Cpu %d BTE appears to have "
+				       "hung.\n", smp_processor_id());
+			} else {
+				good_xfer_cnt++;
+			}
+		}
+
+		/* Every x passes, take a little break. */
+		if (!(++passes % 40)) {
+			passes = 0;
+			schedule_timeout(0.01 * HZ);
+		}
+	}
+
+	kfree(notify);
+
+	printk("Cpu %d had %ld good passes\n",
+	       smp_processor_id(), good_xfer_cnt);
+
+	atomic_dec(&brt_thread_cnt);
+	return (0);
+}
+
+
+/***********************************************************************
+ * Invalid Transfer Test.
+ * 
+ *	Just transfer from the local node to a nasid which does not
+ *	exist.
+ *
+ *	>>> Potential Problem: on SN1, HUB interrupt doesn't always
+ *	occurr.
+ *
+ **********************************************************************/
+
+
+/*
+ * Locate a nasid which doesn't exist.  Perform a bte_copy from that
+ * node to our local node.
+ */
+static int
+brt_tst_invalid_xfers(void)
+{
+	int i;
+	int free_nasid = -1;
+	int cpu;
+	int error_cnt;
+
+	u64 ret_code;
+
+	if (ix_srcnasid != -1) {
+		free_nasid = ix_srcnasid;
+	} else {
+		/* Only looking for nasids from C-Nodes. */
+		for (i = 0; i < PLAT_MAX_NODE_NUMBER; i += 2) {
+			if (local_node_data->physical_node_map[i] == -1) {
+				free_nasid = i;
+				break;
+			}
+		}
+	}
+
+	if (free_nasid == -1) {
+		printk("tst_invalid_xfers: No free nodes found. "
+		       "Exiting.\n");
+		return (0);
+	}
+
+	printk("tst_invalid_xfers: Using source nasid of %d\n",
+	       free_nasid);
+
+	error_cnt = 0;
+
+	for (i = 0; i < ix_iterations; i++) {
+		if (verbose >= 1) {
+			printk("-------------------------------"
+			       "-------------------------------"
+			       "--------------\n");
+		}
+		if ((verbose >= 1) || !(i % 10)) {
+			printk("  Loop %d\n", i);
+		}
+
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			set_cpus_allowed(current, (1UL << cpu));
+
+			if (verbose > 1) {
+				printk("Testing with CPU %d\n",
+				       smp_processor_id());
+			}
+
+			/* >>> Need a better means of calculating a
+			 * remote addr. */
+			ret_code = bte_copy(TO_NODE(free_nasid, 0),
+					    __pa(nodepda->bte_if[0].
+						 bte_test_buf),
+					    4 * L1_CACHE_BYTES,
+					    BTE_NOTIFY,
+					    NULL);
+			error_cnt += (ret_code ? 1 : 0);
+		}
+	}
+
+	ret_code = ((error_cnt != (ix_iterations * smp_num_cpus)) ?
+		    1 : 0);
+	return (ret_code);
+}
+
+
+/***********************************************************************
+ * Kernel command line handler.
+ * 
+ **********************************************************************/
+
+
+#if !defined(MODULE)
+static int __init
+brt_setup(char *str)
+{
+	int cur_val;
+
+	if (get_option(&str, &cur_val)) {
+		selected_tests = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		verbose = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		hang_timeout = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		hang_usec = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_min_lines = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_max_lines = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_iterations = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_alternate = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_memcpy = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		ix_iterations = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		ix_srcnasid = cur_val;
+	}
+
+	return (1);
+}
+#endif				/* !defined(MODULE) */
+
+
+/***********************************************************************
+ * Module parameters.
+ *	
+ *	The two supported cases are loadable module parms and kernel
+ *	command line support.
+ *	
+ *	The loadable module options are specified below in the
+ *	MODULE_PARM macros and have associated descriptions.
+ *	
+ *	The kernel command line option is btetest=x[,y[,z]] etc.  The
+ *	individual setting order is constant.  NOTE: The btetest flag
+ *	is checked for in the bte_init_node function.
+ *	
+ **********************************************************************/
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Test the Block Transfer Engine(BTE) "
+		   "present on SGI machines.");
+
+MODULE_PARM(selected_tests, "1i");
+MODULE_PARM_DESC(selected_tests, "Bitmask of tests to run.");
+
+MODULE_PARM(verbose, "1i");
+MODULE_PARM_DESC(verbose,
+		 "How much information should be "
+		 "printed during the tests.");
+
+MODULE_PARM(hang_timeout, "1i");
+MODULE_PARM_DESC(hang_timeout,
+		 "Number of seconds to wait for the Bte "
+		 "Notification Failure.");
+
+MODULE_PARM(hang_usec, "1i");
+MODULE_PARM_DESC(hang_usec,
+		 "Number of micro-seconds to wait for the 4-line Bte "
+		 "transfer to complete.");
+
+MODULE_PARM(tm_min_lines, "1i");
+MODULE_PARM_DESC(tm_min_lines, "Minimum number of cache lines"
+		 " to time with.");
+
+MODULE_PARM(tm_max_lines, "1i");
+MODULE_PARM_DESC(tm_max_lines, "Maximum number of cache lines"
+		 " to time with.");
+
+MODULE_PARM(tm_iterations, "1i");
+MODULE_PARM_DESC(tm_iterations, "Rerun each timed transfer this "
+		 "many times.");
+
+MODULE_PARM(tm_alternate, "1i");
+MODULE_PARM_DESC(tm_alternate, "Cycle across cpus between each "
+		 "iteration");
+
+MODULE_PARM(tm_memcpy, "1i");
+MODULE_PARM_DESC(tm_memcpy, "Use memcpy as a comparison to BTE");
+
+MODULE_PARM(ix_iterations, "1i");
+MODULE_PARM_DESC(ix_iterations, "Rerun each transfer from an "
+		 "invalid nasid this many times.");
+
+MODULE_PARM(ix_srcnasid, "1i");
+MODULE_PARM_DESC(ix_srcnasid, "Nasid to attempt xfer from.");
+
+
+#if !defined(MODULE)
+__setup("btetest=", brt_setup);
+#endif				/* !defined(MODULE) */
+
+
+module_init(brt_test_init);
+module_exit(brt_test_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/iomv.c linux-2.4.21-rc3/arch/ia64/sn/kernel/iomv.c
--- linux-2.4.20/arch/ia64/sn/kernel/iomv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/iomv.c	2003-05-22 22:06:42.000000000 +0000
@@ -7,15 +7,7 @@
  */
 
 #include <asm/io.h>
-
-#if 1	/* ##jh */
-#ifdef CONFIG_IA64_SGI_SN1
-#define mmiob sn1_mmiob
-#else
-#define mmiob sn2_mmiob
-#endif
-extern void mmiob(void);
-#endif /* ##jh */
+#include <linux/module.h>
 
 extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */
 
@@ -83,7 +75,6 @@
 	volatile unsigned char *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
 
 /**
@@ -99,7 +90,6 @@
 	volatile unsigned short *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
 
 /**
@@ -115,5 +105,11 @@
 	volatile unsigned int *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
+
+EXPORT_SYMBOL(sn_inb);
+EXPORT_SYMBOL(sn_inw);
+EXPORT_SYMBOL(sn_inl);
+EXPORT_SYMBOL(sn_outb);
+EXPORT_SYMBOL(sn_outw);
+EXPORT_SYMBOL(sn_outl);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/irq.c linux-2.4.21-rc3/arch/ia64/sn/kernel/irq.c
--- linux-2.4.20/arch/ia64/sn/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/irq.c	2003-05-22 22:06:26.000000000 +0000
@@ -226,12 +226,6 @@
 	return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
 }
 
-int
-sn_valid_irq(u8 irq) {
-
-	return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) );
-}
-
 void *kmalloc(size_t, int);
 
 void
@@ -240,7 +234,7 @@
 	int i;
 	irq_desc_t *base_desc = _irq_desc;
 
-	for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) {
+	for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IVECS; i++) {
 		if (base_desc[i].handler == &no_irq_type) {
 			base_desc[i].handler = &irq_type_sn;
 		}
@@ -254,21 +248,14 @@
 
 	for (i=0; i < NR_CPUS; i++) {
 		p =  page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL,
-			get_order(sizeof(struct irq_desc) * NR_IRQS) ) );
+			get_order(sizeof(struct irq_desc) * NR_IVECS) ) );
 		ASSERT(p);
-		memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IRQS);
+		memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IVECS);
 		_sn_irq_desc[i] = p;
 	}
 }
 
 
-#if !defined(CONFIG_IA64_SGI_SN)
-void
-sn_pci_fixup(void)
-{
-}
-#endif
-
 int
 bit_pos_to_irq(int bit) {
 #define BIT_TO_IRQ 64
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/mca.c linux-2.4.21-rc3/arch/ia64/sn/kernel/mca.c
--- linux-2.4.20/arch/ia64/sn/kernel/mca.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/mca.c	2003-05-22 22:06:39.000000000 +0000
@@ -34,199 +34,80 @@
  */
 
 #include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/smp_lock.h>
-#include <linux/kdb.h>
-
-#include <asm/machvec.h>
-#include <asm/page.h>
-#include <asm/ptrace.h>
-#include <asm/system.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <asm/mca.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
-#include <asm/mca.h>
-#include <asm/sn/mca.h>
 
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/acpi-ext.h>
-#include <asm/smp.h>
-#include <asm/sn/sn_cpuid.h>
-
-static char *shub_mmr_names[] = {
-	"sh_event_occurred",
-	"sh_first_error",
-	"sh_event_overflow",
-
-/* PI */
-	"sh_pi_first_error",
-	"sh_pi_error_summary",
-	"sh_pi_error_overflow",
-
-/* PI HW */
-	"sh_pi_error_detail_1",
-	"sh_pi_error_detail_2",
-	"sh_pi_hw_time_stamp",
-
-/* PI UCE */
-	"sh_pi_uncorrected_detail_1",
-	"sh_pi_uncorrected_detail_2",
-	"sh_pi_uncorrected_detail_3",
-	"sh_pi_uncorrected_detail_4",
-	"sh_pi_uncor_time_stamp",
-
-/* PI CE */
-	"sh_pi_corrected_detail_1",
-	"sh_pi_corrected_detail_2",
-	"sh_pi_corrected_detail_3",
-	"sh_pi_corrected_detail_4",
-	"sh_pi_cor_time_stamp",
-
-/* MD */
-	"sh_mem_error_summary",
-	"sh_mem_error_overflow",
-/* MD HW */
-	"sh_misc_err_hdr_upper",
-	"sh_misc_err_hdr_lower",
-	"sh_md_dqlp_mmr_xperr_val",
-	"sh_md_dqlp_mmr_yperr_val",
-	"sh_md_dqrp_mmr_xperr_val",
-	"sh_md_dqrp_mmr_yperr_val",
-	"sh_md_hw_time_stamp",
-
-/* MD UCE */
-	"sh_dir_uc_err_hdr_lower",
-	"sh_dir_uc_err_hdr_upper",
-	"sh_md_dqlp_mmr_xuerr1",
-	"sh_md_dqlp_mmr_xuerr2",
-	"sh_md_dqlp_mmr_yuerr1",
-	"sh_md_dqlp_mmr_yuerr2",
-	"sh_md_dqrp_mmr_xuerr1",
-	"sh_md_dqrp_mmr_xuerr2",
-	"sh_md_dqrp_mmr_yuerr1",
-	"sh_md_dqrp_mmr_yuerr2",
-	"sh_md_uncor_time_stamp",
-
-/* MD CE */
-	"sh_dir_cor_err_hdr_lower",
-	"sh_dir_cor_err_hdr_upper",
-	"sh_md_dqlp_mmr_xcerr1",
-	"sh_md_dqlp_mmr_xcerr2",
-	"sh_md_dqlp_mmr_ycerr1",
-	"sh_md_dqlp_mmr_ycerr2",
-	"sh_md_dqrp_mmr_xcerr1",
-	"sh_md_dqrp_mmr_xcerr2",
-	"sh_md_dqrp_mmr_ycerr1",
-	"sh_md_dqrp_mmr_ycerr2",
-	"sh_md_cor_time_stamp",
-
-/* MD CE, UCE */
-	"sh_md_dqls_mmr_xamopw_err",
-	"sh_md_dqrs_mmr_yamopw_err",
-
-/* XN */
-	"sh_xn_error_summary",
-	"sh_xn_first_error",
-	"sh_xn_error_overflow",
-
-/* XN HW */
-	"sh_xniilb_error_summary",
-	"sh_xniilb_first_error",
-	"sh_xniilb_error_overflow",
-	"sh_xniilb_error_detail_1",
-	"sh_xniilb_error_detail_2",
-	"sh_xniilb_error_detail_3",
-
-	"sh_ni0_error_summary_1",
-	"sh_ni0_first_error_1",
-	"sh_ni0_error_overflow_1",
-
-	"sh_ni0_error_summary_2",
-	"sh_ni0_first_error_2",
-	"sh_ni0_error_overflow_2",
-	"sh_ni0_error_detail_1",
-	"sh_ni0_error_detail_2",
-	"sh_ni0_error_detail_3",
-
-	"sh_ni1_error_summary_1",
-	"sh_ni1_first_error_1",
-	"sh_ni1_error_overflow_1",
-
-	"sh_ni1_error_summary_2",
-	"sh_ni1_first_error_2",
-	"sh_ni1_error_overflow_2",
-
-	"sh_ni1_error_detail_1",
-	"sh_ni1_error_detail_2",
-	"sh_ni1_error_detail_3",
-
-	"sh_xn_hw_time_stamp",
-
-/* XN HW & UCE & SBE */
-	"sh_xnpi_error_summary",
-	"sh_xnpi_first_error",
-	"sh_xnpi_error_overflow",
-	"sh_xnpi_error_detail_1",
-
-	"sh_xnmd_error_summary",
-	"sh_xnmd_first_error",
-	"sh_xnmd_error_overflow",
-	"sh_xnmd_ecc_err_report",
-	"sh_xnmd_error_detail_1",
-
-/* XN UCE */
-	"sh_xn_uncorrected_detail_1",
-	"sh_xn_uncorrected_detail_2",
-	"sh_xn_uncorrected_detail_3",
-	"sh_xn_uncorrected_detail_4",
-	"sh_xn_uncor_time_stamp",
-
-/* XN CE */
-	"sh_xn_corrected_detail_1",
-	"sh_xn_corrected_detail_2",
-	"sh_xn_corrected_detail_3",
-	"sh_xn_corrected_detail_4",
-	"sh_xn_cor_time_stamp",
-
-/* LB HW */
-	"sh_lb_error_summary",
-	"sh_lb_first_error",
-	"sh_lb_error_overflow",
-	"sh_lb_error_detail_1",
-	"sh_lb_error_detail_2",
-	"sh_lb_error_detail_3",
-	"sh_lb_error_detail_4",
-	"sh_lb_error_detail_5",
-	"sh_junk_error_status",
-};
 
-void 
-sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) 
+
+/*
+ * Interval for calling SAL to poll for errors that do NOT cause error
+ * interrupts. SAL will raise a CPEI if any errors are present that
+ * need to be logged.
+ */
+#define CPEI_INTERVAL	(5*HZ)
+
+
+struct timer_list sn_cpei_timer;
+void sn_init_cpei_timer(void);
+
+
+/*
+ * print_hook
+ *
+ * This function is the callback routine that SAL calls to log error
+ * info for platform errors. 
+ */
+static int
+print_hook(const char *fmt, ...)
 {
-	sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data;
-	u64 *mmr_val = (u64 *)&(sh_info->shub_state);
-	char **mmr_name = shub_mmr_names;
-	int mmr_count = sizeof(sal_log_shub_state_t)>>3;
-
-	while(mmr_count) {
-		if(*mmr_val) {
-			prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val);
-		}
-		mmr_name++;
-		mmr_val++;
-		mmr_count--;
+	static int	newline=1;
+	char		buf[400], *p;
+	va_list		args;
+	int		len=0;
+
+
+	va_start(args, fmt);
+	if (newline) {
+		strcpy(buf, "+ ");
+		len += 2;
 	}
+	len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args);
 
+	/* Prefix each line with "+ " to be consistent with mca.c. */
+	p = buf;
+	while ((p=strchr(p, '\n')) && *++p != '\0') {
+		memmove(p+2, p, 1+strlen(p));
+		strncpy(p, "+ ", 2);
+		len += 2;
+	}
+	newline = (p != 0);
+
+	va_end(args);
+	printk("%s", buf);
+	return len;
 }
 
-sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
+
+
+/*
+ * ia64_sn2_platform_plat_specific_err_print
+ *
+ * Called by the MCA handler to log platform-specific errors.
+ */
+void
+ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
 {
-	struct ia64_sal_retval isrv;
+	ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len);
+}
+
 
+
+static void
+sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
+{
 	/*
 	 * this function's sole purpose is to call SAL when we receive
 	 * a CE interrupt from SHUB or when the timer routine decides
@@ -234,46 +115,45 @@
 	 */
 
 	/* CALL SAL_LOG_CE */
-	SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0);
-}
 
-#include <linux/timer.h>
+	ia64_sn_plat_cpei_handler();
+}
 
-#define CPEI_INTERVAL   (HZ/100)
-struct timer_list sn_cpei_timer;
-void sn_init_cpei_timer(void);
 
-void
+static void
 sn_cpei_timer_handler(unsigned long dummy) {
-        sn_cpei_handler(-1, NULL, NULL);
-        del_timer(&sn_cpei_timer);
-        sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_cpei_handler(-1, NULL, NULL);
+	del_timer(&sn_cpei_timer);
+	sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
         add_timer(&sn_cpei_timer);
 }
 
 void
 sn_init_cpei_timer() {
-        sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
         sn_cpei_timer.function = sn_cpei_timer_handler;
         add_timer(&sn_cpei_timer);
 }
 
+
+
+
 #ifdef ajmtestceintr
 
 struct timer_list sn_ce_timer;
 
 void
 sn_ce_timer_handler(long dummy) {
-        unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00;
+	unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00;
 
-        *pi_ce_error_inject_reg = 0x0000000000000100;
-        del_timer(&sn_ce_timer);
-        sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
+	*pi_ce_error_inject_reg = 0x0000000000000100;
+	del_timer(&sn_ce_timer);
+	sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
         add_timer(&sn_ce_timer);
 }
 
 sn_init_ce_timer() {
-        sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
         sn_ce_timer.function = sn_ce_timer_handler;
         add_timer(&sn_ce_timer);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/misctest.c linux-2.4.21-rc3/arch/ia64/sn/kernel/misctest.c
--- linux-2.4.20/arch/ia64/sn/kernel/misctest.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/misctest.c	2003-05-22 22:06:39.000000000 +0000
@@ -4,119 +4,368 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
-
+#include <asm/page.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sn/intr.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/leds.h>
 
 extern	int autotest_enabled;
-int	mcatest=0;
-
+long	mcatest=0, debug0, debug1, debug2, debug3;
 
+#define HDELAY(t)	(IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t))
 
 /* 
  * mcatest
- *	1 = expected MCA
- *	2 = unexpected MCA
- *	3 = expected MCA + unexpected MCA
- *	4 = INIT
- *	5 = speculative load to garbage memory address
- *	6 = speculative load with ld8.s (needs poison hack in PROM)
- *	7 = speculative load from mis-predicted branch (needs poison hack in PROM)
+ *	mactest contains a decimal number (RPTT) where
+ *		R - flag, if non zero, run forever
+ *
+ *		P - identifies when to run the test
+ *		    0 execute test at cpu 0 early init
+ *		    1 execute test at cpu 0 idle
+ *		    2 execute test at last (highest numbered) cpu idle
+ *		    3 execute test on all cpus at idle
+ *
+ *		TT- identifies test to run
+ *		    01 = MCA via dup TLB dropin
+ *		    02 = MCA via garbage address
+ *		    03 = lfetch via garbage address
+ *		    05 = INIT self
+ *		    06 = INIT other cpu
+ *		    07 = INIT non-existent cpu
+ *		    10 = IPI stress test. Target cpu 0
+ *		    11 = IPI stress test. Target all cpus
+ *		    12 = TLB stress test
+ *		    13 = Park cpu (spinloop)
+ *		    14 = One shot TLB test with tlb spinlock
+ *		    15 = One shot TLB test
+ *		    16 = One shot TLB test sync'ed with RTC
+ *		    20 = set led to the cpuid & spin.
+ *		    21 = Try mixed cache/uncached refs & see what happens
+ *		    22 = Call SAL reboot
+ *		    23 = Call PAL halt
  */
 static int __init set_mcatest(char *str)
 {
-	get_option(&str, &mcatest);
+	int	val;
+	get_option(&str, &val);
+	mcatest = val;
 	return 1;
 }
-
 __setup("mcatest=", set_mcatest);
 
+static int __init set_debug0(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug0 = val;
+	return 1;
+}
+__setup("debug0=", set_debug0);
+
+static int __init set_debug1(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug1 = val;
+	return 1;
+}
+__setup("debug1=", set_debug1);
+
+static int __init set_debug2(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug2 = val;
+	return 1;
+}
+__setup("debug2=", set_debug2);
+
+static int __init set_debug3(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug3 = val;
+	return 1;
+}
+__setup("debug3=", set_debug3);
+
+static volatile int	go;
+
+static void
+do_sync(int pos) {
+	if (pos != 3)
+		return;
+	else if (smp_processor_id() == 0)
+		go = 1;
+	else
+		while (!go);
+}
+
+static void
+sgi_mcatest_bkpt(void)
+{
+}
+
+
+/*
+ * Optional test
+ *	pos - 0 called from early init
+ *	pos - called when cpu about to go idle (fully initialized
+ */
 void
-sgi_mcatest(void)
+sgi_mcatest(int pos)
 {
-	if (mcatest == 1 || mcatest == 3) {
-		long	*p, result, adrs[] = {0xc0000a000f021004UL, 0xc0000a000f026004UL, 0x800000000, 0x500000, 0};
-		long	size[] = {1,2,4,8};
-		int	r, i, j;
-		p = (long*)0xc000000000000000UL;
-		ia64_fc(p);
-		*p = 0x0123456789abcdefL;
-		for (i=0; i<5; i++) {
-			for (j=0; j<4; j++) {
-				printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]);
-				result = -1;
-				r = ia64_sn_probe_io_slot (adrs[i], size[j], &result);
-				printk("    status %d, val 0x%lx\n", r, result); 
+	long	spos, test, repeat;
+	int	cpu, curcpu, i, n;
+
+	//if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323;
+	repeat = mcatest/1000;
+	spos = (mcatest/100)%10;
+	test = mcatest % 100;
+	curcpu = smp_processor_id();
+
+	if ( mcatest == 0 || !((pos == 0 && spos == 0) ||
+		(pos == 1 && spos == 3) ||
+	        (pos == 1 && spos == 1 && curcpu == 0) ||
+	        (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1)))
+		return;
+	     
+again:
+	if (test == 1 || test == 2 || test == 3) {
+		void zzzmca(int);
+		printk("CPU %d: About to cause unexpected MCA\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		zzzmca(test-1);
+	
+		HDELAY(100000);
+	}
+
+	if (test == 4) {
+		long    result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL,  0xc00000180e022004UL, 0xc00000180e023004UL };
+		long    size[] = {1,2,4,8};
+		int     r, i, j, k;
+
+		for (k=0; k<2; k++) {
+			for (i=0; i<6; i++) {
+				for (j=0; j<4; j++) {
+					printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]);
+					result = -1;
+					r = ia64_sn_probe_io_slot (adrs[i], size[j], &result);
+					printk("    status %d, val 0x%lx\n", r, result);
+					udelay(100000);
+				}
 			}
 		}
+
 	}
-	if (mcatest == 2 || mcatest == 3) {
-		void zzzmca(int, int, int);
-		printk("About to cause unexpected MCA\n");
-		zzzmca(mcatest, 0x32dead, 0x33dead);
-	}
-	if (mcatest == 4) {
-		long	*p;
-		int	delivery_mode = 5;
-		printk("About to try to cause an INIT on cpu 0\n");
-		p = (long*)((0xc0000a0000000000LL | ((long)get_nasid())<<33) | 0x1800080);
-		*p = (delivery_mode << 8);
-		udelay(10000);
-		printk("Returned from INIT\n");
-	}
-	if (mcatest == 5) {
-		int zzzspec(long);
-		int	i;
-		long	psr, dcr, res, val, addr=0xff00000000UL;
-
-		dcr = ia64_get_dcr();
-		for (i=0; i<5; i++) {
-			printk("Default DCR: 0x%lx\n", ia64_get_dcr());
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(0);
-			printk("New     DCR: 0x%lx\n", ia64_get_dcr());
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(dcr);
-			res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val);
-			printk("zzzspec: probe %ld, 0x%lx\n", res, val);
-			psr = ia64_clear_ic();
-			ia64_itc(0x2, 0xe00000ff00000000UL,
-			          pte_val(mk_pte_phys(0xff00000000UL,
-				  __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M);
-			ia64_set_psr(psr);
-			ia64_srlz_i ();
-		}
 
+	if (test == 5) {
+		cpu =  curcpu;
+		printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
+		
+		HDELAY(100000);
+		printk("CPU %d: Returned from INIT\n", curcpu);
+	}
+
+	if (test == 6) {
+		cpu =  curcpu ^ 1;
+		printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 7) {
+		printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
 	}
-	if (mcatest == 6) {
-		int zzzspec(long);
-		int	i;
-		long	dcr, addr=0xe000000008000000UL;
-
-		dcr = ia64_get_dcr();
-		for (i=0; i<5; i++) {
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(0);
-		}
-		ia64_set_dcr(dcr);
-	}
-	if (mcatest == 7) {
-		int zzzspec2(long, long);
-		int	i;
-		long	addr=0xe000000008000000UL;
-		long	addr2=0xe000000007000000UL;
-
-		for (i=0; i<5; i++) {
-			printk("zzzspec2\n");
-			zzzspec2(addr, addr2);
+
+	if (test == 10) {
+		n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000;
+		cpu = 0;
+		printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 11) {
+		n = IS_RUNNING_ON_SIMULATOR() ? 100 : 10000000;
+		printk("CPU %d: IPI stress test. Target all cpus\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			for (cpu=0; cpu<smp_num_cpus; cpu++)
+				if (smp_num_cpus > 2 && cpu != curcpu)
+					platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 12) {
+		long adr = 0xe002200000000000UL;
+		n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000;
+		printk("CPU %d: TLB flush stress test\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			platform_global_tlb_purge(adr, adr+25*PAGE_SIZE, 14);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+	
+	if (test == 13) {
+		printk("CPU %d: Park cpu in spinloop\n", curcpu);
+		while(1);
+	}
+	if (test == 14 || test == 15 || test == 16 || test == 17) {
+		long adr = 0xe002200000000000UL;
+		static int inited=0;
+		if (inited == 0) {
+			if (debug0 == 0) debug0 = 1;
+			repeat = 1;
+			do_sync(spos);
+			if (curcpu >= smp_num_cpus-2) {
+				printk("Parking cpu %d\n", curcpu);
+				local_irq_disable();
+				while(1);
+			} else {
+				printk("Waiting cpu %d\n", curcpu);
+				HDELAY(1000000);
+			}
+			HDELAY(1000000);
+			inited = 1;
+		}
+		if (test == 16 || test == 17) {
+			unsigned long t, shift, mask;
+			mask =  (smp_num_cpus > 16) ? 0x1f : 0xf;
+			shift = 25-debug1;
+			do {
+				t = get_cycles();
+				if (IS_RUNNING_ON_SIMULATOR())
+					t = (t>>8);
+				else
+					t = (t>>shift);
+				t = t & mask;
+			} while (t == curcpu);
+			do {
+				t = get_cycles();
+				if (IS_RUNNING_ON_SIMULATOR())
+					t = (t>>8);
+				else
+					t = (t>>shift);
+				t = t & mask;
+			} while (t != curcpu);
+		}
+		if(debug3) printk("CPU %d: One TLB start\n", curcpu);
+		if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14);
+		if(debug3) printk("CPU %d: One TLB flush done\n", curcpu);
+	}
+	if (test == 20) {
+		local_irq_disable();
+		set_led_bits(smp_processor_id(), 0xff);
+		while(1);
+	}
+	if (test == 21) {
+		extern long ia64_mca_stack[];
+		int		i, n;
+		volatile long	*p, *up;
+		p = (volatile long*)__imva(ia64_mca_stack);
+		up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET);
+
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(p+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(up+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n");
+		for (n=0, i=0; i<100; i++)
+			*(p+i) = i;
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(up+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n");
+		for (n=0, i=0; i<100; i++)
+			ia64_fc((void*)(p+i));
+		printk("ZZZ done\n");
+	}
+	if (test == 21) {
+		int i;
+		volatile long tb, t[10];
+		for (i=0; i<10; i++) {
+			tb = debug3+ia64_get_itc();
+			sgi_mcatest_bkpt();
+			t[i] = ia64_get_itc() - tb;
+		}
+		for (i=0; i<10; i++) {
+			printk("ZZZ NULL  0x%lx\n", t[i]);
+		}
+		for (i=0; i<10; i++) {
+			tb = debug3+ia64_get_itc();
+			ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0);
+			t[i] = ia64_get_itc() - tb;
 		}
+		for (i=0; i<10; i++) {
+			printk("ZZZ DRAIN 0x%lx\n", t[i]);
+		}
+	}
+	if (test == 22) {
+		extern void machine_restart(char*);
+		printk("ZZZ machine_restart\n");
+		machine_restart(0);
 	}
+	if (test == 23) {
+		printk("ZZZ ia64_pal_halt_light\n");
+		ia64_pal_halt_light();
+	}
+	if (repeat)
+		goto again;
+
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/setup.c linux-2.4.21-rc3/arch/ia64/sn/kernel/setup.c
--- linux-2.4.20/arch/ia64/sn/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/setup.c	2003-05-22 22:06:51.000000000 +0000
@@ -47,14 +47,14 @@
 #include <linux/bootmem.h>
 #include <linux/mmzone.h>
 #include <linux/interrupt.h>
+#include <linux/acpi.h>
+#include <linux/compiler.h>
+#include <linux/sched.h>
 
 #include <asm/io.h>
 #include <asm/sal.h>
 #include <asm/machvec.h>
 #include <asm/system.h>
-#ifdef CONFIG_IA64_MCA
-#include <asm/acpi-ext.h>
-#endif
 #include <asm/processor.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
@@ -68,15 +68,21 @@
 #include <asm/sn/leds.h>
 #include <asm/sn/bte.h>
 #include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
 
 #ifdef CONFIG_IA64_SGI_SN2
 #include <asm/sn/sn2/shub.h>
 #endif
 
-extern void bte_init_node (nodepda_t *, cnodeid_t, char **);
+extern void bte_init_node (nodepda_t *, cnodeid_t);
 extern void bte_init_cpu (void);
 
-long sn_rtc_cycles_per_second;   
+unsigned long sn_rtc_cycles_per_second;   
+unsigned long sn_rtc_usec_per_cyc;
+
+partid_t sn_partid = -1;
+char sn_system_serial_number_string[128];
+u64 sn_partition_serial_number;
 
 /*
  * This is the address of the RRegs in the HSpace of the global
@@ -137,7 +143,7 @@
  * virt_to_page() (asm-ia64/page.h), among other things.
  */
 unsigned long
-sn_map_nr (unsigned long addr)
+sn_map_nr (void *addr)
 {
 	return MAP_NR_DISCONTIG(addr);
 }
@@ -149,10 +155,43 @@
  * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK
  * are turned on.  See start_kernel() in init/main.c.
  */
-#if defined(CONFIG_IA64_EARLY_PRINTK) && defined(CONFIG_IA64_SGI_SN)
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+
 void __init
 early_sn_setup(void)
 {
+	void ia64_sal_handler_init (void *entry_point, void *gpval);
+	efi_system_table_t			*efi_systab;
+	efi_config_table_t 			*config_tables;
+	struct ia64_sal_systab			*sal_systab;
+	struct ia64_sal_desc_entry_point	*ep;
+	char					*p;
+	int					i;
+
+	/*
+	 * Parse enough of the SAL tables to locate the SAL entry point. Since, console
+	 * IO on SN2 is done via SAL calls, early_printk wont work without this.
+	 *
+	 * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c.
+	 * Any changes to those file may have to be made hereas well.
+	 */
+	efi_systab = (efi_system_table_t*)__va(ia64_boot_param->efi_systab);
+	config_tables = __va(efi_systab->tables);
+	for (i = 0; i < efi_systab->nr_tables; i++) {
+		if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
+			sal_systab = __va(config_tables[i].table);
+			p = (char*)(sal_systab+1);
+			for (i = 0; i < sal_systab->entry_count; i++) {
+				if (*p == SAL_DESC_ENTRY_POINT) {
+					ep = (struct ia64_sal_desc_entry_point *) p;
+					ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
+					break;
+				}
+				p += SAL_DESC_SIZE(*p);
+			}
+		}
+	}
+
 	if ( IS_RUNNING_ON_SIMULATOR() ) {
 #if defined(CONFIG_IA64_SGI_SN1)
 		master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0);
@@ -162,18 +201,10 @@
 		printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address);
 	}
 }
-#endif /* CONFIG_IA64_EARLY_PRINTK && CONFIG_IA64_SGI_SN */
+#endif /* CONFIG_IA64_SGI_SN1 */
 
-#ifdef NOT_YET_CONFIG_IA64_MCA
-extern void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs);
-static struct irqaction mca_cpe_irqaction = { 
-	handler:    ia64_mca_cpe_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "cpe_hndlr"
-};
-#endif
 #ifdef CONFIG_IA64_MCA
-extern int platform_irq_list[];
+extern int platform_intr_list[];
 #endif
 
 extern nasid_t master_nasid;
@@ -191,22 +222,56 @@
 {
 	long status, ticks_per_sec, drift;
 	int i;
+	int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
+
+	printk("SGI SAL version %x.%02x\n", major, minor);
+
+	/*
+	 * Confirm the SAL we're running on is recent enough...
+	 */
+	if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR &&
+					   minor < SN_SAL_MIN_MINOR)) {
+		printk(KERN_ERR "This kernel needs SGI SAL version >= "
+		       "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR);
+		panic("PROM version too old\n");
+	}
+
+#ifdef CONFIG_IA64_SGI_SN2
+	{
+		extern void io_sh_swapper(int, int);
+		io_sh_swapper(get_nasid(), 0);
+	}
+#endif
 
 	master_nasid = get_nasid();
 	(void)get_console_nasid();
+#ifndef CONFIG_IA64_SGI_SN1
+	{
+		extern nasid_t get_master_baseio_nasid(void);
+		(void)get_master_baseio_nasid();
+	}
+#endif
 
 	status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift);
-	if (status != 0 || ticks_per_sec < 100000)
-		printk(KERN_WARNING "unable to determine platform RTC clock frequency\n");
+	if (status != 0 || ticks_per_sec < 100000) {
+		printk(KERN_WARNING "unable to determine platform RTC clock frequency, guessing.\n");
+		/* PROM gives wrong value for clock freq. so guess */
+		sn_rtc_cycles_per_second = 1000000000000UL/30000UL;
+	}
 	else
 		sn_rtc_cycles_per_second = ticks_per_sec;
+
+#ifdef CONFIG_IA64_SGI_SN1
+	/* PROM has wrong value on SN1 */
+	sn_rtc_cycles_per_second = 990177;
+#endif
+	sn_rtc_usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
+			       + sn_rtc_cycles_per_second/2) / sn_rtc_cycles_per_second;
 		
 	for (i=0;i<NR_CPUS;i++)
 		_sn_irq_desc[i] = _irq_desc;
 
-#ifdef CONFIG_IA64_MCA
-	platform_irq_list[ACPI20_ENTRY_PIS_CPEI] = IA64_PCE_VECTOR;
-#endif
+	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_PCE_VECTOR;
 
 
 	if ( IS_RUNNING_ON_SIMULATOR() )
@@ -296,7 +361,7 @@
 	 */
 	for (cnode = 0; cnode < numnodes; cnode++) {
 		init_platform_nodepda(nodepdaindr[cnode], cnode);
-		bte_init_node (nodepdaindr[cnode], cnode, cmdline_p);
+		bte_init_node (nodepdaindr[cnode], cnode);
 	}
 }
 
@@ -331,9 +396,16 @@
 	cnode = nasid_to_cnodeid(nasid);
 	slice = cpu_physical_id_to_slice(cpuphyid);
 
+	printk("CPU %d: nasid %d, slice %d, cnode %d\n",
+			smp_processor_id(), nasid, slice, cnode);
+
+	memset(&pda, 0, sizeof(pda));
 	pda.p_nodepda = nodepdaindr[cnode];
-	pda.led_address = (long*) (LED0 + (slice<<LED_CPU_SHIFT));
-	pda.led_state = 0;
+	pda.led_address = (typeof(pda.led_address)) (LED0 + (slice<<LED_CPU_SHIFT));
+#ifdef LED_WAR
+	pda.led_address = (typeof(pda.led_address)) (LED0 + (slice<<(LED_CPU_SHIFT-1))); /* temp til L1 firmware fixed */
+#endif
+	pda.led_state = LED_ALWAYS_SET;
 	pda.hb_count = HZ/2;
 	pda.hb_state = 0;
 	pda.idle_flag = 0;
@@ -359,9 +431,35 @@
 		irqpdaindr[cpuid] = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t));
 	else
 		irqpdaindr[cpuid] = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL, get_order(sizeof(irqpda_t))));
+
 	memset(irqpdaindr[cpuid], 0, sizeof(irqpda_t));
 	pda.p_irqpda = irqpdaindr[cpuid];
-	pda.pio_write_status_addr = (volatile unsigned long *)LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) );
+
+	pda.pio_write_status_addr = (volatile unsigned long *)
+			LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) );
+	pda.mem_write_status_addr = (volatile u64 *)
+			LOCAL_MMR_ADDR((slice < 2 ? SH_MEMORY_WRITE_STATUS_0 : SH_MEMORY_WRITE_STATUS_1 ) );
+
+	if (nodepda->node_first_cpu == cpuid) {
+		int	buddy_nasid;
+		buddy_nasid = cnodeid_to_nasid(local_cnodeid() == numnodes-1 ? 0 : local_cnodeid()+ 1);
+		pda.pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL);
+	}
+
+#ifdef BRINGUP2
+	/*
+	 * Zero out the counters used for counting MCAs
+	 *   ZZZZZ temp
+	 */
+	{
+		long	*p;
+		p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE0);
+		*p = 0;
+		p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE1);
+		*p = 0;
+	}
+
+#endif
 #endif
 
 #ifdef CONFIG_IA64_SGI_SN1
@@ -401,7 +499,6 @@
 	return cpu;
 }
 
-#if 0 /* ##jh */
 /**
  * get_cycles - return a non-decreasing timestamp
  *
@@ -412,4 +509,186 @@
 {
 	return GET_RTC_COUNTER();
 }
+
+/**
+ * gettimeoffset - number of usecs elapsed since &xtime was last updated
+ *
+ * This function is used by do_gettimeofday() to determine the number
+ * of usecs that have elapsed since the last update to &xtime.  On SN
+ * this is accomplished using the RTC built in to each Hub chip; each
+ * is guaranteed to be synchronized by the PROM, so a local read will
+ * suffice (get_cycles() does this for us).  A snapshot of the RTC value
+ * is taken on every timer interrupt and this function more or less
+ * subtracts that snapshot value from the current value.
+ *
+ * Note that if a lot of processing was done during the last timer
+ * interrupt then &xtime may be some number of jiffies out of date.
+ * This function must account for that.
+ */
+unsigned long
+gettimeoffset(void)
+{
+	unsigned long current_rtc_val, local_last_rtc_val;
+	unsigned long usec;
+
+	local_last_rtc_val = last_rtc_val;
+	current_rtc_val = get_cycles();
+	usec = last_itc_lost_usec;
+
+	/* If the RTC has wrapped around, compensate */
+	if (unlikely(current_rtc_val < local_last_rtc_val)) {
+		printk(KERN_NOTICE "RTC wrapped cpu:%d current:0x%lx last:0x%lx\n",
+				smp_processor_id(), current_rtc_val,
+				local_last_rtc_val);
+		current_rtc_val += RTC_MASK;
+	}
+
+	usec += ((current_rtc_val - local_last_rtc_val)*sn_rtc_usec_per_cyc) >> 
+		IA64_USEC_PER_CYC_SHIFT;
+
+	/*
+	 * usec is the number of microseconds into the current clock interval. Every
+	 * clock tick, xtime is advanced by "tick" microseconds. If "usec"
+	 * is allowed to get larger than "tick", the time value returned by gettimeofday
+	 * will go backward.
+	 */
+	if (usec >= tick)
+		usec = tick-1;
+
+	return usec;
+}
+
+#ifdef II_PRTE_TLB_WAR
+long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */
+#endif
+
+#ifdef BUS_INT_WAR
+
+#include <asm/hw_irq.h>
+#include <asm/sn/pda.h>
+
+void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs);
+
+static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;
+
+#define IRQCPU(irq)	((irq)>>8)
+
+void
+sn_add_polled_interrupt(int irq, int interval)
+{
+	unsigned long flags, irq_cnt;
+	sn_poll_entry_t	*irq_list;
+
+	irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;;
+
+	spin_lock_irqsave(&irq_lock, flags);
+	irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count;
+	irq_list[irq_cnt].irq = irq;
+	irq_list[irq_cnt].interval = interval;
+	irq_list[irq_cnt].tick = interval;
+	pdacpu(IRQCPU(irq)).pda_poll_entry_count++;
+	spin_unlock_irqrestore(&irq_lock, flags);
+
+
+}
+
+void
+sn_delete_polled_interrupt(int irq)
+{
+	unsigned long flags, i, irq_cnt;
+	sn_poll_entry_t	*irq_list;
+
+	irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;
+
+	spin_lock_irqsave(&irq_lock, flags);
+	irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count;
+	for (i=0; i<irq_cnt; i++) {
+		if (irq_list[i].irq == irq) {
+			irq_list[i] = irq_list[irq_cnt-1];
+			pdacpu(IRQCPU(irq)).pda_poll_entry_count--;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+long sn_int_poll_ticks=50;
+
+void
+sn_irq_poll(int cpu, int reason) 
+{
+	unsigned long flags, i;
+	sn_poll_entry_t	*irq_list;
+
+
+#ifdef CONFIG_SHUB_1_0_SPECIFIC
+	ia64_handle_irq(IA64_IPI_VECTOR, 0);
+#else
+	if (sn_int_poll_ticks == 0)
+		return;
+#endif
+	irq_list = pda.pda_poll_entries;
+
+	for (i=0; i<pda.pda_poll_entry_count; i++, irq_list++) {
+		if (--irq_list->tick <= 0) {
+#ifdef CONFIG_SHUB_1_0_SPECIFIC
+			irq_list->tick = irq_list->interval;
+#else
+			irq_list->tick = sn_int_poll_ticks;
+#endif
+			local_irq_save(flags);
+			ia64_handle_irq(irq_to_vector(irq_list->irq), 0);
+			local_irq_restore(flags);
+		}
+	}
+}	
+
+#define PROCFILENAME	"sn_int_poll_ticks"
+
+static struct proc_dir_entry *proc_op;
+
+
+static int
+read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+
+	len += sprintf(buffer + len, "Poll hack: interval %ld ticks\n", sn_int_poll_ticks);
+
+	if (len <= off+count) *eof = 1;
+	*start = buffer + off;
+	len   -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+static int
+write_proc (struct file *file, const char *userbuf, unsigned long count, void *data)
+{
+       extern long atoi(char *);
+       char        buf[80];
+
+       if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
+           return -EFAULT;
+
+       sn_int_poll_ticks = atoi(buf);
+
+       return count;
+}
+
+
+int __init
+sn_poll_init(void)
+{
+	if ((proc_op = create_proc_entry(PROCFILENAME, 0644, NULL)) == NULL) {
+		printk("%s: unable to create proc entry", PROCFILENAME);
+		return -1;
+	}
+	proc_op->read_proc = read_proc;
+	proc_op->write_proc = write_proc;
+	return 0;
+}
+
+module_init(sn_poll_init);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/Makefile linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# ia64/platform/sn/sn1/Makefile
+# arch/ia64/sn/kernel/sn1/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
 #
@@ -40,12 +40,8 @@
 .S.o:
 	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
 
-all: sn1.a
-
-O_TARGET        = sn1.a
+O_TARGET        = sn1.o
 
 obj-y          = cache.o error.o iomv.o synergy.o sn1_smp.o
 
-clean::
-
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/sn1_smp.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/sn1_smp.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/sn1_smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/sn1_smp.c	2003-05-22 22:06:27.000000000 +0000
@@ -59,11 +59,16 @@
  * to other cpus for flushing TLB ranges.
  */
 typedef struct {
-	unsigned long	start;
-	unsigned long	end;
-	unsigned long	nbits;
-	unsigned int	rid;
-	atomic_t	unfinished_count;
+	union {
+		struct {
+			unsigned long	start;
+			unsigned long	end;
+			unsigned long	nbits;
+			unsigned int	rid;
+			atomic_t	unfinished_count;
+		} ptc;
+		char pad[SMP_CACHE_BYTES];
+	};
 } ptc_params_t;
 
 #define NUMPTC	512
@@ -149,11 +154,11 @@
 		return;
 
 	do {
-		start = ptcParams->start;
+		start = ptcParams->ptc.start;
 		saved_rid = (unsigned int) ia64_get_rr(start);
-		end = ptcParams->end;
-		nbits = ptcParams->nbits;
-		rid = ptcParams->rid;
+		end = ptcParams->ptc.end;
+		nbits = ptcParams->ptc.nbits;
+		rid = ptcParams->ptc.rid;
 
 		if (saved_rid != rid) {
 			ia64_set_rr(start, (unsigned long)rid);
@@ -167,7 +172,7 @@
 
 		ia64_srlz_i();
 
-		result = atomic_dec(&ptcParams->unfinished_count);
+		result = atomic_dec(&ptcParams->ptc.unfinished_count);
 #ifdef PTCDEBUG
 		{
 		    int i = ptcParams-&ptcParamArray[0];
@@ -256,7 +261,7 @@
 		/* check the current pointer to the beginning */
 		ptr = params;
 		while(--ptr >= &ptcParamArray[0]) {
-			if (atomic_read(&ptr->unfinished_count) == 0)
+			if (atomic_read(&ptr->ptc.unfinished_count) == 0)
 				break;
 			++backlog;
 		}
@@ -265,7 +270,7 @@
 			/* check the end of the array */
 			ptr = &ptcParamArray[NUMPTC];
 			while (--ptr > params) {
-				if (atomic_read(&ptr->unfinished_count) == 0)
+				if (atomic_read(&ptr->ptc.unfinished_count) == 0)
 					break;
 				++backlog;
 			}
@@ -275,12 +280,12 @@
 #endif	/* PTCDEBUG */
 
 	/* wait for the next entry to clear...should be rare */
-	if (atomic_read(&next->unfinished_count) > 0) {
+	if (atomic_read(&next->ptc.unfinished_count) > 0) {
 #ifdef PTCDEBUG
 		ptcParamsAllBusy++;
 
-		if (atomic_read(&nextnext->unfinished_count) == 0) {
-		    if (atomic_read(&next->unfinished_count) > 0) {
+		if (atomic_read(&nextnext->ptc.unfinished_count) == 0) {
+		    if (atomic_read(&next->ptc.unfinished_count) > 0) {
 			panic("\nnonzero next zero nextnext %lx %lx\n",
 			    (long)next, (long)nextnext);
 		    }
@@ -293,16 +298,16 @@
 		local_irq_restore(irqflags);
 
 		/* now we know it's not this cpu, so just wait */
-		while (atomic_read(&next->unfinished_count) > 0) {
+		while (atomic_read(&next->ptc.unfinished_count) > 0) {
 			barrier();
 		}
 	}
 
-	params->start = start;
-	params->end = end;
-	params->nbits = nbits;
-	params->rid = (unsigned int) ia64_get_rr(start);
-	atomic_set(&params->unfinished_count, smp_num_cpus);
+	params->ptc.start = start;
+	params->ptc.end = end;
+	params->ptc.nbits = nbits;
+	params->ptc.rid = (unsigned int) ia64_get_rr(start);
+	atomic_set(&params->ptc.unfinished_count, smp_num_cpus);
 
 	/* The atomic_set above can hit memory *after* the update
 	 * to ptcParamsEmpty below, which opens a timing window
@@ -335,13 +340,11 @@
 	 * shouldn't be using user TLB entries.  To change this to wait
 	 * for all the flushes to complete, enable the following code.
 	 */
-#ifdef SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE
+#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR)
 	/* this code is not tested */
 	/* wait for the flush to complete */
-	while (atomic_read(&params.unfinished_count) > 1)
+	while (atomic_read(&params->ptc.unfinished_count) > 0)
 		barrier();
-
-	atomic_set(&params->unfinished_count, 0);
 #endif
 }
 
@@ -369,18 +372,17 @@
 
 	static int 	off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088};
 
+#ifdef BUS_INT_WAR
+	if (vector != ap_wakeup_vector) {
+		return;
+	}
+#endif
+
 	nasid = cpu_physical_id_to_nasid(physid);
         slice = cpu_physical_id_to_slice(physid);
 
 	p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]);
 
-#if defined(ZZZBRINGUP)
-	{
-	static int count=0;
-	if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx\n",
-		smp_processor_id(), vector, nasid, slice, (long)p);
-	}
-#endif
 	mb();
 	*p = (delivery_mode << 8) | (vector & 0xff);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/synergy.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/synergy.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/synergy.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn1/synergy.c	2003-05-22 22:06:38.000000000 +0000
@@ -240,6 +240,7 @@
 	synergy_perf_t	*p;
 	int		checked = 0;
 	int		err = 0;
+	unsigned long	flags;
 
 	/* bit 45 is enable */
 	modesel |= (1UL << 45);
@@ -279,7 +280,7 @@
 			memset(p, 0, sizeof(synergy_perf_t));
 			p->modesel = modesel;
 
-			spin_lock_irq(&npdap->synergy_perf_lock);
+			spin_lock_irqsave(&npdap->synergy_perf_lock, flags);
 			if (npdap->synergy_perf_data == NULL) {
 				/* circular list */
 				p->next = p;
@@ -290,7 +291,7 @@
 				p->next = npdap->synergy_perf_data->next;
 				npdap->synergy_perf_data->next = p;
 			}
-			spin_unlock_irq(&npdap->synergy_perf_lock);
+			spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags);
 		}
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/Makefile linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# ia64/platform/sn/sn1/Makefile
+# arch/ia64/sn/kernel/sn2/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
 #
@@ -40,12 +40,8 @@
 .S.o:
 	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
 
-all: sn2.a
+O_TARGET        = sn2.o
 
-O_TARGET        = sn2.a
-
-obj-y          = cache.o iomv.o sn2_smp.o
-
-clean::
+obj-y          = cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/iomv.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/iomv.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/iomv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/iomv.c	2003-05-22 22:06:43.000000000 +0000
@@ -56,10 +56,13 @@
  * a chipset register to ensure ordering.
  *
  * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear.
+ * See PV 871084 for details about the WAR about zero value.
+ *
  */
 void
 sn2_mmiob (void)
 {
-	while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000)
-		udelay(5);
+	while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != 
+				SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK)
+		udelay(1);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/ptc_deadlock.S linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/ptc_deadlock.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/ptc_deadlock.S	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,80 @@
+/* 
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <asm/sn/sn2/shub_mmr.h>
+
+#define ZEROVAL		0x3f		// "zero" value for outstanding PIO requests
+#define DEADLOCKBIT	SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT
+#define WRITECOUNT	SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT
+#define ALIAS_OFFSET	(SH_PIO_WRITE_STATUS_0_ALIAS-SH_PIO_WRITE_STATUS_0)
+
+
+	.global	sn2_ptc_deadlock_recovery_core
+	.proc  	sn2_ptc_deadlock_recovery_core
+
+sn2_ptc_deadlock_recovery_core:
+	.regstk 5,0,0,0
+
+	ptc0  	 = in0
+	data0 	 = in1
+	ptc1  	 = in2
+	data1 	 = in3
+	piowc 	 = in4
+	piowcphy = r30
+	psrsave  = r2
+	zeroval  = r3
+	scr1	 = r16
+	scr2	 = r17
+
+
+	extr.u	piowcphy=piowc,0,61;;	// Convert piowc to uncached physical address
+	dep	piowcphy=-1,piowcphy,63,1
+
+	mov	zeroval=ZEROVAL		// "zero" value for PIO write count
+
+1:
+	add	scr2=ALIAS_OFFSET,piowc	// Address of WRITE_STATUS alias register 
+	mov	scr1=7;;		// Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
+	st8.rel	[scr2]=scr1;;
+
+5:	ld8.acq	scr1=[piowc];;		// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b
+	
+
+
+	////////////// BEGIN PHYSICAL MODE ////////////////////
+	mov psrsave=psr			// Disable IC (no PMIs)
+	rsm psr.i | psr.dt | psr.ic;;
+	srlz.i;;
+
+	st8.rel [ptc0]=data0		// Write PTC0 & wait for completion.
+
+5:	ld8.acq	scr1=[piowcphy];;	// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b;;
+
+	tbit.nz	p6,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK
+	
+(p7)	st8.rel [ptc1]=data1;;		// Now write PTC1.
+
+	mov psr.l=psrsave;;		// Reenable IC
+	srlz.i;;
+	////////////// END   PHYSICAL MODE ////////////////////
+
+(p6)	br.cond.spnt 1b;;		// Repeat if DEADLOCK occurred.
+
+5:	ld8.acq	scr1=[piowc];;		// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b
+	
+	br.ret.sptk	rp
+	.endp sn2_ptc_deadlock_recovery_core
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/sn2_smp.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/sn2_smp.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/sn2_smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/sn2_smp.c	2003-05-22 22:06:26.000000000 +0000
@@ -46,6 +46,7 @@
 #include <asm/irq.h>
 #include <asm/sal.h>
 #include <asm/system.h>
+#include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/hw_irq.h>
@@ -53,6 +54,322 @@
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/sn2/shub_mmr.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/rw_mmr.h>
+
+void sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1);
+
+
+static spinlock_t sn2_global_ptc_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+
+static unsigned long sn2_ptc_deadlock_count;
+
+
+static inline unsigned long
+wait_piowc(void)
+{
+	volatile unsigned long *piows;
+	unsigned long	ws;
+
+	piows = pda.pio_write_status_addr;
+	do {
+		__asm__ __volatile__ ("mf.a" ::: "memory");
+	} while (((ws = *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != 
+			SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK);
+	return ws;
+}
+
+static long use_tlb_hack;
+static volatile unsigned long zz[1024] __attribute__((__aligned__(128)));
+static inline long
+get_itc(void)
+{
+        long ret;                                                                                                           
+        __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret));
+        return ret+1;
+}                                                                                                                           
+
+
+
+#ifdef PTCG_WAR
+/*
+ * The following structure is used to pass params thru smp_call_function
+ * to other cpus for flushing TLB ranges.
+ */
+typedef struct {
+	unsigned long	start;
+	unsigned long	end;
+	unsigned long	nbits;
+	unsigned int	rid;
+	atomic_t	unfinished_count;
+	char		fill[96];
+} ptc_params_t;
+
+#define NUMPTC	512
+
+static ptc_params_t	ptcParamArray[NUMPTC] __attribute__((__aligned__(128)));
+
+/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */
+static ptc_params_t	*ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128)));
+static volatile ptc_params_t	*ptcParamsEmpty __cacheline_aligned;
+
+/*REFERENCED*/
+static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+
+static int ptcInit = 0;
+#ifdef PTCDEBUG
+static int ptcParamsAllBusy = 0;		/* debugging/statistics */
+static int ptcCountBacklog = 0;
+static int ptcBacklog[NUMPTC+1];
+static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128)));
+static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128)));
+#endif
+
+/*
+ * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference,
+ * so that we get a clean compile with the ia64 patch without the
+ * actual SN1 specific code in arch/ia64/kernel/smp.c.
+ */
+extern void smp_send_flush_tlb (void) __attribute((weak));
+
+
+/**
+ * sn1_ptc_l_range - purge local translation cache
+ * @start: start of virtual address range
+ * @end: end of virtual address range
+ * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc))
+ *
+ * Purges the range specified from the local processor's translation cache
+ * (as opposed to the translation registers).  Note that more than the specified
+ * range *may* be cleared from the cache by some processors.
+ *
+ * This is probably not good enough, but I don't want to try to make it better 
+ * until I get some statistics on a running system. At a minimum, we should only 
+ * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's 
+ * own FSB. Also, we only have to serialize per FSB, not globally.
+ *
+ * More likely, we will have to do some work to reduce the frequency of calls to
+ * this routine.
+ */
+static inline void
+sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits)
+{
+	do {
+		__asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
+		start += (1UL << nbits);
+	} while (start < end);
+	ia64_srlz_d();
+}
+
+/**
+ * sn1_received_flush_tlb - cpu tlb flush routine
+ *
+ * Flushes the TLB of a given processor.
+ */
+void
+sn1_received_flush_tlb(void)
+{
+	unsigned long	start, end, nbits;
+	unsigned int	rid, saved_rid;
+	int		cpu = smp_processor_id();
+	int		result;
+	ptc_params_t	*ptcParams;
+
+	ptcParams = ptcParamsNextByCpu[cpu*16];
+	if (ptcParams == ptcParamsEmpty)
+		return;
+
+	do {
+		start = ptcParams->start;
+		saved_rid = (unsigned int) ia64_get_rr(start);
+		end = ptcParams->end;
+		nbits = ptcParams->nbits;
+		rid = ptcParams->rid;
+
+		if (saved_rid != rid) {
+			ia64_set_rr(start, (unsigned long)rid);
+			ia64_srlz_d();
+		}
+
+		sn1_ptc_l_range(start, end, nbits);
+
+		if (saved_rid != rid) 
+			ia64_set_rr(start, (unsigned long)saved_rid);
+
+		ia64_srlz_i();
+
+		result = atomic_dec(&ptcParams->unfinished_count);
+#ifdef PTCDEBUG
+		{
+		    int i = ptcParams-&ptcParamArray[0];
+		    ptcParamsResults[cpu][i] = (char) result;
+		    ptcParamsCounts[cpu][i]++;
+		}
+#endif /* PTCDEBUG */
+
+		if (++ptcParams == &ptcParamArray[NUMPTC])
+			ptcParams = &ptcParamArray[0];
+
+	} while (ptcParams != ptcParamsEmpty);
+
+	ptcParamsNextByCpu[cpu*16] = ptcParams;
+}
+
+/**
+ * sn1_global_tlb_purge - flush a translation cache range on all processors
+ * @start: start of virtual address range to flush
+ * @end: end of virtual address range
+ * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc))
+ *
+ * Flushes the translation cache of all processors from @start to @end.
+ */
+void
+sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
+{
+	ptc_params_t	*params;
+	ptc_params_t	*next;
+	unsigned long	irqflags;
+#ifdef PTCDEBUG
+	ptc_params_t	*nextnext;
+	int		backlog = 0;
+#endif
+
+	if (smp_num_cpus == 1) {
+		sn1_ptc_l_range(start, end, nbits);
+		return;
+	}
+
+	if (in_interrupt()) {
+		/*
+		 *  If at interrupt level and cannot get spinlock, 
+		 *  then do something useful by flushing own tlbflush queue
+		 *  so as to avoid a possible deadlock.
+		 */
+		while (!spin_trylock(&ptcParamsLock)) {
+			local_irq_save(irqflags);
+			sn1_received_flush_tlb();
+			local_irq_restore(irqflags);
+			udelay(10);	/* take it easier on the bus */	
+		}
+	} else {
+		spin_lock(&ptcParamsLock);
+	}
+
+	if (!ptcInit) {
+		int cpu;
+		ptcInit = 1;
+		memset(ptcParamArray, 0, sizeof(ptcParamArray));
+		ptcParamsEmpty = &ptcParamArray[0];
+		for (cpu=0; cpu<NR_CPUS; cpu++)
+			ptcParamsNextByCpu[cpu*16] = &ptcParamArray[0];
+
+#ifdef PTCDEBUG
+		memset(ptcBacklog, 0, sizeof(ptcBacklog));
+		memset(ptcParamsCounts, 0, sizeof(ptcParamsCounts));
+		memset(ptcParamsResults, 0, sizeof(ptcParamsResults));
+#endif	/* PTCDEBUG */
+	}
+
+	params = (ptc_params_t *) ptcParamsEmpty;
+	next = (ptc_params_t *) ptcParamsEmpty + 1;
+	if (next == &ptcParamArray[NUMPTC])
+		next = &ptcParamArray[0];
+
+#ifdef PTCDEBUG
+	nextnext = next + 1;
+	if (nextnext == &ptcParamArray[NUMPTC])
+		nextnext = &ptcParamArray[0];
+
+	if (ptcCountBacklog) {
+		/* quick count of backlog */
+		ptc_params_t *ptr;
+
+		/* check the current pointer to the beginning */
+		ptr = params;
+		while(--ptr >= &ptcParamArray[0]) {
+			if (atomic_read(&ptr->unfinished_count) == 0)
+				break;
+			++backlog;
+		}
+
+		if (backlog) {
+			/* check the end of the array */
+			ptr = &ptcParamArray[NUMPTC];
+			while (--ptr > params) {
+				if (atomic_read(&ptr->unfinished_count) == 0)
+					break;
+				++backlog;
+			}
+		}
+		ptcBacklog[backlog]++;
+	}
+#endif	/* PTCDEBUG */
+
+	/* wait for the next entry to clear...should be rare */
+	if (atomic_read(&next->unfinished_count) > 0) {
+#ifdef PTCDEBUG
+		ptcParamsAllBusy++;
+
+		if (atomic_read(&nextnext->unfinished_count) == 0) {
+		    if (atomic_read(&next->unfinished_count) > 0) {
+			panic("\nnonzero next zero nextnext %lx %lx\n",
+			    (long)next, (long)nextnext);
+		    }
+		}
+#endif
+
+		/* it could be this cpu that is behind */
+		local_irq_save(irqflags);
+		sn1_received_flush_tlb();
+		local_irq_restore(irqflags);
+
+		/* now we know it's not this cpu, so just wait */
+		while (atomic_read(&next->unfinished_count) > 0) {
+			barrier();
+		}
+	}
+
+	params->start = start;
+	params->end = end;
+	params->nbits = nbits;
+	params->rid = (unsigned int) ia64_get_rr(start);
+	atomic_set(&params->unfinished_count, smp_num_cpus);
+
+	/* The atomic_set above can hit memory *after* the update
+	 * to ptcParamsEmpty below, which opens a timing window
+	 * that other cpus can squeeze into!
+	 */
+	mb();
+
+	/* everything is ready to process:
+	 *	-- global lock is held
+	 *	-- new entry + 1 is free
+	 *	-- new entry is set up
+	 * so now:
+	 *	-- update the global next pointer
+	 *	-- unlock the global lock
+	 *	-- send IPI to notify other cpus
+	 *	-- process the data ourselves
+	 */
+	ptcParamsEmpty = next;
+	spin_unlock(&ptcParamsLock);
+	smp_send_flush_tlb();
+
+	local_irq_save(irqflags);
+	sn1_received_flush_tlb();
+	local_irq_restore(irqflags);
+
+	/* 
+	 * Since IPIs are polled event (for now), we need to wait til the
+	 * TLB flush has started.
+	 * wait for the flush to complete 
+	 */ 
+	while (atomic_read(&params->unfinished_count) > 0)
+		barrier();
+}
+
+#endif /* PTCG_WAR */
+
 
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
@@ -63,42 +380,116 @@
  * Purges the translation caches of all processors of the given virtual address
  * range.
  */
+
 void
 sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
 {
-	int		cnode, nasid;
-	volatile long	*ptc0, *ptc1, *piows;
-	unsigned long	ws, next, data0, data1;
-
-	piows = (long*)LOCAL_MMR_ADDR(get_slice() ? SH_PIO_WRITE_STATUS_1 : SH_PIO_WRITE_STATUS_0);
+	int			cnode, mycnode, nasid;
+	volatile unsigned	long	*ptc0, *ptc1;
+	unsigned long		flags=0, data0, data1;
+	long 		        zzbase, zztime, zztime2;
+
+	/*
+	 * Special case 1 cpu & 1 node. Use local purges.
+	 */
+#ifdef PTCG_WAR
+	sn1_global_tlb_purge(start, end, nbits);
+	return;
+#endif /* PTCG_WAR */
+		
 	data0 = (1UL<<SH_PTC_0_A_SHFT) |
 		(nbits<<SH_PTC_0_PS_SHFT) |
 		((ia64_get_rr(start)>>8)<<SH_PTC_0_RID_SHFT) |
 		(1UL<<SH_PTC_0_START_SHFT);
 
-	ptc0 = (long*)GLOBAL_MMR_ADDR(0, SH_PTC_0);
-	ptc1 = (long*)GLOBAL_MMR_ADDR(0, SH_PTC_1);
+	ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0);
+	ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1);
+
+	mycnode = local_cnodeid();
+
+	/* 
+	 * For now, we dont want to spin uninterruptibly waiting
+	 * for the lock. Makes hangs hard to debug.
+	 */
+	zzbase = smp_processor_id()*16;
+	zz[zzbase+0] += 0x0000ffff00000001UL;
+
+	local_irq_save(flags);
+	zztime = get_itc();     
+	spin_lock(&sn2_global_ptc_lock);
+	zz[zzbase+0] += 0xffff000000000000UL;
+	zztime2 = get_itc();     
+
 	do {
-		*(piows+1) = -1;	/* use alias address to clear bits*/
-		next = start;
-		do {
-			for (cnode = 0; cnode < numnodes; cnode++) {
+		data1 = start | (1UL<<SH_PTC_1_START_SHFT);
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			if (is_headless_node(cnode))
+				continue;
+			if (cnode == mycnode) {
+				asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory");
+			} else {
 				nasid = cnodeid_to_nasid(cnode);
 				ptc0 = CHANGE_NASID(nasid, ptc0);
 				ptc1 = CHANGE_NASID(nasid, ptc1);
-				data1 = next | (1UL<<SH_PTC_1_START_SHFT);
-				*ptc0 = data0;
-				*ptc1 = data1;
+				pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1);
 			}
-			next += (1UL << nbits);
-		} while (next < end);
+		}
 
-		while ((ws = *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK)
-			;
+		if (wait_piowc() & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK) {
+			zz[zzbase+1]++;
+			sn2_ptc_deadlock_recovery(data0, data1);
+		}
 
-	} while (ws & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK);
+		start += (1UL << nbits);
+
+	} while (start < end);
+
+	zz[zzbase+0] -= 0xffffffff00000000UL;   
+	zztime2 = get_itc() - zztime2;    
+	spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+
+	zztime = get_itc() - zztime;    
+
+	zz[zzbase+6] += zztime;                                                                                             
+	if (zztime > zz[zzbase+7])
+	       zz[zzbase+7] = zztime; 
+
+	zz[zzbase+8] += zztime2;                                                                                             
+	if (zztime2 > zz[zzbase+9])
+	       zz[zzbase+9] = zztime2; 
 
-	
+}
+
+/*
+ * sn2_ptc_deadlock_recovery
+ *
+ * Recover from PTC deadlocks conditions. Recovery requires stepping thru each 
+ * TLB flush transaction.  The recovery sequence is somewhat tricky & is
+ * coded in assembly language.
+ */
+void
+sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1)
+{
+	extern void sn2_ptc_deadlock_recovery_core(long*, long, long*, long, long*);
+	int	cnode, mycnode, nasid;
+	long	*ptc0, *ptc1, *piows;
+
+	sn2_ptc_deadlock_count++;
+
+	ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0);
+	ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1);
+	piows = (long*)pda.pio_write_status_addr;
+
+	mycnode = local_cnodeid();
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if (is_headless_node(cnode) || cnode == mycnode)
+			continue;
+		nasid = cnodeid_to_nasid(cnode);
+		ptc0 = CHANGE_NASID(nasid, ptc0);
+		ptc1 = CHANGE_NASID(nasid, ptc1);
+		sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows);
+	}
 }
 
 /**
@@ -121,28 +512,32 @@
 sn_send_IPI_phys(long physid, int vector, int delivery_mode)
 {
 	long		nasid, slice;
-	long		*p, val;
+	long		val;
+	volatile long	*p;
+
+#if defined(BUS_INT_WAR) && defined(CONFIG_SHUB_1_0_SPECIFIC)
+	if (vector != ap_wakeup_vector && delivery_mode == IA64_IPI_DM_INT) {
+		return;
+	}
+#endif
 
 	nasid = cpu_physical_id_to_nasid(physid);
         slice = cpu_physical_id_to_slice(physid);
 
-	p = (long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT);
+	p = (long*)GLOBAL_MMR_PHYS_ADDR(nasid, SH_IPI_INT);
 	val =   (1UL<<SH_IPI_INT_SEND_SHFT) | 
 		(physid<<SH_IPI_INT_PID_SHFT) | 
 	        ((long)delivery_mode<<SH_IPI_INT_TYPE_SHFT) | 
 		((long)vector<<SH_IPI_INT_IDX_SHFT) |
 		(0x000feeUL<<SH_IPI_INT_BASE_SHFT);
 
-#if defined(BRINGUP)
-	{
-	static int count=0;
-	if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx, val 0x%lx\n",
-		smp_processor_id(), vector, nasid, slice, (long)p, val);
-	}
-#endif
 	mb();
-	*p = val;
-	
+	pio_phys_write_mmr(p, val);
+
+#ifndef CONFIG_SHUB_1_0_SPECIFIC
+	/* doesnt work on shub 1.0 */
+	wait_piowc();
+#endif
 }
 
 /**
@@ -172,13 +567,131 @@
 }
 
 
-/**
- * init_sn2_smp_config - initialize SN2 smp configuration
- *
- * currently a NOP.
- */
-void __init
-init_sn2_smp_config(void)
+
+/* ----------------------------------------------------------------------------------------------- */
+
+#include <linux/proc_fs.h>
+
+
+static struct proc_dir_entry *ptcg_stats;
+
+static int
+ptcg_read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data)
+{
+	long cpu, *p, cnt;
+	int len = 0;
+
+	p = (long*)LOCAL_MMR_ADDR(SH_DIAG_MSG_DATA7L);
+	len += sprintf(buffer + len, "PTCG Stats (option 0x%lx)\n", use_tlb_hack);
+
+	len += sprintf(buffer + len, "%-14s", "CPU");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", cpu);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "flushes");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+0]&0xffffffff);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "deadlocks");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+1]);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "aver-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		cnt = zz[cpu*16+0]&0xffffffff;
+		len += sprintf(buffer + len, "%10ld", cnt ? zz[cpu*16+6]/(cnt)/cpu_data(cpu)->cyc_per_usec : 0);
+	}
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "max-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+7]/cpu_data(cpu)->cyc_per_usec);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "iaver-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		cnt = zz[cpu*16+0]&0xffffffff;
+		len += sprintf(buffer + len, "%10ld", cnt ? zz[cpu*16+8]/(cnt)/cpu_data(cpu)->cyc_per_usec : 0);
+	}
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "imax-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+9]/cpu_data(cpu)->cyc_per_usec);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "long-piowc");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+9]);
+	len += sprintf(buffer + len, "\n");
+
+        len += sprintf(buffer + len, "%-14s", "ipi-rp-error");
+        for (cpu=0; cpu<smp_num_cpus; cpu++) {
+                p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE0);
+                len += sprintf(buffer + len, "%10ld", *p);
+        }
+	len += sprintf(buffer + len, "\n");
+
+        len += sprintf(buffer + len, "%-14s", "lb-cb-error");
+        for (cpu=0; cpu<smp_num_cpus; cpu++) {
+                p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE1);
+                len += sprintf(buffer + len, "%10ld", *p);
+        }
+        len += sprintf(buffer + len, "\n");
+
+
+	if (len <= off+count) *eof = 1;
+	*start = buffer + off;
+	len   -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+
+static int
+ptcg_write_proc (struct file *file, const char *userbuf, unsigned long count, void *data)
 {
+	extern long atoi(char *);
+	char		buf[80];
+	long		val;
+	long		cpu;
+	long		*p;
+
+	if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
+		return -EFAULT;
+
+	val = atoi(buf);
+	if (val&4) val |= 1;
+	use_tlb_hack = val;
+
+	memset((void*)zz, 0, sizeof(zz));
+
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE0);
+		*p = 0;
+		p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE1);
+		*p = 0;
+	}
+	return count;
+}
+
+	
 
+static int
+sn2_ptcg_stats_init(void)
+{
+	if ((ptcg_stats = create_proc_entry("ptcg_stats", 0644, NULL)) == NULL) {
+		printk("unable to create proc entry for ptcg_stats");
+		return -1;
+	}
+	ptcg_stats->read_proc = ptcg_read_proc;
+	ptcg_stats->write_proc = ptcg_write_proc;
+	return 0;
 }
+
+#include <linux/module.h>
+module_init(sn2_ptcg_stats_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/sn_proc_fs.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <asm/sn/sn_sal.h>
+
+
+static int partition_id_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+
+	return sprintf(page, "%d\n", sn_local_partid());
+}
+
+struct proc_dir_entry * sgi_proc_dir = NULL;
+
+void
+register_sn_partition_id(void) {
+	struct proc_dir_entry *entry;
+
+	if (!sgi_proc_dir) {
+		sgi_proc_dir = proc_mkdir("sgi_sn", 0);
+	}
+	entry = create_proc_entry("partition_id", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = partition_id_read_proc;
+		entry->write_proc = NULL;
+	}
+}
+
+static int
+system_serial_number_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+	return sprintf(page, "%s\n", sn_system_serial_number());
+}
+
+static int
+licenseID_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+	return sprintf(page, "0x%lx\n",sn_partition_serial_number_val());
+}
+
+void
+register_sn_serial_numbers(void) {
+	struct proc_dir_entry *entry;
+
+	if (!sgi_proc_dir) {
+		sgi_proc_dir = proc_mkdir("sgi_sn", 0);
+	}
+	entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = system_serial_number_read_proc;
+		entry->write_proc = NULL;
+	}
+	entry = create_proc_entry("licenseID", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = licenseID_read_proc;
+		entry->write_proc = NULL;
+	}
+}
+
+#endif /* CONFIG_PROC_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn_asm.S linux-2.4.21-rc3/arch/ia64/sn/kernel/sn_asm.S
--- linux-2.4.20/arch/ia64/sn/kernel/sn_asm.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn_asm.S	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,33 @@
-
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
 #include <linux/config.h>
@@ -8,9 +35,10 @@
 
 // Testing only.
 // Routine will cause MCAs
-//   zzzmsa(n)
+//   zzzmca(n)
 //      n=0 MCA via duplicate TLB dropin
-//      n=0 MCA via read of garbage address
+//      n=1 MCA via read of garbage address
+//      n=2 MCA via lfetch read of garbage address
 //
 
 #define ITIR(key, ps)           ((key<<8) | (ps<<2))
@@ -45,20 +73,30 @@
 
                         rsm      0x2000;;
                         srlz.d;
-                        mov      r11      = 1
+                        mov      r11      = 5
                         mov      r3       = ITIR(0,TLB_PAGESIZE);;
                         mov      cr.itir  = r3
                         mov      r10      = 0;;
                         itr.d    dtr[r11] = r10;;
-                        mov      r11      = 2
+                        mov      r11      = 6
 
                         itr.d    dtr[r11] = r10;;
                         br      9f
 
-1:                      movl    r8=0xfe00000048;;
-                        ld8     r9=[r8];;
+1:
+			cmp.eq	p6,p7=1,r32
+#ifdef CONFIG_IA64_SGI_SN1
+                        movl    r8=0xe00000fe00000048;;
+#else
+                        movl    r8=0xe0007fb000000048;;
+#endif
+                 (p6)   ld8     r9=[r8]
+                 (p7)   lfetch.fault.nt2  [r8]
+			;;
                         mf
+			;;
                         mf.a
+			;;
                         srlz.d
 
 9:                      mov     ar.pfs=loc4
@@ -66,83 +104,4 @@
 
                         .endp   zzzmca
 
-                        .global zzzspec
-                        .proc   zzzspec
-zzzspec:
-			mov	r8=r32
-			movl	r9=0xe000000000000000
-			movl	r10=0x4000;;
-			ld8.s	r16=[r8];;
-			ld8.s	r17=[r9];;
-			add	r8=r8,r10;;
-			ld8.s	r18=[r8];;
-			add	r8=r8,r10;;
-			ld8.s	r19=[r8];;
-			add	r8=r8,r10;;
-			ld8.s	r20=[r8];;
-			mov	r8=r0
-			tnat.nz	p6,p0=r16
-			tnat.nz	p7,p0=r17
-			tnat.nz	p8,p0=r18
-			tnat.nz	p9,p0=r19
-			tnat.nz	p10,p0=r20;;
-		(p6)	dep	r8=-1,r8,0,1;;
-		(p7)	dep	r8=-1,r8,1,1;;
-		(p8)	dep	r8=-1,r8,2,1;;
-		(p9)	dep	r8=-1,r8,3,1;;
-		(p10)	dep	r8=-1,r8,4,1;;
-                        br.ret.sptk     rp
-                        .endp   zzzspec
-
-                        .global zzzspec2
-                        .proc   zzzspec2
-zzzspec2:
-			cmp.eq	p6,p7=r2,r2
-			movl	r16=0xc0000a0001000020
-			;;
-			mf
-			;;
-			ld8	r9=[r16]
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			ld8	r9=[r16];;
-			cmp.ne	p6,p7=r9,r16
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			ld8	r9=[r33];;
-			cmp.ne	p6,p7=r9,r33
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			tpa	r23=r32
-			add	r20=512,r33
-			add	r21=1024,r33;;
-			ld8	r9=[r20]
-			ld8	r10=[r21];;
-			nop.i	0
-			{ .mib
-			nop.m 0
-			cmp.ne	p6,p7=r10,r33
-		(p6)	br.spnt	1f
-			}
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-			br.ret.sptk     rp
-
-                        .endp   zzzspec
-
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sn_ksyms.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sn_ksyms.c	2003-05-22 22:06:52.000000000 +0000
@@ -44,6 +44,7 @@
 EXPORT_SYMBOL(hwgraph_edge_add);
 EXPORT_SYMBOL(pciio_info_master_get);
 EXPORT_SYMBOL(pciio_info_get);
+
 #ifdef CONFIG_IA64_SGI_SN_DEBUG
 EXPORT_SYMBOL(__pa_debug);
 EXPORT_SYMBOL(__va_debug);
@@ -52,5 +53,30 @@
 /* Support IPIs for loaded modules. */
 EXPORT_SYMBOL(sn_send_IPI_phys);
 
+/* symbols referenced by partitioning modules */
+#include <asm/sn/bte_copy.h>
+EXPORT_SYMBOL(bte_unaligned_copy);
+#include <asm/sal.h>
+EXPORT_SYMBOL(ia64_sal);
+
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/sn_sal.h>
+EXPORT_SYMBOL(sal_lock);
+EXPORT_SYMBOL(sn_partid);
+EXPORT_SYMBOL(sn_local_partid);
+EXPORT_SYMBOL(sn_system_serial_number_string);
+EXPORT_SYMBOL(sn_partition_serial_number);
+#endif
+
+/* added by tduffy 04.08.01 to fix depmod issues */
 #include <linux/mmzone.h>
 
+#ifdef BUS_INT_WAR
+extern void sn_add_polled_interrupt(int, int);
+extern void sn_delete_polled_interrupt(int);
+EXPORT_SYMBOL(sn_add_polled_interrupt);
+EXPORT_SYMBOL(sn_delete_polled_interrupt);
+#endif
+
+extern nasid_t master_nasid;
+EXPORT_SYMBOL(master_nasid);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sv.c linux-2.4.21-rc3/arch/ia64/sn/kernel/sv.c
--- linux-2.4.20/arch/ia64/sn/kernel/sv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/kernel/sv.c	2003-05-22 22:06:47.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.  All rights reserved
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This implemenation of synchronization variables is heavily based on
  * one done by Steve Lord <lord@sgi.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/tools/make_textsym linux-2.4.21-rc3/arch/ia64/sn/tools/make_textsym
--- linux-2.4.20/arch/ia64/sn/tools/make_textsym	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/sn/tools/make_textsym	2003-05-22 22:06:24.000000000 +0000
@@ -44,7 +44,7 @@
 
 [ -f $VMLINUX ] || help
 
-$OBJDUMP -t $LINUX | sort > $TMPSYM
+$OBJDUMP -t $LINUX | egrep -v '__ks' | sort > $TMPSYM
 SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l`
 
 # Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE.
@@ -58,74 +58,74 @@
 # pipe everything thru sort
 echo "TEXTSYM V1.0"
 (cat <<END 
-GLOBAL | ${textprefix}00400000 | CODE | VEC_VHPT_Translation_0000
-GLOBAL | ${textprefix}00400400 | CODE | VEC_ITLB_0400
-GLOBAL | ${textprefix}00400800 | CODE | VEC_DTLB_0800
-GLOBAL | ${textprefix}00400c00 | CODE | VEC_Alt_ITLB_0c00
-GLOBAL | ${textprefix}00401000 | CODE | VEC_Alt_DTLB_1000
-GLOBAL | ${textprefix}00401400 | CODE | VEC_Data_nested_TLB_1400
-GLOBAL | ${textprefix}00401800 | CODE | VEC_Instruction_Key_Miss_1800
-GLOBAL | ${textprefix}00401c00 | CODE | VEC_Data_Key_Miss_1c00
-GLOBAL | ${textprefix}00402000 | CODE | VEC_Dirty-bit_2000
-GLOBAL | ${textprefix}00402400 | CODE | VEC_Instruction_Access-bit_2400
-GLOBAL | ${textprefix}00402800 | CODE | VEC_Data_Access-bit_2800
-GLOBAL | ${textprefix}00402c00 | CODE | VEC_Break_instruction_2c00
-GLOBAL | ${textprefix}00403000 | CODE | VEC_External_Interrupt_3000
-GLOBAL | ${textprefix}00403400 | CODE | VEC_Reserved_3400
-GLOBAL | ${textprefix}00403800 | CODE | VEC_Reserved_3800
-GLOBAL | ${textprefix}00403c00 | CODE | VEC_Reserved_3c00
-GLOBAL | ${textprefix}00404000 | CODE | VEC_Reserved_4000
-GLOBAL | ${textprefix}00404400 | CODE | VEC_Reserved_4400
-GLOBAL | ${textprefix}00404800 | CODE | VEC_Reserved_4800
-GLOBAL | ${textprefix}00404c00 | CODE | VEC_Reserved_4c00
-GLOBAL | ${textprefix}00405000 | CODE | VEC_Page_Not_Present_5000
-GLOBAL | ${textprefix}00405100 | CODE | VEC_Key_Permission_5100
-GLOBAL | ${textprefix}00405200 | CODE | VEC_Instruction_Access_Rights_5200
-GLOBAL | ${textprefix}00405300 | CODE | VEC_Data_Access_Rights_5300
-GLOBAL | ${textprefix}00405400 | CODE | VEC_General_Exception_5400
-GLOBAL | ${textprefix}00405500 | CODE | VEC_Disabled_FP-Register_5500
-GLOBAL | ${textprefix}00405600 | CODE | VEC_Nat_Consumption_5600
-GLOBAL | ${textprefix}00405700 | CODE | VEC_Speculation_5700
-GLOBAL | ${textprefix}00405800 | CODE | VEC_Reserved_5800
-GLOBAL | ${textprefix}00405900 | CODE | VEC_Debug_5900
-GLOBAL | ${textprefix}00405a00 | CODE | VEC_Unaligned_Reference_5a00
-GLOBAL | ${textprefix}00405b00 | CODE | VEC_Unsupported_Data_Reference_5b00
-GLOBAL | ${textprefix}00405c00 | CODE | VEC_Floating-Point_Fault_5c00
-GLOBAL | ${textprefix}00405d00 | CODE | VEC_Floating_Point_Trap_5d00
-GLOBAL | ${textprefix}00405e00 | CODE | VEC_Lower_Privilege_Tranfer_Trap_5e00
-GLOBAL | ${textprefix}00405f00 | CODE | VEC_Taken_Branch_Trap_5f00
-GLOBAL | ${textprefix}00406000 | CODE | VEC_Single_Step_Trap_6000
-GLOBAL | ${textprefix}00406100 | CODE | VEC_Reserved_6100
-GLOBAL | ${textprefix}00406200 | CODE | VEC_Reserved_6200
-GLOBAL | ${textprefix}00406300 | CODE | VEC_Reserved_6300
-GLOBAL | ${textprefix}00406400 | CODE | VEC_Reserved_6400
-GLOBAL | ${textprefix}00406500 | CODE | VEC_Reserved_6500
-GLOBAL | ${textprefix}00406600 | CODE | VEC_Reserved_6600
-GLOBAL | ${textprefix}00406700 | CODE | VEC_Reserved_6700
-GLOBAL | ${textprefix}00406800 | CODE | VEC_Reserved_6800
-GLOBAL | ${textprefix}00406900 | CODE | VEC_IA-32_Exeception_6900
-GLOBAL | ${textprefix}00406a00 | CODE | VEC_IA-32_Intercept_6a00
-GLOBAL | ${textprefix}00406b00 | CODE | VEC_IA-32_Interrupt_6b00
-GLOBAL | ${textprefix}00406c00 | CODE | VEC_Reserved_6c00
-GLOBAL | ${textprefix}00406d00 | CODE | VEC_Reserved_6d00
-GLOBAL | ${textprefix}00406e00 | CODE | VEC_Reserved_6e00
-GLOBAL | ${textprefix}00406f00 | CODE | VEC_Reserved_6f00
-GLOBAL | ${textprefix}00407000 | CODE | VEC_Reserved_7000
-GLOBAL | ${textprefix}00407100 | CODE | VEC_Reserved_7100
-GLOBAL | ${textprefix}00407200 | CODE | VEC_Reserved_7200
-GLOBAL | ${textprefix}00407300 | CODE | VEC_Reserved_7300
-GLOBAL | ${textprefix}00407400 | CODE | VEC_Reserved_7400
-GLOBAL | ${textprefix}00407500 | CODE | VEC_Reserved_7500
-GLOBAL | ${textprefix}00407600 | CODE | VEC_Reserved_7600
-GLOBAL | ${textprefix}00407700 | CODE | VEC_Reserved_7700
-GLOBAL | ${textprefix}00407800 | CODE | VEC_Reserved_7800
-GLOBAL | ${textprefix}00407900 | CODE | VEC_Reserved_7900
-GLOBAL | ${textprefix}00407a00 | CODE | VEC_Reserved_7a00
-GLOBAL | ${textprefix}00407b00 | CODE | VEC_Reserved_7b00
-GLOBAL | ${textprefix}00407c00 | CODE | VEC_Reserved_7c00
-GLOBAL | ${textprefix}00407d00 | CODE | VEC_Reserved_7d00
-GLOBAL | ${textprefix}00407e00 | CODE | VEC_Reserved_7e00
-GLOBAL | ${textprefix}00407f00 | CODE | VEC_Reserved_7f00
+GLOBAL | ${textprefix}00000000 | CODE | VEC_VHPT_Translation_0000
+GLOBAL | ${textprefix}00000400 | CODE | VEC_ITLB_0400
+GLOBAL | ${textprefix}00000800 | CODE | VEC_DTLB_0800
+GLOBAL | ${textprefix}00000c00 | CODE | VEC_Alt_ITLB_0c00
+GLOBAL | ${textprefix}00001000 | CODE | VEC_Alt_DTLB_1000
+GLOBAL | ${textprefix}00001400 | CODE | VEC_Data_nested_TLB_1400
+GLOBAL | ${textprefix}00001800 | CODE | VEC_Instruction_Key_Miss_1800
+GLOBAL | ${textprefix}00001c00 | CODE | VEC_Data_Key_Miss_1c00
+GLOBAL | ${textprefix}00002000 | CODE | VEC_Dirty-bit_2000
+GLOBAL | ${textprefix}00002400 | CODE | VEC_Instruction_Access-bit_2400
+GLOBAL | ${textprefix}00002800 | CODE | VEC_Data_Access-bit_2800
+GLOBAL | ${textprefix}00002c00 | CODE | VEC_Break_instruction_2c00
+GLOBAL | ${textprefix}00003000 | CODE | VEC_External_Interrupt_3000
+GLOBAL | ${textprefix}00003400 | CODE | VEC_Reserved_3400
+GLOBAL | ${textprefix}00003800 | CODE | VEC_Reserved_3800
+GLOBAL | ${textprefix}00003c00 | CODE | VEC_Reserved_3c00
+GLOBAL | ${textprefix}00004000 | CODE | VEC_Reserved_4000
+GLOBAL | ${textprefix}00004400 | CODE | VEC_Reserved_4400
+GLOBAL | ${textprefix}00004800 | CODE | VEC_Reserved_4800
+GLOBAL | ${textprefix}00004c00 | CODE | VEC_Reserved_4c00
+GLOBAL | ${textprefix}00005000 | CODE | VEC_Page_Not_Present_5000
+GLOBAL | ${textprefix}00005100 | CODE | VEC_Key_Permission_5100
+GLOBAL | ${textprefix}00005200 | CODE | VEC_Instruction_Access_Rights_5200
+GLOBAL | ${textprefix}00005300 | CODE | VEC_Data_Access_Rights_5300
+GLOBAL | ${textprefix}00005400 | CODE | VEC_General_Exception_5400
+GLOBAL | ${textprefix}00005500 | CODE | VEC_Disabled_FP-Register_5500
+GLOBAL | ${textprefix}00005600 | CODE | VEC_Nat_Consumption_5600
+GLOBAL | ${textprefix}00005700 | CODE | VEC_Speculation_5700
+GLOBAL | ${textprefix}00005800 | CODE | VEC_Reserved_5800
+GLOBAL | ${textprefix}00005900 | CODE | VEC_Debug_5900
+GLOBAL | ${textprefix}00005a00 | CODE | VEC_Unaligned_Reference_5a00
+GLOBAL | ${textprefix}00005b00 | CODE | VEC_Unsupported_Data_Reference_5b00
+GLOBAL | ${textprefix}00005c00 | CODE | VEC_Floating-Point_Fault_5c00
+GLOBAL | ${textprefix}00005d00 | CODE | VEC_Floating_Point_Trap_5d00
+GLOBAL | ${textprefix}00005e00 | CODE | VEC_Lower_Privilege_Tranfer_Trap_5e00
+GLOBAL | ${textprefix}00005f00 | CODE | VEC_Taken_Branch_Trap_5f00
+GLOBAL | ${textprefix}00006000 | CODE | VEC_Single_Step_Trap_6000
+GLOBAL | ${textprefix}00006100 | CODE | VEC_Reserved_6100
+GLOBAL | ${textprefix}00006200 | CODE | VEC_Reserved_6200
+GLOBAL | ${textprefix}00006300 | CODE | VEC_Reserved_6300
+GLOBAL | ${textprefix}00006400 | CODE | VEC_Reserved_6400
+GLOBAL | ${textprefix}00006500 | CODE | VEC_Reserved_6500
+GLOBAL | ${textprefix}00006600 | CODE | VEC_Reserved_6600
+GLOBAL | ${textprefix}00006700 | CODE | VEC_Reserved_6700
+GLOBAL | ${textprefix}00006800 | CODE | VEC_Reserved_6800
+GLOBAL | ${textprefix}00006900 | CODE | VEC_IA-32_Exeception_6900
+GLOBAL | ${textprefix}00006a00 | CODE | VEC_IA-32_Intercept_6a00
+GLOBAL | ${textprefix}00006b00 | CODE | VEC_IA-32_Interrupt_6b00
+GLOBAL | ${textprefix}00006c00 | CODE | VEC_Reserved_6c00
+GLOBAL | ${textprefix}00006d00 | CODE | VEC_Reserved_6d00
+GLOBAL | ${textprefix}00006e00 | CODE | VEC_Reserved_6e00
+GLOBAL | ${textprefix}00006f00 | CODE | VEC_Reserved_6f00
+GLOBAL | ${textprefix}00007000 | CODE | VEC_Reserved_7000
+GLOBAL | ${textprefix}00007100 | CODE | VEC_Reserved_7100
+GLOBAL | ${textprefix}00007200 | CODE | VEC_Reserved_7200
+GLOBAL | ${textprefix}00007300 | CODE | VEC_Reserved_7300
+GLOBAL | ${textprefix}00007400 | CODE | VEC_Reserved_7400
+GLOBAL | ${textprefix}00007500 | CODE | VEC_Reserved_7500
+GLOBAL | ${textprefix}00007600 | CODE | VEC_Reserved_7600
+GLOBAL | ${textprefix}00007700 | CODE | VEC_Reserved_7700
+GLOBAL | ${textprefix}00007800 | CODE | VEC_Reserved_7800
+GLOBAL | ${textprefix}00007900 | CODE | VEC_Reserved_7900
+GLOBAL | ${textprefix}00007a00 | CODE | VEC_Reserved_7a00
+GLOBAL | ${textprefix}00007b00 | CODE | VEC_Reserved_7b00
+GLOBAL | ${textprefix}00007c00 | CODE | VEC_Reserved_7c00
+GLOBAL | ${textprefix}00007d00 | CODE | VEC_Reserved_7d00
+GLOBAL | ${textprefix}00007e00 | CODE | VEC_Reserved_7e00
+GLOBAL | ${textprefix}00007f00 | CODE | VEC_Reserved_7f00
 END
 
 
@@ -157,10 +157,10 @@
 	print $0
 	if (sn1 != 0) {
 		/* 32 bits of sn1 physical addrs, */
-		print substr($0,1,9) substr($0,18,18) "Phy_" substr($0,36)
+		print substr($0,1,9) "04" substr($0,20,16) "Phy_" substr($0,36)
 	} else {
 		/* 38 bits of sn2 physical addrs, need addr space bits */
-		print substr($0,1,9) "30" substr($0,18,18) "Phy_" substr($0,36)
+		print substr($0,1,9) "3004" substr($0,20,16) "Phy_" substr($0,36)
 	}
 
 } ' | sort -k3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/vmlinux.lds.S linux-2.4.21-rc3/arch/ia64/vmlinux.lds.S
--- linux-2.4.20/arch/ia64/vmlinux.lds.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/ia64/vmlinux.lds.S	2003-05-22 22:06:40.000000000 +0000
@@ -13,6 +13,8 @@
   /DISCARD/ : {
 	*(.text.exit)
 	*(.data.exit)
+	*(*.text.exit)
+	*(*.data.exit)
 	*(.exitcall.exit)
 	*(.IA_64.unwind.text.exit)
 	*(.IA_64.unwind_info.text.exit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/amiga/config.c linux-2.4.21-rc3/arch/m68k/amiga/config.c
--- linux-2.4.20/arch/m68k/amiga/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/amiga/config.c	2003-05-22 22:06:25.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>
+#include <linux/delay.h>
 #ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
 #endif
@@ -95,6 +96,7 @@
 static void a2000_gettod (int *, int *, int *, int *, int *, int *);
 static int amiga_hwclk (int, struct rtc_time *);
 static int amiga_set_clock_mmss (unsigned long);
+static unsigned int amiga_get_ss (void);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
@@ -428,6 +430,7 @@
 
   mach_hwclk           = amiga_hwclk;
   mach_set_clock_mmss  = amiga_set_clock_mmss;
+  mach_get_ss          = amiga_get_ss; 
 #ifdef CONFIG_AMIGA_FLOPPY
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
@@ -574,135 +577,145 @@
 static void a3000_gettod (int *yearp, int *monp, int *dayp,
 			  int *hourp, int *minp, int *secp)
 {
-	volatile struct tod3000 *tod = TOD_3000;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
-	tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+	*secp  = tod_3000.second1 * 10 + tod_3000.second2;
+	*minp  = tod_3000.minute1 * 10 + tod_3000.minute2;
+	*hourp = tod_3000.hour1   * 10 + tod_3000.hour2;
+	*dayp  = tod_3000.day1    * 10 + tod_3000.day2;
+	*monp  = tod_3000.month1  * 10 + tod_3000.month2;
+	*yearp = tod_3000.year1   * 10 + tod_3000.year2;
 
-	*secp  = tod->second1 * 10 + tod->second2;
-	*minp  = tod->minute1 * 10 + tod->minute2;
-	*hourp = tod->hour1   * 10 + tod->hour2;
-	*dayp  = tod->day1    * 10 + tod->day2;
-	*monp  = tod->month1  * 10 + tod->month2;
-	*yearp = tod->year1   * 10 + tod->year2;
-
-	tod->cntrl1 = TOD3000_CNTRL1_FREE;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 }
 
 static void a2000_gettod (int *yearp, int *monp, int *dayp,
 			  int *hourp, int *minp, int *secp)
 {
-	volatile struct tod2000 *tod = TOD_2000;
+	int cnt = 5;
 
-	tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+	tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	
+	while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+	{
+	        tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	        udelay(70);
+	        tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	}
 
-	while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-		;
+	if (!cnt)
+		printk(KERN_INFO "gettod: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
-	*secp  = tod->second1     * 10 + tod->second2;
-	*minp  = tod->minute1     * 10 + tod->minute2;
-	*hourp = (tod->hour1 & 3) * 10 + tod->hour2;
-	*dayp  = tod->day1        * 10 + tod->day2;
-	*monp  = tod->month1      * 10 + tod->month2;
-	*yearp = tod->year1       * 10 + tod->year2;
+	*secp  = tod_2000.second1     * 10 + tod_2000.second2;
+	*minp  = tod_2000.minute1     * 10 + tod_2000.minute2;
+	*hourp = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
+	*dayp  = tod_2000.day1        * 10 + tod_2000.day2;
+	*monp  = tod_2000.month1      * 10 + tod_2000.month2;
+	*yearp = tod_2000.year1       * 10 + tod_2000.year2;
 
-	if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-		if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
+	if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+		if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
 			*hourp = 0;
-		else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
+		else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
 			*hourp += 12;
 	}
 
-	tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 }
 
 static int amiga_hwclk(int op, struct rtc_time *t)
 {
 	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
 		if (!op) { /* read */
-			t->tm_sec  = tod->second1 * 10 + tod->second2;
-			t->tm_min  = tod->minute1 * 10 + tod->minute2;
-			t->tm_hour = tod->hour1   * 10 + tod->hour2;
-			t->tm_mday = tod->day1    * 10 + tod->day2;
-			t->tm_wday = tod->weekday;
-			t->tm_mon  = tod->month1  * 10 + tod->month2 - 1;
-			t->tm_year = tod->year1   * 10 + tod->year2;
+			t->tm_sec  = tod_3000.second1 * 10 + tod_3000.second2;
+			t->tm_min  = tod_3000.minute1 * 10 + tod_3000.minute2;
+			t->tm_hour = tod_3000.hour1   * 10 + tod_3000.hour2;
+			t->tm_mday = tod_3000.day1    * 10 + tod_3000.day2;
+			t->tm_wday = tod_3000.weekday;
+			t->tm_mon  = tod_3000.month1  * 10 + tod_3000.month2 - 1;
+			t->tm_year = tod_3000.year1   * 10 + tod_3000.year2;
 			if (t->tm_year <= 69)
 				t->tm_year += 100;
 		} else {
-			tod->second1 = t->tm_sec / 10;
-			tod->second2 = t->tm_sec % 10;
-			tod->minute1 = t->tm_min / 10;
-			tod->minute2 = t->tm_min % 10;
-			tod->hour1   = t->tm_hour / 10;
-			tod->hour2   = t->tm_hour % 10;
-			tod->day1    = t->tm_mday / 10;
-			tod->day2    = t->tm_mday % 10;
+			tod_3000.second1 = t->tm_sec / 10;
+			tod_3000.second2 = t->tm_sec % 10;
+			tod_3000.minute1 = t->tm_min / 10;
+			tod_3000.minute2 = t->tm_min % 10;
+			tod_3000.hour1   = t->tm_hour / 10;
+			tod_3000.hour2   = t->tm_hour % 10;
+			tod_3000.day1    = t->tm_mday / 10;
+			tod_3000.day2    = t->tm_mday % 10;
 			if (t->tm_wday != -1)
-				tod->weekday = t->tm_wday;
-			tod->month1  = (t->tm_mon + 1) / 10;
-			tod->month2  = (t->tm_mon + 1) % 10;
+				tod_3000.weekday = t->tm_wday;
+			tod_3000.month1  = (t->tm_mon + 1) / 10;
+			tod_3000.month2  = (t->tm_mon + 1) % 10;
 			if (t->tm_year >= 100)
 				t->tm_year -= 100;
-			tod->year1   = t->tm_year / 10;
-			tod->year2   = t->tm_year % 10;
+			tod_3000.year1   = t->tm_year / 10;
+			tod_3000.year2   = t->tm_year % 10;
 		}
 
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
+		int cnt = 5;
 
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+		{
+			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+			udelay(70);
+			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		}
+
+		if (!cnt)
+			printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
 		if (!op) { /* read */
-			t->tm_sec  = tod->second1     * 10 + tod->second2;
-			t->tm_min  = tod->minute1     * 10 + tod->minute2;
-			t->tm_hour = (tod->hour1 & 3) * 10 + tod->hour2;
-			t->tm_mday = tod->day1        * 10 + tod->day2;
-			t->tm_wday = tod->weekday;
-			t->tm_mon  = tod->month1      * 10 + tod->month2 - 1;
-			t->tm_year = tod->year1       * 10 + tod->year2;
+			t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
+			t->tm_min  = tod_2000.minute1     * 10 + tod_2000.minute2;
+			t->tm_hour = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
+			t->tm_mday = tod_2000.day1        * 10 + tod_2000.day2;
+			t->tm_wday = tod_2000.weekday;
+			t->tm_mon  = tod_2000.month1      * 10 + tod_2000.month2 - 1;
+			t->tm_year = tod_2000.year1       * 10 + tod_2000.year2;
 			if (t->tm_year <= 69)
 				t->tm_year += 100;
 
-			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-				if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
+			if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+				if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
 					t->tm_hour = 0;
-				else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
+				else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
 					t->tm_hour += 12;
 			}
 		} else {
-			tod->second1 = t->tm_sec / 10;
-			tod->second2 = t->tm_sec % 10;
-			tod->minute1 = t->tm_min / 10;
-			tod->minute2 = t->tm_min % 10;
-			if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
-				tod->hour1 = t->tm_hour / 10;
+			tod_2000.second1 = t->tm_sec / 10;
+			tod_2000.second2 = t->tm_sec % 10;
+			tod_2000.minute1 = t->tm_min / 10;
+			tod_2000.minute2 = t->tm_min % 10;
+			if (tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)
+				tod_2000.hour1 = t->tm_hour / 10;
 			else if (t->tm_hour >= 12)
-				tod->hour1 = TOD2000_HOUR1_PM +
+				tod_2000.hour1 = TOD2000_HOUR1_PM +
 					(t->tm_hour - 12) / 10;
 			else
-				tod->hour1 = t->tm_hour / 10;
-			tod->hour2   = t->tm_hour % 10;
-			tod->day1    = t->tm_mday / 10;
-			tod->day2    = t->tm_mday % 10;
+				tod_2000.hour1 = t->tm_hour / 10;
+			tod_2000.hour2   = t->tm_hour % 10;
+			tod_2000.day1    = t->tm_mday / 10;
+			tod_2000.day2    = t->tm_mday % 10;
 			if (t->tm_wday != -1)
-				tod->weekday = t->tm_wday;
-			tod->month1  = (t->tm_mon + 1) / 10;
-			tod->month2  = (t->tm_mon + 1) % 10;
+				tod_2000.weekday = t->tm_wday;
+			tod_2000.month1  = (t->tm_mon + 1) / 10;
+			tod_2000.month2  = (t->tm_mon + 1) % 10;
 			if (t->tm_year >= 100)
 				t->tm_year -= 100;
-			tod->year1   = t->tm_year / 10;
-			tod->year2   = t->tm_year % 10;
+			tod_2000.year1   = t->tm_year / 10;
+			tod_2000.year2   = t->tm_year % 10;
 		}
 
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 	}
 
 	return 0;
@@ -713,35 +726,54 @@
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
 	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		tod_3000.second1 = real_seconds / 10;
+		tod_3000.second2 = real_seconds % 10;
+		tod_3000.minute1 = real_minutes / 10;
+		tod_3000.minute2 = real_minutes % 10;
 		
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
+		int cnt = 5;
 
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
-
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+		{
+			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+			udelay(70);
+			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		}
 
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		if (!cnt)
+			printk(KERN_INFO "set_clock_mmss: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
+
+		tod_2000.second1 = real_seconds / 10;
+		tod_2000.second2 = real_seconds % 10;
+		tod_2000.minute1 = real_minutes / 10;
+		tod_2000.minute2 = real_minutes % 10;
+
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 	}
 
 	return 0;
 }
 
+static unsigned int amiga_get_ss( void )
+{
+	unsigned int s;
+
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
+		s = tod_3000.second1 * 10 + tod_3000.second2;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { 
+		s = tod_2000.second1 * 10 + tod_2000.second2;
+	}
+	return s;
+}
+
 static NORET_TYPE void amiga_reset( void )
     ATTRIB_NORET;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/apollo/config.c linux-2.4.21-rc3/arch/m68k/apollo/config.c
--- linux-2.4.20/arch/m68k/apollo/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/apollo/config.c	2003-05-22 22:06:40.000000000 +0000
@@ -51,7 +51,6 @@
 static void dn_timer_int(int irq,void *, struct pt_regs *);
 static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
 static void dn_get_model(char *model);
-static int dn_cpuctrl=0xff00;
 static const char *apollo_models[] = {
 	"DN3000 (Otter)",
 	"DN3010 (Otter)",
@@ -313,6 +312,8 @@
 }
 
 #ifdef CONFIG_HEARTBEAT
+static int dn_cpuctrl=0xff00;
+
 static void dn_heartbeat(int on) {
 
 	if(on) { 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/apollo/dma.c linux-2.4.21-rc3/arch/m68k/apollo/dma.c
--- linux-2.4.20/arch/m68k/apollo/dma.c	2000-01-28 16:04:58.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/apollo/dma.c	2003-05-22 22:06:39.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/apollodma.h>
+#include <asm/io.h>
 
 /* note only works for 16 Bit 1 page DMA's */
 
@@ -27,7 +28,7 @@
 #if 0
 		printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
 #endif
-		outw(start_map_addr+i, xlat_map_entry);
+		out_be16(xlat_map_entry, start_map_addr+i);
 	}
 
 	next_free_xlat_entry+=2;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/atari/stram.c linux-2.4.21-rc3/arch/m68k/atari/stram.c
--- linux-2.4.20/arch/m68k/atari/stram.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/atari/stram.c	2003-05-22 22:06:51.000000000 +0000
@@ -146,7 +146,7 @@
 
 /* The following two numbers define the maximum fraction of ST-RAM in total
  * memory, below that the kernel would automatically use ST-RAM as swap
- * space. This decision can be overriden with stram_swap= */
+ * space. This decision can be overridden with stram_swap= */
 #define MAX_STRAM_FRACTION_NOM		1
 #define MAX_STRAM_FRACTION_DENOM	3
 
@@ -347,7 +347,7 @@
 		/*
 		 * If the whole ST-RAM is used for swapping, there are no allocatable
 		 * dma pages left. But unfortunately, some shared parts of the kernel
-		 * (particularily the SCSI mid-level) call __get_dma_pages()
+		 * (particularly the SCSI mid-level) call __get_dma_pages()
 		 * unconditionally :-( These calls then fail, and scsi.c even doesn't
 		 * check for NULL return values and just crashes. The quick fix for
 		 * this (instead of doing much clean up work in the SCSI code) is to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/bvme6000/rtc.c linux-2.4.21-rc3/arch/m68k/bvme6000/rtc.c
--- linux-2.4.20/arch/m68k/bvme6000/rtc.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/bvme6000/rtc.c	2003-05-22 22:06:25.000000000 +0000
@@ -179,7 +179,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/config.in linux-2.4.21-rc3/arch/m68k/config.in
--- linux-2.4.20/arch/m68k/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/config.in	2003-05-22 22:06:50.000000000 +0000
@@ -111,7 +111,9 @@
    bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
    bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
 fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_Q40" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APOLLO" = "y" -o \
+     "$CONFIG_ATARI" = "y" -o "$CONFIG_MAC" = "y" -o \
+     "$CONFIG_Q40" = "y" ]; then
    bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
 else
   if [ "$CONFIG_HP300" = "y" ]; then
@@ -502,7 +504,7 @@
      "$CONFIG_SUN3X_ZS" = "y" -o "$CONFIG_SERIAL" = "y" -o \
      "$CONFIG_MVME147_SCC" -o "$CONFIG_SERIAL167" = "y" -o \
      "$CONFIG_MVME162_SCC" -o "$CONFIG_BVME6000_SCC" = "y" -o \
-     "$CONFIG_DN_SERIAL" -o ]; then
+     "$CONFIG_DN_SERIAL" ]; then
    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Support for user serial device modules' CONFIG_USERIAL
@@ -517,9 +519,12 @@
    if [ "$CONFIG_SUN3" = "y" ]; then
       define_bool CONFIG_GEN_RTC y
    else
-      bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+      tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC      
    fi
 fi
+if [ "$CONFIG_GEN_RTC" != "n" ]; then
+   bool '   Extended RTC operation' CONFIG_GEN_RTC_X
+fi
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
    int '  Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/ifpsp060/fskeleton.S linux-2.4.21-rc3/arch/m68k/ifpsp060/fskeleton.S
--- linux-2.4.20/arch/m68k/ifpsp060/fskeleton.S	1996-09-25 07:47:39.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/ifpsp060/fskeleton.S	2003-05-22 22:06:40.000000000 +0000
@@ -302,7 +302,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_FP_CALL_TOP
 _FP_CALL_TOP:
 	.long	_060_real_bsun		- _FP_CALL_TOP
 	.long	_060_real_snan		- _FP_CALL_TOP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/ifpsp060/iskeleton.S linux-2.4.21-rc3/arch/m68k/ifpsp060/iskeleton.S
--- linux-2.4.20/arch/m68k/ifpsp060/iskeleton.S	1999-01-19 18:58:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/ifpsp060/iskeleton.S	2003-05-22 22:06:26.000000000 +0000
@@ -270,7 +270,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_I_CALL_TOP
 _I_CALL_TOP:
 	.long	_060_real_chk		- _I_CALL_TOP
 	.long	_060_real_divbyzero	- _I_CALL_TOP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/entry.S linux-2.4.21-rc3/arch/m68k/kernel/entry.S
--- linux-2.4.20/arch/m68k/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/entry.S	2003-05-22 22:06:25.000000000 +0000
@@ -240,13 +240,10 @@
 2:
 	RESTORE_ALL
 1:
-#if 1
-	bfextu  %sp@(PT_SR){#5,#3},%d0	| Check for nested interrupt.
-#if MAX_NOINT_IPL > 0
-	cmpiw	#MAX_NOINT_IPL,%d0
-#endif
-	jhi	2b
-#endif
+	moveq	#(~ALLOWINT>>8)&0xff,%d0
+	andb	%sp@(PT_SR),%d0
+	jne	2b
+
 	/* check if we need to do software interrupts */
 	tstl	SYMBOL_NAME(irq_stat)	| softirq_pending ?
 	jeq	SYMBOL_NAME(ret_from_exception)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/head.S linux-2.4.21-rc3/arch/m68k/kernel/head.S
--- linux-2.4.20/arch/m68k/kernel/head.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/head.S	2003-05-22 22:06:45.000000000 +0000
@@ -130,7 +130,7 @@
  *
  * mmu_engage
  * ----------
- *	Thanks to a small helping routine enabling the mmu got quiet simple
+ *	Thanks to a small helping routine enabling the mmu got quite simple
  * and there is only one way left. mmu_engage makes a complete a new mapping
  * that only includes the absolute necessary to be able to jump to the final
  * postion and to restore the original mapping.
@@ -190,7 +190,7 @@
  *
  * options
  * -------
- *	There are many options availble in a build of this file.  I've
+ *	There are many options available in a build of this file.  I've
  * taken the time to describe them here to save you the time of searching
  * for them and trying to understand what they mean.
  *
@@ -1202,7 +1202,7 @@
  *
  * Map the kernel (that's already done),
  * Map the I/O (on most machines that's the
- * 0x5000.0000 ... 0x5200.0000 range,
+ * 0x5000.0000 ... 0x5300.0000 range,
  * Map the video frame buffer using as few pages
  * as absolutely (this requirement mostly stems from
  * the fact that when the frame buffer is at
@@ -1246,10 +1246,11 @@
 	andl	L(mac_videobase),%d0
 
 	mmu_map		#VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
-	mmu_map_eq	#0x40800000,#0x02000000,%d3	/* rom ? */
-	mmu_map_eq	#0x50000000,#0x02000000,%d3
-	mmu_map_eq	#0x60000000,#0x00400000,%d3
-	mmu_map_eq	#0x9c000000,#0x00400000,%d3
+	/* The ROM starts at 4000 0000		    	*/
+	mmu_map_eq	#0x40000000,#0x02000000,%d3
+	/* IO devices                               	*/
+	mmu_map_eq	#0x50000000,#0x03000000,%d3
+	/* NuBus slot space				*/
 	mmu_map_tt	#1,#0xf8000000,#0x08000000,%d3
 
 	jbra	L(mmu_init_done)
@@ -1461,6 +1462,9 @@
 	andl	L(mac_videobase),%d0
 	addl	#VIDEOMEMBASE,%d0
 	movel	%d0,L(mac_videobase)
+#ifdef MAC_SERIAL_DEBUG
+	orl	#0x50000000,L(mac_sccbase)
+#endif		
 1:
 #endif
 
@@ -3048,10 +3052,6 @@
 #ifdef CONFIG_MAC
 	is_not_mac(5f)
 
-#ifdef CONSOLE
-	console_putc	%d0
-#endif /* CONSOLE */
-
 #ifdef MAC_SERIAL_DEBUG
 
 #ifdef MAC_USE_SCC_A
@@ -3446,6 +3446,10 @@
 	putn	%pc@(L(cputype))
 	putc	'\n'
 
+#ifdef MAC_SERIAL_DEBUG
+	putn	%pc@(L(mac_sccbase))
+	putc	'\n'
+#endif	
 #  if defined(MMU_PRINT)
 	jbsr	mmu_print_machine_cpu_types
 #  endif /* MMU_PRINT */
@@ -3622,7 +3626,7 @@
 	movel	%a0@(Lconsole_struct_num_columns),%d1
 	cmpl	%d1,%d0
 	jcs	1f
-	putc	'\n'	/* recursion is OK! */
+	console_putc	#'\n'	/* recursion is OK! */
 1:
 	movel	%a0@(Lconsole_struct_cur_row),%d1
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/m68k_ksyms.c linux-2.4.21-rc3/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.4.20/arch/m68k/kernel/m68k_ksyms.c	2001-01-04 21:00:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/m68k_ksyms.c	2003-05-22 22:06:51.000000000 +0000
@@ -18,6 +18,7 @@
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
+#include <asm/rtc.h>
 
 asmlinkage long long __ashldi3 (long long, int);
 asmlinkage long long __ashrdi3 (long long, int);
@@ -26,7 +27,7 @@
 extern char m68k_debug_device[];
 
 extern void dump_thread(struct pt_regs *, struct user *);
-extern int dump_fpu(elf_fpregset_t *);
+extern int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu);
 
 /* platform dependent support */
 
@@ -49,6 +50,10 @@
 EXPORT_SYMBOL(kernel_set_cachemode);
 #endif /* !CONFIG_SUN3 */
 EXPORT_SYMBOL(m68k_debug_device);
+EXPORT_SYMBOL(mach_hwclk);
+EXPORT_SYMBOL(mach_get_ss);
+EXPORT_SYMBOL(mach_get_rtc_pll);
+EXPORT_SYMBOL(mach_set_rtc_pll);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(strnlen);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/process.c linux-2.4.21-rc3/arch/m68k/kernel/process.c
--- linux-2.4.20/arch/m68k/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/process.c	2003-05-22 22:06:47.000000000 +0000
@@ -124,7 +124,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	int pid;
 	mm_segment_t fs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/setup.c linux-2.4.21-rc3/arch/m68k/kernel/setup.c
--- linux-2.4.20/arch/m68k/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/setup.c	2003-05-22 22:06:52.000000000 +0000
@@ -90,6 +90,9 @@
 void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
 int (*mach_hwclk) (int, struct rtc_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
+unsigned int (*mach_get_ss)(void) = NULL;
+int (*mach_get_rtc_pll)(struct rtc_pll_info *) = NULL;
+int (*mach_set_rtc_pll)(struct rtc_pll_info *) = NULL;
 void (*mach_reset)( void );
 void (*mach_halt)( void ) = NULL;
 void (*mach_power_off)( void ) = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/signal.c linux-2.4.21-rc3/arch/m68k/kernel/signal.c
--- linux-2.4.20/arch/m68k/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/signal.c	2003-05-22 22:06:27.000000000 +0000
@@ -16,7 +16,7 @@
  * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
  *
  * mathemu support by Roman Zippel
- *  (Note: fpstate in the signal context is completly ignored for the emulator
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
  *         and the internal floating point format is put on stack)
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/time.c linux-2.4.21-rc3/arch/m68k/kernel/time.c
--- linux-2.4.20/arch/m68k/kernel/time.c	2001-01-04 21:00:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/time.c	2003-05-22 22:06:38.000000000 +0000
@@ -55,28 +55,11 @@
  */
 static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
 {
-	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
-
 	do_timer(regs);
 
 	if (!user_mode(regs))
 		do_profile(regs->pc);
 
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
 #ifdef CONFIG_HEARTBEAT
 	/* use power LED as a heartbeat instead -- much more useful
 	   for debugging -- based on the version for PReP by Cort */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/traps.c linux-2.4.21-rc3/arch/m68k/kernel/traps.c
--- linux-2.4.20/arch/m68k/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/kernel/traps.c	2003-05-22 22:06:47.000000000 +0000
@@ -302,7 +302,7 @@
 	return res;
 }
 
-/* after an exception in a writeback the stack frame coresponding
+/* after an exception in a writeback the stack frame corresponding
  * to that exception is discarded, set a few bits in the old frame 
  * to simulate what it should look like
  */
@@ -332,7 +332,7 @@
 			fp->un.fmt7.wb2s = 0;
 	}
 
-	/* do the 2nd wb only if the first one was succesful (except for a kernel wb) */
+	/* do the 2nd wb only if the first one was successful (except for a kernel wb) */
 	if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
 		res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
 				       fp->un.fmt7.wb3d);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/baboon.c linux-2.4.21-rc3/arch/m68k/mac/baboon.c
--- linux-2.4.20/arch/m68k/mac/baboon.c	2000-12-04 01:48:19.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mac/baboon.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Baboon Custom IC Managment
+ * Baboon Custom IC Management
  *
  * The Baboon custom IC controls the IDE, PCMCIA and media bay on the
  * PowerBook 190. It multiplexes multiple interrupt sources onto the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/config.c linux-2.4.21-rc3/arch/m68k/mac/config.c
--- linux-2.4.20/arch/m68k/mac/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mac/config.c	2003-05-22 22:06:42.000000000 +0000
@@ -104,7 +104,7 @@
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
 {
-	printk("Resetting ...\n");
+	printk(KERN_INFO "Resetting ...\n");
 	mac_reset();
 }
 
@@ -205,7 +205,7 @@
 void __init config_mac(void)
 {
 	if (!MACH_IS_MAC) {
-	  printk("ERROR: no Mac, but config_mac() called!! \n");
+	  printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
 	}
 
 #ifdef CONFIG_VT
@@ -370,13 +370,14 @@
 	 */	 
 	 
 	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
+	{	MAC_MODEL_Q605_ACC, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
 	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
  	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/*	The Q700 does have a NS Sonic */
-	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 
@@ -389,8 +390,8 @@
 	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	/* These have the comm slot, and therefore the possibility of SONIC ethernet */
+	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -402,7 +403,7 @@
 	/* The C610 may or may not have SONIC.  We probe to make sure */
 	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 
 	/*
 	 * The PowerBooks all the same "Combo" custom IC for SCSI and SCC
@@ -455,7 +456,7 @@
 		/* no bootinfo model id -> NetBSD booter was used! */
 		/* XXX FIXME: breaks for model > 31 */
 		model=(mac_bi_data.cpuid>>2)&63;
-		printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+		printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
 	}
 
 	macintosh_config = mac_data_table; 
@@ -473,22 +474,22 @@
 	iop_preinit();
 	mac_debug_init();
 
-	printk ("Detected Macintosh model: %d \n", model);
+	printk (KERN_INFO "Detected Macintosh model: %d \n", model);
 
 	/*
 	 * Report booter data:
 	 */
-	printk (" Penguin bootinfo data:\n");
-	printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
+	printk (KERN_DEBUG " Penguin bootinfo data:\n");
+	printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
 		mac_bi_data.videoaddr, mac_bi_data.videorow, 
 		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
 		mac_bi_data.dimensions >> 16); 
-	printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+	printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
 		mac_bi_data.videological, mac_orig_videoaddr, 
 		mac_bi_data.sccbase); 
-	printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+	printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
 		mac_bi_data.boottime, mac_bi_data.gmtbias); 
-	printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+	printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
 		mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); 
 #if 0
 	printk ("Ramdisk: addr 0x%lx size 0x%lx\n", 
@@ -511,7 +512,7 @@
 	    MACHW_SET(MAC_SCSI_96_2);
 	  break;
 	default:
-	  printk("config.c: wtf: unknown scsi, using 53c80\n");
+	  printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
 	  MACHW_SET(MAC_SCSI_80);
 	  break;
 
@@ -525,7 +526,7 @@
 
 void mac_report_hardware(void)
 {
-	printk("Apple Macintosh %s\n", macintosh_config->name);
+	printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
 
 static void mac_get_model(char *str)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/iop.c linux-2.4.21-rc3/arch/m68k/mac/iop.c
--- linux-2.4.20/arch/m68k/mac/iop.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mac/iop.c	2003-05-22 22:06:41.000000000 +0000
@@ -28,7 +28,7 @@
  *		  globally-visible functions take an IOP number instead of an
  *		  an actual base address.
  * 990610 (jmt) - Finished the message passing framework and it seems to work.
- *		  Sending _definately_ works; my adb-bus.c mods can send
+ *		  Sending _definitely_ works; my adb-bus.c mods can send
  *		  messages and receive the MSG_COMPLETED status back from the
  *		  IOP. The trick now is figuring out the message formats.
  * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
@@ -236,7 +236,7 @@
 
 /*
  * This is called by the startup code before anything else. Its purpose
- * is to find and initalize the IOPs early in the boot sequence, so that
+ * is to find and initialize the IOPs early in the boot sequence, so that
  * the serial IOP can be placed into bypass mode _before_ we try to
  * initialize the serial console.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/macints.c linux-2.4.21-rc3/arch/m68k/mac/macints.c
--- linux-2.4.20/arch/m68k/mac/macints.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mac/macints.c	2003-05-22 22:06:51.000000000 +0000
@@ -30,7 +30,7 @@
  *		  - slot 0: SCSI interrupt
  *		  - slot 1: Sound interrupt
  *
- * Levels 3-6 vary by machine type. For VIA or RBV Macintohes:
+ * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
  *
  *	3	- unused (?)
  *
@@ -494,7 +494,7 @@
  * Add an interrupt service routine to an interrupt source.
  * Returns 0 on success.
  *
- * FIXME: You can register interrupts on nonexistant source (ie PSC4 on a
+ * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
  *        non-PSC machine). We should return -EINVAL in those cases.
  */
  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/via.c linux-2.4.21-rc3/arch/m68k/mac/via.c
--- linux-2.4.20/arch/m68k/mac/via.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mac/via.c	2003-05-22 22:06:41.000000000 +0000
@@ -137,15 +137,15 @@
 			panic("UNKNOWN VIA TYPE");
 	}
 
-	printk("VIA1 at %p is a 6522 or clone\n", via1);
+	printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
 
-	printk("VIA2 at %p is ", via2);
+	printk(KERN_INFO "VIA2 at %p is ", via2);
 	if (rbv_present) {
-		printk("an RBV\n");
+		printk(KERN_INFO "an RBV\n");
 	} else if (oss_present) {
-		printk("an OSS\n");
+		printk(KERN_INFO "an OSS\n");
 	} else {
-		printk("a 6522 or clone\n");
+		printk(KERN_INFO "a 6522 or clone\n");
 	}
 
 #ifdef DEBUG_VIA
@@ -291,22 +291,22 @@
 
 void via_debug_dump(void)
 {
-	printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+	printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 		(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
-	printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+	printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 		(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
 	if (oss_present) {
-		printk("VIA2: <OSS>\n");
+		printk(KERN_DEBUG "VIA2: <OSS>\n");
 	} else if (rbv_present) {
-		printk("VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
+		printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
 			(uint) via2[rIFR], (uint) via2[rIER]);
-		printk("      SIFR = 0x%02X SIER = 0x%02X\n",
+		printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
 			(uint) via2[rSIFR], (uint) via2[rSIER]);
 	} else {
-		printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+		printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 			(uint) via2[vDirA], (uint) via2[vDirB],
 			(uint) via2[vACR]);
-		printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+		printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 			(uint) via2[vPCR],
 			(uint) via2[vIFR], (uint) via2[vIER]);
 	}
@@ -374,7 +374,10 @@
 
 	if (!rbv_present) {
 		/* set the line to be an output on non-RBV machines */
-		via2[vDirB] |= 0x02;
+		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			via2[vDirB] |= 0x02;
+		}
 	}
 
 	/* this seems to be an ADB bit on PMU machines */
@@ -390,8 +393,23 @@
 		via2[rSIER] = 0x7F;
 		via2[rSIER] = nubus_active | 0x80;
 	} else {
-		via2[vBufA] = 0xFF;
-		via2[vDirA] = ~nubus_active;
+		/* These are ADB bits on PMU */
+		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			switch(macintosh_config->ident)
+			{
+				case MAC_MODEL_II:
+				case MAC_MODEL_IIX:
+				case MAC_MODEL_IICX:
+				case MAC_MODEL_SE30:
+					via2[vBufA] |= 0x3F;
+					via2[vDirA] = ~nubus_active | 0xc0;
+					break;
+				default:
+					via2[vBufA] = 0xFF;
+					via2[vDirA] = ~nubus_active;
+			}
+		}
 	}
 }
 
@@ -481,7 +499,7 @@
 	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
-	printk("via_irq_enable(%d)\n", irq);
+	printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
@@ -508,7 +526,21 @@
 			via2[rSIER] = IER_SET_BIT(irq_idx);
 		} else {
 			/* Make sure the bit is an input, to enable the irq */
-			via2[vDirA] &= ~irq_bit;
+			/* But not on PowerBooks, that's ADB... */
+			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			   	switch(macintosh_config->ident)
+				{
+					case MAC_MODEL_II:
+					case MAC_MODEL_IIX:
+					case MAC_MODEL_IICX:
+					case MAC_MODEL_SE30:
+						via2[vDirA] &= (~irq_bit | 0xc0);
+						break;
+					default:
+						via2[vDirA] &= ~irq_bit;
+				}
+			}
 		}
 		nubus_active |= irq_bit;
 	}
@@ -520,7 +552,7 @@
 	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
-	printk("via_irq_disable(%d)\n", irq);
+	printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
@@ -533,7 +565,11 @@
 			via2[rSIER] = IER_CLR_BIT(irq_idx);
 		} else {
 			/* disable the nubus irq by changing dir to output */
-			via2[vDirA] |= irq_bit;
+			/* except on PMU */
+			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+				via2[vDirA] |= irq_bit;
+			}
 		}
 		nubus_active &= ~irq_bit;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/math-emu/fp_arith.c linux-2.4.21-rc3/arch/m68k/math-emu/fp_arith.c
--- linux-2.4.20/arch/m68k/math-emu/fp_arith.c	1999-08-15 18:47:29.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/math-emu/fp_arith.c	2003-05-22 22:06:39.000000000 +0000
@@ -113,7 +113,7 @@
 	return dest;
 }
 
-/* fp_fsub: Implementes the kernel of the FSUB, FSSUB, and FDSUB
+/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB
    instructions.
 
    Remember that the arguments are in assembler-syntax order! */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/Makefile linux-2.4.21-rc3/arch/m68k/mm/Makefile
--- linux-2.4.20/arch/m68k/mm/Makefile	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mm/Makefile	2003-05-22 22:06:27.000000000 +0000
@@ -14,7 +14,7 @@
 ifndef CONFIG_SUN3
 obj-y		+= kmap.o memory.o motorola.o
 else
-obj-y		+= sun3mmu.o
+obj-y		+= sun3kmap.o sun3mmu.o
 endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/memory.c linux-2.4.21-rc3/arch/m68k/mm/memory.c
--- linux-2.4.20/arch/m68k/mm/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mm/memory.c	2003-05-22 22:06:50.000000000 +0000
@@ -434,46 +434,51 @@
 #endif
 
 /* invalidate page in both caches */
-#define	clear040(paddr)					\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cinvp %%bc,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+static inline void clear040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cinvp %%bc,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* invalidate page in i-cache */
-#define	cleari040(paddr)				\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cinvp %%ic,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+static inline void cleari040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cinvp %%ic,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* push page in both caches */
-#define	push040(paddr)					\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cpushp %%bc,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
+static inline void push040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cpushp %%bc,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* push and invalidate page in both caches, must disable ints
  * to avoid invalidating valid data */
-#define	pushcl040(paddr)			\
-	do { unsigned long flags;               \
-             save_flags(flags);                 \
-	     cli();                             \
-             push040(paddr);			\
-	     if (CPU_IS_060) clear040(paddr);	\
-	     restore_flags(flags);              \
-	} while(0)
-
-/* push page in both caches, invalidate in i-cache */
-/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
-#define	pushcli040(paddr)			\
-	do { push040(paddr);			\
-	} while(0)
+static inline void pushcl040(unsigned long paddr)
+{
+	unsigned long flags;
 
+	local_irq_save(flags);
+	push040(paddr);
+	if (CPU_IS_060)
+		clear040(paddr);
+	local_irq_restore(flags);
+}
 
 /*
  * 040: Hit every page containing an address in the range paddr..paddr+len-1.
@@ -567,7 +572,7 @@
 	paddr &= PAGE_MASK;
 
 	do {
-	    pushcli040(paddr);
+	    push040(paddr);
 	    paddr += tmp;
 	} while ((len -= tmp) > 0);
     }
@@ -593,12 +598,6 @@
 }
 
 
-#undef clear040
-#undef cleari040
-#undef push040
-#undef pushcl040
-#undef pushcli040
-
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
 int mm_end_of_chunk (unsigned long addr, int len)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/sun3kmap.c linux-2.4.21-rc3/arch/m68k/mm/sun3kmap.c
--- linux-2.4.20/arch/m68k/mm/sun3kmap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mm/sun3kmap.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,156 @@
+/*
+ * linux/arch/m68k/mm/sun3kmap.c
+ *
+ * Copyright (C) 2002 Sam Creasey <sammy@sammy.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/sun3mmu.h>
+
+#undef SUN3_KMAP_DEBUG
+
+#ifdef SUN3_KMAP_DEBUG
+extern void print_pte_vaddr(unsigned long vaddr);
+#endif
+
+extern void mmu_emu_map_pmeg (int context, int vaddr);
+
+static inline void do_page_mapin(unsigned long phys, unsigned long virt, 
+				 unsigned long type)
+{
+	unsigned long pte;
+	pte_t ptep;
+
+	ptep = mk_pte_phys(phys, PAGE_KERNEL);
+	pte = pte_val(ptep);
+	pte |= type;
+
+	sun3_put_pte(virt, pte);
+
+#ifdef SUN3_KMAP_DEBUG
+	print_pte_vaddr(virt);
+#endif
+
+}
+
+static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt, 
+				 unsigned long type, int pages)
+{
+
+	if(sun3_get_segmap(virt & ~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) 
+		mmu_emu_map_pmeg(sun3_get_context(), virt);
+
+	while(pages) {
+		do_page_mapin(phys, virt, type);
+		phys += PAGE_SIZE;
+		virt += PAGE_SIZE;
+		pages--;
+	}
+}
+
+void *sun3_ioremap(unsigned long phys, unsigned long size, 
+		   unsigned long type)
+{
+	struct vm_struct *area;
+	unsigned long offset, virt, ret;
+	int pages;
+
+	if(!size)
+		return NULL;
+
+	/* page align */
+	offset = phys & (PAGE_SIZE-1);
+	phys &= ~(PAGE_SIZE-1);
+
+	size += offset;
+	size = PAGE_ALIGN(size);
+	if((area = get_vm_area(size, VM_IOREMAP)) == NULL)
+		return NULL;
+
+#ifdef SUN3_KMAP_DEBUG
+	printk("ioremap: got virt %p size %lx(%lx)\n", 
+	       area->addr, size, area->size);
+#endif
+
+	pages = size / PAGE_SIZE;
+	virt = (unsigned long)area->addr;
+	ret = virt + offset;
+
+	while(pages) {
+		int seg_pages;
+
+		seg_pages = (SUN3_PMEG_SIZE - (virt & SUN3_PMEG_MASK)) / PAGE_SIZE;
+		if(seg_pages > pages)
+			seg_pages = pages;
+		
+		do_pmeg_mapin(phys, virt, type, seg_pages);
+
+		pages -= seg_pages;
+		phys += seg_pages * PAGE_SIZE;
+		virt += seg_pages * PAGE_SIZE;
+	}
+		
+	return (void *)ret;
+
+}
+ 
+ 
+void *__ioremap(unsigned long phys, unsigned long size, int cache)
+{
+	
+	return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO);
+	
+}
+
+void iounmap(void *addr)
+{
+	vfree((void *)(PAGE_MASK & (unsigned long)addr));	
+}
+
+/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
+ * trapping the potential read fault.  Returns 0 if the access faulted,
+ * 1 on success.
+ *  
+ * This function is primarily used to check addresses on the VME bus.
+ *
+ * Mucking with the page fault handler seems a little hackish to me, but
+ * SunOS, NetBSD, and Mach all implemented this check in such a manner, 
+ * so I figure we're allowed.
+ */
+int sun3_map_test(unsigned long addr, char *val)
+{
+	int ret = 0;
+
+	__asm__ __volatile__
+		(".globl _sun3_map_test_start\n"
+		 "_sun3_map_test_start:\n"
+		 "1: moveb (%2), (%0)\n"
+		 "   moveq #1, %1\n"
+		 "2:\n"
+		 ".section .fixup,\"ax\"\n"
+		 ".even\n"
+		 "3: moveq #0, %1\n"
+		 "   jmp 2b\n"
+		 ".previous\n"
+		 ".section __ex_table,\"a\"\n"
+		 ".align 4\n"
+		 ".long 1b,3b\n"
+		 ".previous\n"
+		 ".globl _sun3_map_test_end\n"
+		 "_sun3_map_test_end:\n"
+		 : "=a"(val), "=r"(ret)
+		 : "a"(addr));
+	
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/sun3mmu.c linux-2.4.21-rc3/arch/m68k/mm/sun3mmu.c
--- linux-2.4.20/arch/m68k/mm/sun3mmu.c	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mm/sun3mmu.c	2003-05-22 22:06:39.000000000 +0000
@@ -96,13 +96,12 @@
 	}
 
 	mmu_emu_init(bootmem_end);
-	
+
 	current->mm = NULL;
 
 	/* memory sizing is a hack stolen from motorola.c..  hope it works for us */
-	zones_size[1] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
-	zones_size[0] = zones_size[1]/2;
-	zones_size[1] -= zones_size[0];
+	zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+	zones_size[1] = 0;
 	
 	free_area_init(zones_size);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mvme16x/rtc.c linux-2.4.21-rc3/arch/m68k/mvme16x/rtc.c
--- linux-2.4.20/arch/m68k/mvme16x/rtc.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/mvme16x/rtc.c	2003-05-22 22:06:47.000000000 +0000
@@ -168,7 +168,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/q40/config.c linux-2.4.21-rc3/arch/m68k/q40/config.c
--- linux-2.4.20/arch/m68k/q40/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/q40/config.c	2003-05-22 22:06:47.000000000 +0000
@@ -58,7 +58,10 @@
 extern void q40_gettod (int *year, int *mon, int *day, int *hour,
                            int *min, int *sec);
 extern int q40_hwclk (int, struct rtc_time *);
+extern unsigned int q40_get_ss (void);
 extern int q40_set_clock_mmss (unsigned long);
+static int q40_get_rtc_pll(struct rtc_pll_info *pll);
+static int q40_set_rtc_pll(struct rtc_pll_info *pll);
 extern void q40_reset (void);
 void q40_halt(void);
 extern void q40_waitbut(void);
@@ -196,6 +199,9 @@
     mach_gettimeoffset   = q40_gettimeoffset; 
     mach_gettod  	 = q40_gettod;
     mach_hwclk           = q40_hwclk; 
+    mach_get_ss          = q40_get_ss; 
+    mach_get_rtc_pll     = q40_get_rtc_pll; 
+    mach_set_rtc_pll     = q40_set_rtc_pll; 
     mach_set_clock_mmss	 = q40_set_clock_mmss;
 
     mach_reset		 = q40_reset;
@@ -331,6 +337,11 @@
 	return 0;
 }
 
+unsigned int q40_get_ss()
+{
+	return bcd2bin(Q40_RTC_SECS);
+}
+
 /*
  * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
  * clock is out by > 30 minutes.  Logic lifted from atari code.
@@ -362,3 +373,33 @@
 	return retval;
 }
 
+
+/* get and set PLL calibration of RTC clock */
+#define Q40_RTC_PLL_MASK ((1<<5)-1)
+#define Q40_RTC_PLL_SIGN (1<<5)
+
+static int q40_get_rtc_pll(struct rtc_pll_info *pll)
+{
+      int tmp=Q40_RTC_CTRL;
+      pll->pll_value = tmp & Q40_RTC_PLL_MASK;
+      if (tmp & Q40_RTC_PLL_SIGN) 
+	  pll->pll_value = -pll->pll_value;
+      pll->pll_max=31;
+      pll->pll_min=-31;
+      pll->pll_posmult=512;
+      pll->pll_negmult=256;
+      pll->pll_clock=125829120;
+      return 0;
+  }
+
+static int q40_set_rtc_pll(struct rtc_pll_info *pll)
+{
+  if (!pll->pll_ctrl){
+      /* the docs are a bit unclear so I am doublesetting RTC_WRITE here ... */
+      int tmp=(pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | Q40_RTC_WRITE;
+      Q40_RTC_CTRL |= Q40_RTC_WRITE;
+      Q40_RTC_CTRL = tmp;
+      Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+      return 0;
+  } else return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/q40/q40ints.c linux-2.4.21-rc3/arch/m68k/q40/q40ints.c
--- linux-2.4.20/arch/m68k/q40/q40ints.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/q40/q40ints.c	2003-05-22 22:06:40.000000000 +0000
@@ -7,7 +7,7 @@
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  *
- * .. used to be losely based on bvme6000ints.c
+ * .. used to be loosely based on bvme6000ints.c
  *
  */
 
@@ -271,7 +271,7 @@
 #if 0
 static struct IRQ_TABLE iirqs[]={
   {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
-  Q40_{IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
   {0,0}};
 #endif
 static struct IRQ_TABLE eirqs[]={
@@ -438,7 +438,7 @@
 {
   /* disable ISA iqs : only do something if the driver has been
    * verified to be Q40 "compatible" - right now IDE, NE2K
-   * Any driver should not attempt to sleep accross disable_irq !!
+   * Any driver should not attempt to sleep across disable_irq !!
    */
 
   if ( irq>=5 && irq<=15 ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/Makefile linux-2.4.21-rc3/arch/m68k/sun3/Makefile
--- linux-2.4.20/arch/m68k/sun3/Makefile	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3/Makefile	2003-05-22 22:06:24.000000000 +0000
@@ -14,9 +14,9 @@
 
 export-objs	:= sun3_ksyms.o
 
-obj-y	:= sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o
+obj-y	:= sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o
 
-obj-$(CONFIG_SUN3) += config.o idprom.o mmu_emu.o leds.o dvma.o \
+obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o \
 			intersil.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/idprom.c linux-2.4.21-rc3/arch/m68k/sun3/idprom.c
--- linux-2.4.20/arch/m68k/sun3/idprom.c	1999-09-08 18:20:42.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3/idprom.c	2003-05-22 22:06:40.000000000 +0000
@@ -31,8 +31,8 @@
 { "Sun 3/60", (SM_SUN3 | SM_3_60) },
 { "Sun 3/E", (SM_SUN3 | SM_3_E) },
 /* Now, Sun3x's */
-{ "Sun 3/460 Series", (SM_SUN3 | SM_3_460) },
-{ "Sun 3/80", (SM_SUN3 | SM_3_80) },
+{ "Sun 3/460 Series", (SM_SUN3X | SM_3_460) },
+{ "Sun 3/80", (SM_SUN3X | SM_3_80) },
 /* Then, Sun4's */
 //{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
 //{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/mmu_emu.c linux-2.4.21-rc3/arch/m68k/sun3/mmu_emu.c
--- linux-2.4.20/arch/m68k/sun3/mmu_emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3/mmu_emu.c	2003-05-22 22:06:26.000000000 +0000
@@ -178,7 +178,6 @@
 			pmeg_alloc[sun3_get_segmap(seg)] = 2;
 		}
 	}
-
 	
 	dvma_init();
 	
@@ -277,7 +276,7 @@
 //todo: better allocation scheme? but is extra complexity worthwhile?
 //todo: only clear old entries if necessary? how to tell?
 
-static inline void mmu_emu_map_pmeg (int context, int vaddr)
+inline void mmu_emu_map_pmeg (int context, int vaddr)
 {
 	static unsigned char curr_pmeg = 128;
 	int i;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/sun3dvma.c linux-2.4.21-rc3/arch/m68k/sun3/sun3dvma.c
--- linux-2.4.20/arch/m68k/sun3/sun3dvma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3/sun3dvma.c	2003-05-22 22:06:28.000000000 +0000
@@ -97,7 +97,7 @@
 	printk("end of hole listing...\n");
 	
 }
-#endif DVMA_DEBUG
+#endif /* DVMA_DEBUG */
 
 static inline int refill(void)
 {
@@ -317,8 +317,14 @@
 
 void dvma_unmap(void *baddr)
 {
-
-	free_baddr((unsigned long)baddr);
+	unsigned long addr;
+	
+	addr = (unsigned long)baddr;
+	/* check if this is a vme mapping */
+	if(!(addr & 0x00f00000))
+		addr |= 0xf00000;
+	
+	free_baddr(addr);
 	
 	return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/sun3ints.c linux-2.4.21-rc3/arch/m68k/sun3/sun3ints.c
--- linux-2.4.20/arch/m68k/sun3/sun3ints.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3/sun3ints.c	2003-05-22 22:06:46.000000000 +0000
@@ -17,6 +17,7 @@
 #include <asm/sun3ints.h>
 
 extern void sun3_leds (unsigned char);
+static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
 
 void sun3_disable_interrupts(void)
 {
@@ -62,11 +63,6 @@
 	*sun3_intreg |=  (1<<irq);
 }
 
-int sun3_get_irq_list(char *buf)
-{
-	return 0;
-}
-
 static void sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
 {
 	sun3_do_irq(irq,fp);
@@ -93,13 +89,39 @@
 
 /* handle requested ints, excepting 5 and 7, which always do the same
    thing */
+void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	sun3_inthandle, sun3_inthandle, sun3_inthandle, sun3_inthandle,
+	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
+};
+
+static const char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL,
+				     NULL, "timer", NULL, "int7 handler" };
 static void *dev_ids[SYS_IRQS];
 static void (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
 	NULL, NULL, NULL, NULL, NULL, sun3_int5, NULL, sun3_int7
 };
-static void (*sun3_vechandler[192])(int, void *, struct pt_regs *);
-static void *vec_ids[192];
-static const char *vec_names[192];
+
+static void (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
+static void *vec_ids[SUN3_INT_VECS];
+static const char *vec_names[SUN3_INT_VECS];
+static int vec_ints[SUN3_INT_VECS];
+
+
+int sun3_get_irq_list(char *buf)
+{
+	int i, len = 0;
+
+	for(i = 0; i < (SUN3_INT_VECS-1); i++) {
+		if(sun3_vechandler[i] != NULL) {
+			len += sprintf(buf+len, "vec %3d: %10u %s\n", i+64,
+				       vec_ints[i],
+				       (vec_names[i]) ? vec_names[i] :
+				       "sun3_vechandler");
+		}
+	}
+
+	return 0;
+}
 
 static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -117,14 +139,6 @@
 //	intersil_clear();
 }
 
-void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	sun3_inthandle, sun3_inthandle, sun3_inthandle, sun3_inthandle,
-	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
-};
-
-static const char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL,
-					   NULL, "timer", NULL, NULL };
-
 void sun3_init_IRQ(void)
 {
 	int i;
@@ -175,6 +189,7 @@
 			sun3_vechandler[vec] = handler;
 			vec_ids[vec] = dev_id;
 			vec_names[vec] = devname;
+			vec_ints[vec] = 0;
 			
 			return 0;
 		}
@@ -221,7 +236,8 @@
 		vec = irq - 64;
 		if(sun3_vechandler[vec] == NULL) 
 			panic ("bad interrupt vector %d received\n",irq);
-			
+
+		vec_ints[vec]++;
 		sun3_vechandler[vec](irq, vec_ids[vec], regs);
 		return;
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3x/config.c linux-2.4.21-rc3/arch/m68k/sun3x/config.c
--- linux-2.4.20/arch/m68k/sun3x/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3x/config.c	2003-05-22 22:06:25.000000000 +0000
@@ -17,12 +17,14 @@
 #include <asm/sun3xprom.h>
 #include <asm/sun3ints.h>
 #include <asm/setup.h>
+#include <asm/oplib.h>
 
 #include "time.h"
 
 volatile char *clock_va;
 extern volatile unsigned char *sun3_intreg;
 
+extern void sun3_get_model(char *model);
 
 int __init sun3x_keyb_init(void)
 {
@@ -44,10 +46,16 @@
 
 }
 
-/* should probably detect types of these eventually. */
-static void sun3x_get_model(char *model)
+static int sun3x_get_hardware_list(char *buffer)
 {
-	sprintf(model, "Sun3x");
+
+	int len = 0;
+
+	len += sprintf(buffer + len, "PROM Revision:\t%s\n",
+		       romvec->pv_monid);
+
+	return len;
+
 }
 
 /*
@@ -81,7 +89,8 @@
 
 	mach_gettod          = sun3x_gettod;
 	mach_hwclk           = sun3x_hwclk;
-	mach_get_model       = sun3x_get_model;
+	mach_get_model       = sun3_get_model;
+	mach_get_hardware_list = sun3x_get_hardware_list;
 
 	sun3_intreg = (unsigned char *)SUN3X_INTREG;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3x/prom.c linux-2.4.21-rc3/arch/m68k/sun3x/prom.c
--- linux-2.4.20/arch/m68k/sun3x/prom.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/m68k/sun3x/prom.c	2003-05-22 22:06:42.000000000 +0000
@@ -26,8 +26,6 @@
 int (*sun3x_mayput)(int);
 void (*sun3x_prom_reboot)(void);
 e_vector sun3x_prom_abort;
-struct idprom *idprom;
-static struct idprom idprom_buffer;
 struct linux_romvec *romvec;
 
 /* prom vector table */
@@ -107,8 +105,6 @@
 void sun3x_prom_init(void)
 {
     /* Read the vector table */
-	int i;
-
 
     sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
     sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
@@ -118,12 +114,9 @@
     sun3x_prom_abort = *(e_vector *)  (SUN3X_P_ABORT);
     romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
 
-    /* make a copy of the idprom structure */
-    for(i = 0; i < sizeof(struct idprom); i++) 
-	    ((unsigned char *)(&idprom_buffer))[i] = ((unsigned char *)SUN3X_IDPROM)[i];
-    idprom = &idprom_buffer;
+    idprom_init();
 
-    if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3X) {
+    if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
 	    printk("Warning: machine reports strange type %02x\n",
 		   idprom->id_machtype);
 	    printk("Pretending it's a 3/80, but very afraid...\n");
@@ -163,3 +156,19 @@
 {
 	sun3x_halt();
 }
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char
+prom_get_idprom(char *idbuf, int num_bytes)
+{
+        int i;
+
+	/* make a copy of the idprom structure */
+	for(i = 0; i < num_bytes; i++) 
+		idbuf[i] = ((char *)SUN3X_IDPROM)[i];
+
+        return idbuf[0];
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/mips/config-shared.in linux-2.4.21-rc3/arch/mips/config-shared.in
--- linux-2.4.20/arch/mips/config-shared.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/mips/config-shared.in	2003-05-22 22:06:47.000000000 +0000
@@ -479,7 +479,7 @@
 if [ "$CONFIG_CPU_SB1" = "y" ]; then
    choice 'SB1 Pass' \
 	 "Pass1   CONFIG_CPU_SB1_PASS_1  \
-	  Pass2   CONFIG_CPU_SB1_PASS_2
+	  Pass2   CONFIG_CPU_SB1_PASS_2  \
 	  Pass2.2 CONFIG_CPU_SB1_PASS_2_2" Pass1
    if [ "$CONFIG_CPU_SB1_PASS_1" = "y" ]; then
       define_bool CONFIG_SB1_PASS_1_WORKAROUNDS y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/mips/kernel/process.c linux-2.4.21-rc3/arch/mips/kernel/process.c
--- linux-2.4.20/arch/mips/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/mips/kernel/process.c	2003-05-22 22:06:41.000000000 +0000
@@ -152,7 +152,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/mips64/kernel/process.c linux-2.4.21-rc3/arch/mips64/kernel/process.c
--- linux-2.4.20/arch/mips64/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/mips64/kernel/process.c	2003-05-22 22:06:39.000000000 +0000
@@ -151,7 +151,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	int retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/Makefile linux-2.4.21-rc3/arch/parisc/Makefile
--- linux-2.4.20/arch/parisc/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/Makefile	2003-05-22 22:06:41.000000000 +0000
@@ -91,14 +91,6 @@
 SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
 DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.o
 
-ifdef CONFIG_KWDB
-SUBDIRS := $(SUBDIRS) arch/parisc/kdb
-DRIVERS := $(DRIVERS) arch/parisc/kdb/kdb.o
-
-arch/parisc/kdb: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kdb
-endif
-
 arch/parisc/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kernel
 
@@ -106,6 +98,21 @@
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
 
 palo: vmlinux
+	@if [ $$(palo -f /dev/null >/dev/null 2>&1 ; echo $$?) != 2 ]; then \
+		echo 'ERROR: Please install palo first (apt-get install palo)';\
+		echo 'or build it from source and install it somewhere in your $$PATH';\
+		false; \
+	fi
+	@if [ ! -f ./palo.conf ]; then \
+		cp arch/parisc/defpalo.conf palo.conf; \
+		echo 'A generic palo config file (./palo.conf) has been created for you.'; \
+		echo 'You should check it and re-run "make palo".'; \
+		echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
+		false; \
+	fi
+	palo -f ./palo.conf
+
+oldpalo: vmlinux
 	export TOPDIR=`pwd`; \
 	unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/defconfig linux-2.4.21-rc3/arch/parisc/defconfig
--- linux-2.4.20/arch/parisc/defconfig	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/defconfig	2003-05-22 22:06:25.000000000 +0000
@@ -32,7 +32,6 @@
 #
 # CONFIG_SMP is not set
 CONFIG_CHASSIS_LCD_LED=y
-# CONFIG_KWDB is not set
 CONFIG_IOMMU_CCIO=y
 CONFIG_GSC=y
 CONFIG_GSC_LASI=y
@@ -87,7 +86,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -138,6 +139,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -155,6 +161,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -171,6 +182,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# 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
@@ -185,6 +197,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 is not set
 
 #
 # IDE chipset support/bugfixes
@@ -196,12 +209,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 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 is not set
+# 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
@@ -209,6 +225,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -296,9 +313,13 @@
 CONFIG_53C700_USE_CONSISTENT=y
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-CONFIG_SCSI_SYM53C8XX=y
+# CONFIG_ASK_ZALON is not set
+# CONFIG_ASK_NCR53C8XX is not set
+# CONFIG_ASK_SYM53C8XX is not set
 CONFIG_SCSI_ZALON=y
+CONFIG_ASK_ZALON=y
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_ASK_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
@@ -366,6 +387,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
+# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
@@ -403,6 +425,7 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -473,6 +496,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -515,7 +539,6 @@
 #
 # CONFIG_WATCHDOG is not set
 CONFIG_GENRTC=y
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -585,7 +608,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=y
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
@@ -697,6 +720,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_STI=y
 # CONFIG_FB_MATROX is not set
@@ -704,6 +728,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -759,106 +784,6 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/Makefile linux-2.4.21-rc3/arch/parisc/kernel/Makefile
--- linux-2.4.20/arch/parisc/kernel/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -24,7 +24,7 @@
 		pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
 		ptrace.o hardware.o inventory.o drivers.o semaphore.o \
 		signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
-		processor.o power.o
+		processor.o power.o pdc_chassis.o
 
 export-objs	:= parisc_ksyms.o superio.o keyboard.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ccio-dma.c linux-2.4.21-rc3/arch/parisc/kernel/ccio-dma.c
--- linux-2.4.20/arch/parisc/kernel/ccio-dma.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/ccio-dma.c	2003-05-22 22:06:28.000000000 +0000
@@ -609,8 +609,6 @@
 		return 0;
 	}
 
-	dev->dma_mask = mask;   /* save it */
-
 	/* only support 32-bit devices (ie PCI/GSC) */
 	return (int)(mask == 0xffffffffUL);
 }
@@ -1441,7 +1439,7 @@
 	result = request_resource(&iomem_resource, res);
 	if (result < 0) {
 		printk(KERN_ERR 
-		       "%s: failed to claim CCIO bus address space (%p,%p)\n", 
+		       "%s: failed to claim CCIO bus address space (%lx,%lx)\n", 
 		       __FILE__, res->start, res->end);
 	}
 }
@@ -1486,7 +1484,7 @@
 int ccio_allocate_resource(const struct parisc_device *dev,
 		struct resource *res, unsigned long size,
 		unsigned long min, unsigned long max, unsigned long align,
-		void (*alignf)(void *, struct resource *, unsigned long),
+		void (*alignf)(void *, struct resource *, unsigned long, unsigned long),
 		void *alignf_data)
 {
 	struct ioc *ioc = ccio_get_iommu(dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c linux-2.4.21-rc3/arch/parisc/kernel/ccio-rm-dma.c
--- linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/ccio-rm-dma.c	2003-05-22 22:06:38.000000000 +0000
@@ -74,8 +74,6 @@
 		return(0);
 	}
 
-	dev->dma_mask = mask;   /* save it */
-
 	/* only support 32-bit devices (ie PCI/GSC) */
 	return((int) (mask >= 0xffffffffUL));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/drivers.c linux-2.4.21-rc3/arch/parisc/kernel/drivers.c
--- linux-2.4.20/arch/parisc/kernel/drivers.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/drivers.c	2003-05-22 22:06:40.000000000 +0000
@@ -461,6 +461,7 @@
 #define BC_PORT_MASK 0x8
 #define BC_LOWER_PORT 0x8
 
+
 #define BUS_CONVERTER(dev) \
         ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
 
@@ -473,14 +474,29 @@
 	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
 	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
 
-static void walk_native_bus(unsigned long addr, struct parisc_device *parent);
+#define READ_IO_IO_HIGH(dev) \
+	(dev->id.hw_type == HPHW_IOA ? \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high) << 16 : \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high))
+
+
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, 
+			    struct parisc_device *parent);
+
+#define FLEX_MASK (unsigned long)0xfffffffffffc0000
+
+
 void walk_lower_bus(struct parisc_device *dev)
 {
+	unsigned long io_io_low, io_io_high;
 
 	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
 		return;
 
-	walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
+	io_io_low = ((unsigned long)(signed int)READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
+	io_io_high = ((unsigned long)(signed int)READ_IO_IO_HIGH(dev) + ~FLEX_MASK) & FLEX_MASK;
+
+	walk_native_bus(io_io_low, io_io_high, dev);
 }
 
 #define MAX_NATIVE_DEVICES 64
@@ -488,7 +504,9 @@
 
 /**
  * walk_native_bus -- Probe a bus for devices
- * @addr: Base address of this bus.
+ * @io_io_low: Base address of this bus.
+ * @io_io_high: Last address of this bus.
+ * @parent: The parent bus device.
  * 
  * A native bus (eg Runway or GSC) may have up to 64 devices on it,
  * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
@@ -496,28 +514,32 @@
  * devices which are not physically connected (such as extra serial &
  * keyboard ports).  This problem is not yet solved.
  */
-static void walk_native_bus(unsigned long addr, struct parisc_device *parent)
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
+			    struct parisc_device *parent)
 {
-	int i;
+	int i, devices_found = 0;
+	unsigned long hpa = io_io_low;
 	struct hardware_path path;
 
 	get_node_path(parent, &path);
-	for (i = 0; i < MAX_NATIVE_DEVICES; i++) {
-		unsigned long hpa = (addr + i * NATIVE_DEVICE_OFFSET);
-		struct parisc_device *dev;
-
-		/* Was the device already added by Firmware? */
-		dev = find_device_by_addr(hpa);
-		if (!dev) {
-			path.mod = i;
-			dev = alloc_pa_dev(hpa, &path);
-			if (!dev)
-				continue;
-
-			register_parisc_device(dev);
+	do {
+		for (i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
+			struct parisc_device *dev;
+
+			/* Was the device already added by Firmware? */
+			dev = find_device_by_addr(hpa);
+			if (!dev) {
+				path.mod = i;
+				dev = alloc_pa_dev(hpa, &path);
+				if (!dev)
+					continue;
+
+				register_parisc_device(dev);
+				devices_found++;
+			}
+			walk_lower_bus(dev);
 		}
-		walk_lower_bus(dev);
-	}
+	} while (!devices_found && hpa < io_io_high);
 }
 
 #define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
@@ -530,7 +552,9 @@
  */
 void walk_central_bus(void)
 {
-	walk_native_bus(CENTRAL_BUS_ADDR, &root);
+	walk_native_bus(CENTRAL_BUS_ADDR, 
+			CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
+			&root);
 }
 
 void fixup_child_irqs(struct parisc_device *parent, int base,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/entry.S linux-2.4.21-rc3/arch/parisc/kernel/entry.S
--- linux-2.4.20/arch/parisc/kernel/entry.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/entry.S	2003-05-22 22:06:38.000000000 +0000
@@ -759,32 +759,30 @@
 
 	.import do_softirq,code
 intr_do_softirq:
-	bl      do_softirq,%r2
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
-#else
-	nop
 #endif
-	b       intr_check_resched
-	nop
+	ldil	L%intr_check_resched, %r2
+	b	do_softirq
+	ldo	R%intr_check_resched(%r2), %r2
 
 	.import schedule,code
 intr_do_resched:
 	/* Only do reschedule if we are returning to user space */
 	LDREG   PT_IASQ0(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB= 0,%r20,intr_check_sig /* backward */
 	nop
 	LDREG   PT_IASQ1(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB= 0,%r20,intr_check_sig /* backward */
 	nop
 
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
 #endif
 
-	ldil	L%intr_return, %r2
+	ldil	L%intr_check_sig, %r2
 	b	schedule
-	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+	ldo	R%intr_check_sig(%r2), %r2
 
 
 	.import do_signal,code
@@ -799,15 +797,14 @@
 
 	copy	%r0, %r24			/* unsigned long in_syscall */
 	copy	%r16, %r25			/* struct pt_regs *regs */
-	ssm     PSW_SM_I, %r0
+	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 #ifdef __LP64__
 	ldo	-16(%r30),%r29			/* Reference param save area */
 #endif
-	bl	do_signal,%r2
-	copy	%r0, %r26			/* sigset_t *oldset = NULL */
+	ldil	L%intr_restore, %r2
+	b	do_signal
+	ldo	R%intr_restore(%r2), %r2
 
-	b	intr_restore
-	nop
 
 	/*
 	 * External interrupts.
@@ -852,7 +849,7 @@
 	ldo	-16(%r30),%r29	/* Reference param save area */
 #endif
 	b	do_cpu_irq_mask
-	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+	ldo	R%intr_return(%r2), %r2
 
 
 
@@ -925,19 +922,16 @@
 	loadgp
 
 	copy		%r29, %r25	/* arg1 is pt_regs */
-#ifdef CONFIG_KWDB
-	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
-#endif
 
 #ifdef __LP64__
 	ldo		-16(%r30),%r29	/* Reference param save area */
 #endif
 
-	ldil		L%intr_return, %r2
+	ldil		L%intr_restore, %r2
 	copy		%r25, %r16	/* save pt_regs */
 
 	b		handle_interruption
-	ldo		R%intr_return(%r2), %r2	/* return to intr_return */
+	ldo		R%intr_restore(%r2), %r2
 
 
 	/*
@@ -1319,9 +1313,9 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-	extrd,s         pte,35,4,t0
+	extrd,s         pte,35,4,t1
 	depdi		0,63,12,pte	/* clear lower 12 bits */
-        addi,=          1,t0,0 
+        addi,=          1,t1,0 
         extrd,u,*tr     pte,56,25,pte 
 	extrd,s		pte,56,25,pte	/* bit 31:8 >> 8  */ 
 	idtlbt          pte,prot
@@ -1389,9 +1383,9 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-        extrd,s         pte,35,4,t0
+        extrd,s         pte,35,4,t1
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
         idtlbt          pte,prot
@@ -1642,9 +1636,9 @@
 
 	/* Get rid of prot bits and convert to page addr for iitlbt */
 
-        extrd,s         pte,35,4,t0 
+        extrd,s         pte,35,4,t1 
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte 
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
 	iitlbt          pte,prot
@@ -1860,9 +1854,9 @@
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
 	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
 
-        extrd,s         pte,35,4,t0 
+        extrd,s         pte,35,4,t1 
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte 
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
         idtlbt          pte,prot
@@ -2358,9 +2352,9 @@
 	STREG	%r2,TASK_PT_IAOQ0(%r1)
 	ldo	4(%r2),%r2
 	STREG	%r2,TASK_PT_IAOQ1(%r1)
-	copy	%r25,%r16
+
 	b	intr_restore
-	nop
+	copy	%r25,%r16
 
 	.import do_softirq,code
 syscall_do_softirq:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/firmware.c linux-2.4.21-rc3/arch/parisc/kernel/firmware.c
--- linux-2.4.20/arch/parisc/kernel/firmware.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/firmware.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,4 +1,4 @@
-/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+/* arch/parisc/kernel/firmware.c  - safe pdc access routines
  *
  * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
  * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
@@ -177,6 +177,45 @@
 }
 
 /**
+ * pdc_pat_chassis_send_log - Sends a PDC PAT CHASSIS log message.
+ * @retval: -1 on error, 0 on success. Other value are PDC errors
+ *
+ * Must be correctly formatted or expect system crash
+ */
+#ifdef __LP64__
+int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
+{
+	if (!is_pdc_pat())
+		return -1;
+		
+	int retval = 0;
+	
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
+	spin_unlock_irq(&pdc_lock);
+	
+	return retval;
+}
+#endif
+
+/**
+ * pdc_chassis_disp - Updates display
+ * @retval: -1 on error, 0 on success
+ *
+ * Works on old PDC only (E class, others?)
+ */
+int pdc_chassis_disp(unsigned long disp)
+{
+	int retval = 0;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
  * pdc_coproc_cfg - To identify coprocessors attached to the processor.
  * @pdc_coproc_info: Return buffer address.
  *
@@ -507,12 +546,11 @@
 
 /* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
 #define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
-	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 8) == 0)
 
 	retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
 			      __pa(pdc_result), __pa(hwpath));
 
-
 	if (retval >= PDC_OK) {
 		*scsi_id = (unsigned char) pdc_result[0];
 
@@ -534,10 +572,12 @@
 		** pdc_result[3]	PDC suggested SCSI rate
 		*/
 
+		/*
+		** XXX REVISIT: Doesn't look like PAT PDC does the same.
+		** Problem is A500 also exports 50-pin SE SCSI port.
+		*/
 		if (IS_SPROCKETS()) {
 			/*
-			** Revisit: PAT PDC do the same thing?
-			** A500 also exports 50-pin SE SCSI.
 			**	0 == 8-bit
 			**	1 == 16-bit
 			*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/head64.S linux-2.4.21-rc3/arch/parisc/kernel/head64.S
--- linux-2.4.20/arch/parisc/kernel/head64.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/head64.S	2003-05-22 22:06:45.000000000 +0000
@@ -24,7 +24,7 @@
 #include <asm/pdc.h>		/* for PDC_PSW defines */
 
 
-	.level 2.0
+	.level 2.0w
 
 	.section	.initcall.init
 	.align		4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ioctl32.c linux-2.4.21-rc3/arch/parisc/kernel/ioctl32.c
--- linux-2.4.20/arch/parisc/kernel/ioctl32.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/ioctl32.c	2003-05-22 22:06:46.000000000 +0000
@@ -2986,6 +2986,9 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
+COMPATIBLE_IOCTL(BLKBSZGET)
+COMPATIBLE_IOCTL(BLKBSZSET)
+COMPATIBLE_IOCTL(BLKGETSIZE64)
 
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/irq.c linux-2.4.21-rc3/arch/parisc/kernel/irq.c
--- linux-2.4.20/arch/parisc/kernel/irq.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/irq.c	2003-05-22 22:06:41.000000000 +0000
@@ -201,7 +201,7 @@
 {
 #ifdef CONFIG_PROC_FS
 	char *p = buf;
-	unsigned int regnr;
+	unsigned int regnr = 0;
 
 	p += sprintf(p, "     ");
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/lba_pci.c linux-2.4.21-rc3/arch/parisc/kernel/lba_pci.c
--- linux-2.4.20/arch/parisc/kernel/lba_pci.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/lba_pci.c	2003-05-22 22:06:50.000000000 +0000
@@ -735,47 +735,11 @@
 		bus->resource[0] = &(ldev->hba.io_space);
 		bus->resource[1] = &(ldev->hba.lmmio_space);
 	} else {
-		/* KLUGE ALERT!
-		** PCI-PCI Bridge resource munging.
-		** This hack should go away in the near future.
-		** It's based on the Alpha port.
-		*/
-		int i;
-		u16 cmd;
-
-		for (i = 0; i < 4; i++) {
-			bus->resource[i] =
-				&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
-			bus->resource[i]->name = bus->name;
-		}
-#if 0
-		bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
-#else
-		bus->resource[0]->flags |= IORESOURCE_IO;
-#endif
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-		bus->resource[2]->flags = 0;	/* Don't support prefetchable */
-		bus->resource[3]->flags = 0;	/* not used */
-
-		/* 
-		** If the PPB is enabled (ie already configured) then
-		** just read those values.
-		*/
-		(void) lba_cfg_read16(bus->self, PCI_COMMAND, &cmd);
-		if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
-			pci_read_bridge_bases(bus);
-		} else {
-			/* Not configured.
-			** For now, propogate HBA limits to the bus;
-			**	PCI will adjust them later.
-			*/
-			bus->resource[0]->end = ldev->hba.io_space.end;
-			bus->resource[1]->end = ldev->hba.lmmio_space.end;
-		}
+		pci_read_bridge_bases(bus);
 
-		/* Turn off downstream PF memory address range by default */
-		bus->resource[2]->start = 1024*1024;
-		bus->resource[2]->end = bus->resource[2]->start - 1;
+		/* Turn off downstream PreFetchable Memory range by default */
+		bus->resource[2]->start = 0;
+		bus->resource[2]->end = 0;
 	}
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/led.c linux-2.4.21-rc3/arch/parisc/kernel/led.c
--- linux-2.4.20/arch/parisc/kernel/led.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/led.c	2003-05-22 22:06:40.000000000 +0000
@@ -352,7 +352,8 @@
 static unsigned long led_net_rx_counter, led_net_tx_counter;
 
 static void led_get_net_stats(int addvalue)
-{
+{ 
+#ifdef CONFIG_NET
 	static unsigned long rx_total_last, tx_total_last;
 	unsigned long rx_total, tx_total;
 	struct net_device *dev;
@@ -383,6 +384,7 @@
         
 	rx_total_last += rx_total;
         tx_total_last += tx_total;
+#endif
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c linux-2.4.21-rc3/arch/parisc/kernel/parisc_ksyms.c
--- linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/parisc_ksyms.c	2003-05-22 22:06:53.000000000 +0000
@@ -232,3 +232,11 @@
 EXPORT_SYMBOL_NOVERS($$dyncall);
 #endif
 
+#ifdef CONFIG_SMP
+#ifdef CONFIG_DEBUG_SPINLOCK
+#include <asm/spinlock.h>
+EXPORT_SYMBOL(spin_lock);
+EXPORT_SYMBOL(spin_unlock);
+EXPORT_SYMBOL(spin_trylock);
+#endif
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pci.c linux-2.4.21-rc3/arch/parisc/kernel/pci.c
--- linux-2.4.20/arch/parisc/kernel/pci.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/pci.c	2003-05-22 22:06:24.000000000 +0000
@@ -306,13 +306,13 @@
 		   (32) for primary and secondary buses. */
 		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
 
-		/* Read bridge control */
+		/* Read bridge control - force SERR/PERR on */
 		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bus->bridge_ctl);
+		bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+		pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
 	}
 
-	/* Set FBB bit for now. Disable ISA IO forwarding. Enable PERR/SERR */
-	bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK | 
-			   PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+	bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
 }
 
 
@@ -390,7 +390,7 @@
 */
 void __devinit
 pcibios_align_resource(void *data, struct resource *res,
-		       unsigned long size, unsigned long alignment)
+			unsigned long size, unsigned long alignment)
 {
 	unsigned long mask, align;
 
@@ -407,7 +407,7 @@
 	align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
 
 	/* Align to largest of MIN or input size */
-	mask = MAX(size, align) - 1;
+	mask = MAX(alignment, align) - 1;
 	res->start += mask;
 	res->start &= ~mask;
 
@@ -420,7 +420,7 @@
 
 
 int __devinit
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd;
 	int idx;
@@ -438,6 +438,11 @@
 	*/
         for (idx=0; idx<DEVICE_COUNT_RESOURCE; idx++) {
 		struct resource *r = &dev->resource[idx];
+
+                /* only setup requested resources */
+		if (!(mask & (1<<idx)))
+			continue;
+
 		if (r->flags & IORESOURCE_IO)
 			cmd |= PCI_COMMAND_IO;
 		if (r->flags & IORESOURCE_MEM)
@@ -454,9 +459,11 @@
 	*/
 	cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
+#if 0
 	/* If bridge/bus controller has FBB enabled, child must too. */
 	if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
 		cmd |= PCI_COMMAND_FAST_BACK;
+#endif
 
 	DBGC("PCIBIOS: Enabling device %s cmd 0x%04x\n", dev->slot_name, cmd);
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
@@ -478,6 +485,19 @@
 #endif
 }
 
+static void __devinit
+pcibios_enable_ppb(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	/* find a leaf of the PCI bus tree. */
+        list_for_each(list, &bus->children)
+		pcibios_enable_ppb(pci_bus_b(list));
+
+	if (bus->self && (bus->self->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+		pdev_enable_device(bus->self);
+}
+
 
 /*
 ** Mostly copied from drivers/pci/setup-bus.c:pci_assign_unassigned_resources()
@@ -486,16 +506,13 @@
 pcibios_assign_unassigned_resources(struct pci_bus *bus)
 {
 	/* from drivers/pci/setup-bus.c */
-	extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
+	extern void pbus_size_bridges(struct pci_bus *bus);
+	extern void pbus_assign_resources(struct pci_bus *bus);
 
-	struct pbus_set_ranges_data ranges;
+	pbus_size_bridges(bus);
+	pbus_assign_resources(bus);
 
-	ranges.io_end = ranges.io_start
-				= bus->resource[0]->start + PCIBIOS_MIN_IO;
-	ranges.mem_end = ranges.mem_start
-				= bus->resource[1]->start + PCIBIOS_MIN_MEM;
-	ranges.found_vga = 0;
-	pbus_assign_resources(bus, &ranges);
+	pcibios_enable_ppb(bus);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pdc_chassis.c linux-2.4.21-rc3/arch/parisc/kernel/pdc_chassis.c
--- linux-2.4.20/arch/parisc/kernel/pdc_chassis.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/pdc_chassis.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,205 @@
+/*
+ *		arch/parisc/kernel/pdc_chassis.c
+ *
+ * 		Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *		Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ *
+ *		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, or (at your option)
+ *		any later version.
+ *      
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *      
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef PDC_CHASSIS_DEBUG
+#ifdef PDC_CHASSIS_DEBUG
+#define DPRINTK(fmt, args...)	printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+
+#include <asm/pdc_chassis.h>
+#include <asm/processor.h>
+
+static int pdc_chassis_old = 0;	
+
+
+/** 
+ * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility
+ * @pdc_chassis_old: 1 if old pdc chassis style
+ * 
+ * Currently, only E class and A180 are known to work with this.
+ * Inspired by Christoph Plattner
+ */
+
+static void __init pdc_chassis_checkold(void)
+{
+	switch(CPU_HVERSION) {
+		case 0x480:		/* E25 */
+		case 0x481:		/* E35 */
+		case 0x482:		/* E45 */
+		case 0x483:		/* E55 */
+		case 0x516:		/* A180 */
+			pdc_chassis_old = 1;
+			break;
+
+		default:
+			break;
+	}
+	DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
+}
+
+
+/**
+ * pdc_chassis_panic_event() - Called by the panic handler.
+ *
+ * As soon as a panic occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_panic_event(struct notifier_block *this,
+		        unsigned long event, void *ptr)
+{
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+		return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_panic_block = {
+	notifier_call: pdc_chassis_panic_event,
+	priority: INT_MAX,
+};
+
+
+/**
+ * parisc_reboot_event() - Called by the reboot handler.
+ *
+ * As soon as a reboot occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_reboot_event(struct notifier_block *this,
+		        unsigned long event, void *ptr)
+{
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+		return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_reboot_block = {
+	notifier_call: pdc_chassis_reboot_event,
+	priority: INT_MAX,
+};
+
+
+/**
+ * parisc_pdc_chassis_init() - Called at boot time.
+ */
+
+void __init parisc_pdc_chassis_init(void)
+{
+	DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
+
+	/* initialize panic notifier chain */
+	notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block);
+
+	/* initialize reboot notifier chain */
+	register_reboot_notifier(&pdc_chassis_reboot_block);
+
+	/* Check for old LED Panel */
+	pdc_chassis_checkold();
+}
+
+
+/** 
+ * pdc_chassis_send_status() - Sends a predefined message to the chassis,
+ * and changes the front panel LEDs according to the new system state
+ * @retval: PDC call return value.
+ *
+ * Only machines with 64 bits PDC PAT and E-class are supported atm.
+ * 
+ * returns 0 if no error, -1 if no supported PDC is present or invalid message,
+ * else returns the appropriate PDC error code.
+ * 
+ * For a list of predefined messages, see asm-parisc/pdc_chassis.h
+ */
+
+int pdc_chassis_send_status(int message)
+{
+	/* Maybe we should do that in an other way ? */
+	int retval = 0;
+
+	DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
+
+#ifdef __LP64__	/* pdc_pat_chassis_send_log is defined only when #ifdef __LP64__ */
+	if (is_pdc_pat()) {
+		switch(message) {
+			case PDC_CHASSIS_DIRECT_BSTART:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_BCOMPLETE:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_SHUTDOWN:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_PANIC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC);
+				break;
+		
+			case PDC_CHASSIS_DIRECT_LPMC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT);
+				break;
+
+			case PDC_CHASSIS_DIRECT_HPMC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT);
+				break;
+
+			default:
+				retval = -1;
+		}
+	} else retval = -1;
+#else
+	if (pdc_chassis_old) {
+		switch (message) {
+			case PDC_CHASSIS_DIRECT_BSTART:
+			case PDC_CHASSIS_DIRECT_BCOMPLETE:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
+				break;
+							
+			case PDC_CHASSIS_DIRECT_SHUTDOWN:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT));
+				break;
+			
+			case PDC_CHASSIS_DIRECT_HPMC:
+			case PDC_CHASSIS_DIRECT_PANIC:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT));
+				break;
+		
+			case PDC_CHASSIS_DIRECT_LPMC:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN));
+				break;
+
+			default:
+				retval = -1;
+		}
+	} else retval = -1;
+#endif
+		
+	return retval;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pdc_cons.c linux-2.4.21-rc3/arch/parisc/kernel/pdc_cons.c
--- linux-2.4.20/arch/parisc/kernel/pdc_cons.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/pdc_cons.c	2003-05-22 22:06:39.000000000 +0000
@@ -51,33 +51,33 @@
 	return 0;
 }
 
-#ifdef CONFIG_PDC_CONSOLE
+#if defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
+#define PDC_CONSOLE_DEVICE pdc_console_device
 static kdev_t pdc_console_device (struct console *c)
 {
-        return MKDEV(PDCCONS_MAJOR, 0);
+        return MKDEV(MUX_MAJOR, 0);
 }
-#endif
-
-#ifdef CONFIG_PDC_CONSOLE
-#define PDC_CONSOLE_DEVICE pdc_console_device
-#else
+#else 
 #define PDC_CONSOLE_DEVICE NULL
 #endif
 
 static struct console pdc_cons = {
 	name:		"ttyB",
 	write:		pdc_console_write,
- 	device:		PDC_CONSOLE_DEVICE,
+#warning UPSTREAM 2.4.19 removed the next 4 lines but we did not
+	read:		NULL,
+	device:		PDC_CONSOLE_DEVICE,
+	unblank:	NULL,
 	setup:		pdc_console_setup,
 	flags:		CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
 	index:		-1,
 };
 
 static int pdc_console_initialized;
-
 extern unsigned long con_start;	/* kernel/printk.c */
 extern unsigned long log_end;	/* kernel/printk.c */
-  
+
+
 static void pdc_console_init_force(void)
 {
 	if (pdc_console_initialized)
@@ -94,7 +94,7 @@
 
 void pdc_console_init(void)
 {
-#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
 	pdc_console_init_force();
 #endif
 #ifdef EARLY_BOOTUP_DEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/power.c linux-2.4.21-rc3/arch/parisc/kernel/power.c
--- linux-2.4.20/arch/parisc/kernel/power.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/power.c	2003-05-22 22:06:28.000000000 +0000
@@ -44,15 +44,12 @@
 #include <linux/reboot.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/ctype.h>
 
 #include <asm/gsc.h>
 #include <asm/pdc.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/led.h>
-#include <asm/led.h>
 #include <asm/uaccess.h>
 
 
@@ -144,11 +141,7 @@
 DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
 
 /* soft power switch enabled/disabled */
-#ifdef CONFIG_PROC_FS
-static int pwrsw_enabled = 1;
-#else
-#define pwrsw_enabled (1)
-#endif
+int pwrsw_enabled = 1;
 
 /*
  * On gecko style machines (e.g. 712/xx and 715/xx) 
@@ -209,90 +202,6 @@
 
 
 
-/* 
- * /proc filesystem support 
- */
-
-#ifdef CONFIG_SYSCTL
-static int power_proc_read(char *page, char **start, off_t off, int count, 
-	int *eof, void *data)
-{
-	char *out = page;
-	int len;
-
-	out += sprintf(out, "Software power switch support: ");
-	out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" );
-	out += sprintf(out, "\n");
-
-	len = out - page - off;
-	if (len < count) {
-		*eof = 1;
-		if (len <= 0) return 0;
-	} else {
-		len = count;
-	}
-	*start = page + off;
-	return len;
-}
-
-static int power_proc_write(struct file *file, const char *buf, 
-	unsigned long count, void *data)
-{
-	char *cur, lbuf[count];
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	memset(lbuf, 0, count);
-
-	copy_from_user(lbuf, buf, count);
-	cur = lbuf;
-
-	/* skip initial spaces */
-	while (*cur && isspace(*cur))
-		cur++;
-
-	switch (*cur) {
-	case '0':	pwrsw_enabled = 0;
-			break;
-	case '1':	pwrsw_enabled = 1;
-			break;
-	default:	printk(KERN_CRIT "/proc/" SYSCTL_FILENAME 
-					": Parse error: only '0' or '1' allowed!\n");
-			return -EINVAL;
-	} /* switch() */
-
-	return count;
-}
-
-static struct proc_dir_entry *ent;
-
-static void __init power_create_procfs(void)
-{
-	if (!power_tasklet.func)
-		return;
-	
-	ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
-	if (!ent) return;
-	
-	ent->nlink = 1;
-	ent->read_proc = power_proc_read;
-	ent->write_proc = power_proc_write;
-	ent->owner = THIS_MODULE;
-}
-
-static void __exit power_remove_procfs(void)
-{
-	remove_proc_entry(SYSCTL_FILENAME, NULL);
-}
-
-#else
-#define power_create_procfs()	do { } while (0)
-#define power_remove_procfs()	do { } while (0)
-#endif	/* CONFIG_SYSCTL */
-
-
-
 /* parisc_panic_event() is called by the panic handler.
  * As soon as a panic occurs, our tasklets above will not be
  * executed any longer. This function then re-enables the 
@@ -346,7 +255,6 @@
 	/* Register a call for panic conditions. */
 	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
 
-	power_create_procfs();
 	tasklet_enable(&power_tasklet);
 
 	return 0;
@@ -359,7 +267,6 @@
 
 	tasklet_disable(&power_tasklet);
 	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
-	power_remove_procfs();
 	power_tasklet.func = NULL;
 	pdc_soft_power_button(0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/process.c linux-2.4.21-rc3/arch/parisc/kernel/process.c
--- linux-2.4.20/arch/parisc/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/process.c	2003-05-22 22:06:53.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/io.h>
 #include <asm/gsc.h>
 #include <asm/processor.h>
+#include <asm/pdc_chassis.h>
 
 int hlt_counter;
 
@@ -118,6 +119,9 @@
 	/* "Normal" system reset */
 	pdc_do_reset();
 
+	/* set up a new led state on systems shipped with a LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+	
 	/* Nope...box should reset with just CMD_RESET now */
 	gsc_writel(CMD_RESET, COMMAND_GLOBAL);
 
@@ -150,6 +154,8 @@
 	 * following call will immediately power off. */
 	pdc_soft_power_button(0);
 
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+	
 	/* It seems we have no way to power the system off via
 	 * software. The user has to press the button himself. */
 
@@ -163,7 +169,7 @@
  */
 
 extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/processor.c linux-2.4.21-rc3/arch/parisc/kernel/processor.c
--- linux-2.4.20/arch/parisc/kernel/processor.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/processor.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,4 +1,4 @@
-/*    $Id: processor.c,v 1.13 2002/07/04 19:33:01 grundler Exp $
+/*    $Id: processor.c,v 1.14 2002/09/13 06:46:28 grundler Exp $
  *
  *    Initial setup-routines for HP 9000 based hardware.
  *
@@ -77,6 +77,8 @@
 	unsigned long txn_addr;
 	unsigned long cpuid;
 	struct cpuinfo_parisc *p;
+	extern struct irq_region_ops cpu_irq_ops; /* arch/parisc...irq.c */
+	extern struct irqaction cpu_irq_actions[]; /* arch/parisc...irq.c */
 
 #ifndef CONFIG_SMP
 	if (boot_cpu_data.cpu_count > 0) {
@@ -167,12 +169,24 @@
 	**	p->state = STATE_RENDEZVOUS;
 	*/
 
-	/*
-	** itimer and ipi IRQ handlers are statically initialized in
-	** arch/parisc/kernel/irq.c. ie Don't need to register them.
-	*/
-	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#if 0
+	/* CPU 0 IRQ table is statically allocated/initialized */
+	if (cpuid) {
+		struct irqaction actions[];
+
+		/*
+		** itimer and ipi IRQ handlers are statically initialized in
+		** arch/parisc/kernel/irq.c. ie Don't need to register them.
+		*/
+		actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC);
+		if (!actions) {
+			/* not getting it's own table, share with monarch */
+			actions = cpu_irq_actions[0];
+		}
 
+		cpu_irq_actions[cpuid] = actions;
+	}
+#endif
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/sba_iommu.c linux-2.4.21-rc3/arch/parisc/kernel/sba_iommu.c
--- linux-2.4.20/arch/parisc/kernel/sba_iommu.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/sba_iommu.c	2003-05-22 22:06:38.000000000 +0000
@@ -812,10 +812,8 @@
 		return(0);
 	}
 
-	dev->dma_mask = mask;	/* save it */
-
 	/* only support 32-bit PCI devices - no DAC support (yet) */
-	return((int) (mask == 0xffffffff));
+	return((int) (mask == 0xffffffffUL));
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/setup.c linux-2.4.21-rc3/arch/parisc/kernel/setup.c
--- linux-2.4.20/arch/parisc/kernel/setup.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/setup.c	2003-05-22 22:06:52.000000000 +0000
@@ -41,6 +41,7 @@
 #include <asm/processor.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
+#include <asm/pdc_chassis.h>
 #include <asm/machdep.h>	/* for pa7300lc_init() proto */
 
 #define COMMAND_LINE_SIZE 1024
@@ -283,6 +284,11 @@
 	parisc_init_resources();
 	do_device_inventory();                  /* probe for hardware */
 
+	parisc_pdc_chassis_init();
+
+	/* set up a new led state on systems shipped LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+	
 	processor_init();
 	printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
 			boot_cpu_data.cpu_count,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/sys_parisc32.c linux-2.4.21-rc3/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.20/arch/parisc/kernel/sys_parisc32.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/sys_parisc32.c	2003-05-22 22:06:40.000000000 +0000
@@ -2759,20 +2759,9 @@
 
 asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	switch (cmd) {
-		case F_GETLK64:
-			cmd = F_GETLK;
-			break;
-		case F_SETLK64:
-			cmd = F_SETLK;
-			break;
-		case F_SETLKW64:
-			cmd = F_SETLKW;
-			break;
-		default:
-			break;
-	}
-	return sys_fcntl(fd, cmd, arg);
+	if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
+		return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
+	return sys32_fcntl(fd, cmd, arg);
 }
 
 asmlinkage int sys32_pread(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/syscall.S linux-2.4.21-rc3/arch/parisc/kernel/syscall.S
--- linux-2.4.20/arch/parisc/kernel/syscall.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/syscall.S	2003-05-22 22:06:53.000000000 +0000
@@ -593,11 +593,18 @@
 	ENTRY_DIFF(ftruncate64)	/* 200 */
 	ENTRY_SAME(getdents64)
 	ENTRY_DIFF(fcntl64)
-	ENTRY_SAME(ni_syscall)		/* attrctl */
-	ENTRY_SAME(ni_syscall)		/* acl_get */
-	ENTRY_SAME(ni_syscall)		/* acl_set */
-	ENTRY_SAME(gettid)
+#ifdef CONFIG_XFS_FS
+	ENTRY_SAME(attrctl)
+	ENTRY_SAME(acl_get)
+	ENTRY_SAME(acl_set)            /* 205 */
+#else
+	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(ni_syscall)	       /* 205 */
+#endif
+	ENTRY_SAME(gettid)             
 	ENTRY_SAME(readahead)          
+	ENTRY_SAME(tkill)
 
 .end
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/traps.c linux-2.4.21-rc3/arch/parisc/kernel/traps.c
--- linux-2.4.20/arch/parisc/kernel/traps.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/traps.c	2003-05-22 22:06:47.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
@@ -34,17 +35,10 @@
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
 
 #include "../math-emu/math-emu.h"	/* for handle_fpe() */
 
-#ifdef CONFIG_KWDB
-#include <kdb/break.h>		/* for BI2_KGDB_GDB */
-#include <kdb/kgdb_types.h>	/* for __() */
-#include <kdb/save_state.h>	/* for struct save_state */
-#include <kdb/kgdb_machine.h>	/* for pt_regs_to_ssp and ssp_to_pt_regs */
-#include <kdb/trap.h>		/* for I_BRK_INST */
-#endif /* CONFIG_KWDB */
-
 #define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
 			  /*  dumped to the console via printk)          */
 
@@ -66,6 +60,99 @@
 #define RFMT "%08lx"
 #endif
 
+static int kstack_depth_to_print = 24;
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+#ifdef CONFIG_MODULES
+	int retval = 0;
+	struct module *mod;
+#endif
+	extern char _stext, _etext;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+#ifdef CONFIG_MODULES
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+	return retval;
+#endif
+}
+
+
+void show_trace(unsigned long * stack)
+{
+	unsigned long *startstack;
+	unsigned long addr;
+	int i;
+
+	startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1));
+	i = 1;
+	printk("Kernel addresses on the stack:\n");
+	while (stack >= startstack) {
+		addr = *stack--;
+		if (kernel_text_address(addr)) {
+			printk(" [<" RFMT ">] ", addr);
+			if ((i & 0x03) == 0)
+				printk("\n");
+			i++;
+		}
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	show_trace((unsigned long *)tsk->thread.regs.ksp);
+}
+
+void show_stack(unsigned long * sp)
+{
+	unsigned long *stack;
+	int i;
+
+	/*
+	 * debugging aid: "show_stack(NULL);" prints the
+	 * back trace for this cpu.
+	 */
+	if (sp==NULL)
+		sp = (unsigned long*)&sp;
+
+	stack = sp;
+	printk("\n" KERN_CRIT "Stack Dump:\n");
+	printk(KERN_CRIT " " RFMT ":  ", (unsigned long) stack);
+	for (i=0; i < kstack_depth_to_print; i++) {
+		if (((long) stack & (THREAD_SIZE-1)) == 0)
+			break;
+		if (i && ((i & 0x03) == 0))
+			printk("\n" KERN_CRIT " " RFMT ":  ",
+				(unsigned long) stack);
+		printk(RFMT " ", *stack--);
+	}
+	printk("\n" KERN_CRIT "\n");
+	show_trace(sp);
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+	show_stack(0);
+}
+
+
 void show_regs(struct pt_regs *regs)
 {
 	int i;
@@ -121,84 +208,6 @@
 }
 
 
-static void dump_stack(unsigned long from, unsigned long to, int istackflag)
-{
-	unsigned int *fromptr;
-	unsigned int *toptr;
-
-	fromptr = (unsigned int *)from;
-	toptr = (unsigned int *)to;
-
-	printk("\n");
-	printk(KERN_CRIT "Dumping %sStack from 0x%p to 0x%p:\n",
-			istackflag ? "Interrupt " : "",
-			fromptr, toptr);
-
-	while (fromptr < toptr) {
-		printk(KERN_CRIT "%04lx %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		    ((unsigned long)fromptr) & 0xffff,
-		    fromptr[0], fromptr[1], fromptr[2], fromptr[3],
-		    fromptr[4], fromptr[5], fromptr[6], fromptr[7]);
-		fromptr += 8;
-	}
-}
-
-
-void show_stack(struct pt_regs *regs)
-{
-#if 1
-	/* If regs->sr[7] == 0, we are on a kernel stack */
-	if (regs->sr[7] == 0) {
-
-		unsigned long sp = regs->gr[30];
-		unsigned long cr30;
-		unsigned long cr31;
-		unsigned long stack_start;
-		struct pt_regs *int_regs;
-
-		cr30 = mfctl(30);
-		cr31 = mfctl(31);
-		stack_start = sp & ~(ISTACK_SIZE - 1);
-		if (stack_start == cr31) {
-		    /*
-		     * We are on the interrupt stack, get the stack
-		     * pointer from the first pt_regs structure on
-		     * the interrupt stack, so we can dump the task
-		     * stack first.
-		     */
-
-		    int_regs = (struct pt_regs *)cr31;
-		    sp = int_regs->gr[30];
-		    stack_start = sp & ~(INIT_TASK_SIZE - 1);
-		    if (stack_start != cr30) {
-			printk(KERN_CRIT "WARNING! Interrupt-Stack pointer and cr30 do not correspond!\n");
-			printk(KERN_CRIT "Dumping virtual address stack instead\n");
-			dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
-		    } else {
-			dump_stack(stack_start, sp, 0);
-		    };
-
-		    printk("\n\n" KERN_DEBUG "Registers at Interrupt:\n");
-		    show_regs(int_regs);
-
-		    /* Now dump the interrupt stack */
-
-		    sp = regs->gr[30];
-		    stack_start = sp & ~(ISTACK_SIZE - 1);
-		    dump_stack(stack_start,sp,1);
-		}
-		else
-		{
-		    /* Stack Dump! */
-		    printk(KERN_CRIT "WARNING! Stack pointer and cr30 do not correspond!\n");
-		    printk(KERN_CRIT "Dumping virtual address stack instead\n");
-		    dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
-		}
-	}
-#endif
-}
-
-
 void die_if_kernel(char *str, struct pt_regs *regs, long err)
 {
 	if (user_mode(regs)) {
@@ -260,9 +269,6 @@
 void handle_break(unsigned iir, struct pt_regs *regs)
 {
 	struct siginfo si;
-#ifdef CONFIG_KWDB
-	struct save_state ssp;
-#endif /* CONFIG_KWDB */   
 
 	switch(iir) {
 	case 0x00:
@@ -285,26 +291,6 @@
 		handle_gdb_break(regs, TRAP_BRKPT);
 		break;
 
-#ifdef CONFIG_KWDB
-	case KGDB_BREAK_INSN:
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_BRK_INST, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-		break;
-
-	case KGDB_INIT_BREAK_INSN:
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_BRK_INST, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-
-		/* Advance pcoq to skip break */
-		regs->iaoq[0] = regs->iaoq[1];
-		regs->iaoq[1] += 4;
-		break;
-#endif /* CONFIG_KWDB */
-
 	default:
 #ifdef PRINT_USER_FAULTS
 		printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
@@ -335,20 +321,6 @@
 void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
 
 
-#ifdef CONFIG_KWDB
-int debug_call (void)
-{
-    printk (KERN_DEBUG "Debug call.\n");
-    return 0;
-}
-
-int debug_call_leaf (void)
-{
-    return 0;
-}
-#endif /* CONFIG_KWDB */
-
-
 void transfer_pim_to_trap_frame(struct pt_regs *regs)
 {
     register int i;
@@ -425,7 +397,7 @@
 
 
 /*
- * This routine handles page faults.  It determines the address,
+ * This routine handles various exception codes.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
@@ -444,10 +416,20 @@
 	if (!console_drivers)
 		pdc_console_restart();
 
-	if (code == 1)
-	    transfer_pim_to_trap_frame(regs);
 
-	show_stack(regs);
+	/* Not all switch paths will gutter the processor... */
+	switch(code){
+
+	case 1:
+		transfer_pim_to_trap_frame(regs);
+		break;
+	    
+	default:
+		/* Fall through */
+		break;
+	}
+
+	show_stack((unsigned long *)regs->gr[30]);
 
 	printk("\n");
 	printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
@@ -461,32 +443,34 @@
 	 * system will shut down immediately right here. */
 	pdc_soft_power_button(0);
 	
+	/* Gutter the processor... */
 	for(;;)
 	    ;
 }
 
+
 void handle_interruption(int code, struct pt_regs *regs)
 {
 	unsigned long fault_address = 0;
 	unsigned long fault_space = 0;
 	struct siginfo si;
-#ifdef CONFIG_KWDB
-	struct save_state ssp;
-#endif /* CONFIG_KWDB */   
-
-	if (code == 1)
-	    pdc_console_restart();  /* switch back to pdc if HPMC */
-	else
-	    sti();
 
-#if 0
-	printk(KERN_CRIT "Interruption # %d\n", code);
-#endif
+	/* HACK! jsm is going to fix this.
+	 * entry.S will manage I-bit - only enable I-bit if it was
+	 * enabled before we took the "trap".
+	 */
+	if (code != 1)
+		local_irq_enable();
 
 	switch(code) {
 
 	case  1:
 		/* High-priority machine check (HPMC) */
+		pdc_console_restart();  /* switch back to pdc if HPMC */
+
+		/* set up a new led state on systems shipped with a LED State panel */
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
+
 		parisc_terminate("High Priority Machine Check (HPMC)",
 				regs, code, 0);
 		/* NOT REACHED */
@@ -506,6 +490,9 @@
 
 	case  5:
 		/* Low-priority machine check */
+
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
+
 		flush_all_caches();
 		cpu_lpmc(5, regs);
 		return;
@@ -554,6 +541,7 @@
 
 		die_if_kernel("Privileged register usage", regs, code);
 		si.si_code = ILL_PRVREG;
+		/* Fall thru */
 	give_sigill:
 		si.si_signo = SIGILL;
 		si.si_errno = 0;
@@ -561,17 +549,47 @@
 		force_sig_info(SIGILL, &si, current);
 		return;
 
+	case 12:
+		/* Overflow Trap, let the userland signal handler do the cleanup */
+		si.si_signo = SIGFPE;
+		si.si_code = FPE_INTOVF;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGFPE, &si, current);
+		return;
+	
+	case 13:
+		/* Conditional Trap 
+		   The condition succees in an instruction which traps on condition  */
+		si.si_signo = SIGFPE;
+		/* Set to zero, and let the userspace app figure it out from
+		   the insn pointed to by si_addr */
+		si.si_code = 0;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGFPE, &si, current);
+		return;
+
 	case 14:
 		/* Assist Exception Trap, i.e. floating point exception. */
 		die_if_kernel("Floating point exception", regs, 0); /* quiet */
 		handle_fpe(regs);
 		return;
 
+	case 15: 
+		/* Data TLB miss fault/Data page fault */	
+		/* Fall thru */
+	case 16:
+		/* Non-access instruction TLB miss fault */
+		/* The instruction TLB entry needed for the target address of the FIC
+		   is absent, and hardware can't find it, so we get to cleanup */
+		/* Fall thru */
 	case 17:
 		/* Non-access data TLB miss fault/Non-access data page fault */
 		/* TODO: Still need to add slow path emulation code here */
+		/* TODO: Understand what is meant by the TODO listed 
+		   above this one. (Carlos) */
 		fault_address = regs->ior;
-		parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
+		fault_space = regs->isr;
+		break;
 
 	case 18:
 		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
@@ -581,9 +599,8 @@
 			return;
 		}
 		/* Fall Through */
-
-	case 15: /* Data TLB miss fault/Data page fault */
-	case 26: /* PCXL: Data memory access rights trap */
+	case 26: 
+		/* PCXL: Data memory access rights trap */
 		fault_address = regs->ior;
 		fault_space   = regs->isr;
 		break;
@@ -599,7 +616,6 @@
 
 	case 25:
 		/* Taken branch trap */
-#ifndef CONFIG_KWDB
 		regs->gr[0] &= ~PSW_T;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_BRANCH);
@@ -607,14 +623,6 @@
 		 * run.
 		 */
 		return;
-#else
-		/* Kernel debugger: */
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_TAKEN_BR, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-		break;
-#endif /* CONFIG_KWDB */
 
 	case  7:  
 		/* Instruction access rights */
@@ -648,7 +656,6 @@
 			up_read(&current->mm->mmap_sem);
 		}
 		/* Fall Through */
-
 	case 27: 
 		/* Data memory protection ID trap */
 		die_if_kernel("Protection id trap", regs, code);
@@ -682,6 +689,9 @@
 			force_sig_info(SIGBUS, &si, current);
 			return;
 		}
+		
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+
 		parisc_terminate("Unexpected interruption", regs, code, 0);
 		/* NOT REACHED */
 	}
@@ -710,24 +720,17 @@
 	     * The kernel should never fault on its own address space.
 	     */
 
-	    if (fault_space == 0)
-		    parisc_terminate("Kernel Fault", regs, code, fault_address);
+	    if (fault_space == 0) {
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+		parisc_terminate("Kernel Fault", regs, code, fault_address);
+		/** NOT REACHED **/
+	    }
 	}
 
-#ifdef CONFIG_KWDB
-	debug_call_leaf ();
-#endif /* CONFIG_KWDB */
-
 	do_page_fault(regs, code, fault_address);
 }
 
 
-void show_trace_task(struct task_struct *tsk)
-{
-    	BUG();
-}
-
-
 
 int __init check_ivt(void *iva)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/unaligned.c linux-2.4.21-rc3/arch/parisc/kernel/unaligned.c
--- linux-2.4.20/arch/parisc/kernel/unaligned.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/kernel/unaligned.c	2003-05-22 22:06:28.000000000 +0000
@@ -1,4 +1,4 @@
-/*    $Id: unaligned.c,v 1.9 2001/10/04 03:31:08 tausq Exp $
+/*    $Id: unaligned.c,v 1.10 2002/09/22 02:21:05 tausq Exp $
  *
  *    Unaligned memory access handler
  *
@@ -108,7 +108,7 @@
 #define OPCODE_STW_L    OPCODE4(0x1A)
 #define OPCODE_STW_L2   OPCODE4(0x1B)
 
-
+int unaligned_enabled = 1;
 
 void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
@@ -281,6 +281,9 @@
 		}
 	}
 
+	if (!unaligned_enabled)
+		goto force_sigbus;
+
 	/* TODO: make this cleaner... */
 	switch (regs->iir & OPCODE1_MASK)
 	{
@@ -368,7 +371,7 @@
 	{
 		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
 		die_if_kernel("Unaligned data reference", regs, 28);
-
+force_sigbus:
 		/* couldn't handle it ... */
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;
@@ -432,3 +435,4 @@
 
 	return (int)(regs->ior & align_mask);
 }
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/lib/Makefile linux-2.4.21-rc3/arch/parisc/lib/Makefile
--- linux-2.4.20/arch/parisc/lib/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/lib/Makefile	2003-05-22 22:06:48.000000000 +0000
@@ -6,4 +6,6 @@
 L_TARGET = lib.a
 obj-y	:= lusercopy.o bitops.o checksum.o io.o memset.o
 
+obj-$(CONFIG_SMP) += locks.o
+
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/lib/locks.c linux-2.4.21-rc3/arch/parisc/lib/locks.c
--- linux-2.4.20/arch/parisc/lib/locks.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/lib/locks.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * debugging spinlocks for parisc
+ * 
+ * Adapted from the ppc version
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000 /*0xffffffff*/
+
+#define __spin_trylock(x) (__ldcw(&(x)->lock) != 0)
+
+void spin_lock(spinlock_t *lock)
+{
+	int cpu = smp_processor_id();
+	unsigned int stuck = INIT_STUCK;
+	while (!__spin_trylock(lock)) {
+		while ((unsigned volatile long)lock->lock == 0) {
+			if (!--stuck) {
+				printk("spin_lock(%p) CPU#%d NIP %p"
+				       " holder: cpu %ld pc %08lX\n",
+				       lock, cpu, __builtin_return_address(0),
+				       lock->owner_cpu,lock->owner_pc);
+				stuck = INIT_STUCK;
+				/* steal the lock */
+				/*xchg_u32((void *)&lock->lock,0);*/
+			}
+		}
+	}
+	lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	lock->owner_cpu = cpu;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+	if (!__spin_trylock(lock))
+		return 0;
+	lock->owner_cpu = smp_processor_id(); 
+	lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	return 1;
+}
+
+void spin_unlock(spinlock_t *lp)
+{
+  	if ( lp->lock )
+		printk("spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n",
+		       lp, smp_processor_id(), __builtin_return_address(0),
+		       current->comm, current->pid);
+	if ( lp->owner_cpu != smp_processor_id() )
+		printk("spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %x\n",
+		      lp, smp_processor_id(), (int)lp->owner_cpu,
+		      lp->owner_pc,lp->lock);
+	lp->owner_pc = lp->owner_cpu = 0;
+	wmb();
+	lp->lock = 1;
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/mm/fault.c linux-2.4.21-rc3/arch/parisc/mm/fault.c
--- linux-2.4.20/arch/parisc/mm/fault.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/mm/fault.c	2003-05-22 22:06:51.000000000 +0000
@@ -257,7 +257,8 @@
 	}
 
 	parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
-
+	/* NOT REACHED! */
+	
   out_of_memory:
 	up_read(&mm->mmap_sem);
 	printk(KERN_CRIT "VM: killing process %s\n", current->comm);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/mm/init.c linux-2.4.21-rc3/arch/parisc/mm/init.c
--- linux-2.4.20/arch/parisc/mm/init.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/mm/init.c	2003-05-22 22:06:46.000000000 +0000
@@ -21,6 +21,7 @@
 
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
+#include <asm/pdc_chassis.h>
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
@@ -409,6 +410,9 @@
 	}
 
 	printk("%luk freed\n", (unsigned long)(&__init_end - &__init_begin) >> 10);
+
+	/* set up a new led state on systems shipped LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
 }
 
 /*
@@ -574,13 +578,8 @@
 			for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
 				pte_t pte;
 
-#if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
+#if !defined(CONFIG_STI_CONSOLE)
 #warning STI console should explicitly allocate executable pages but does not
-/* KWDB needs to write kernel text when setting break points.
-**
-** The right thing to do seems like KWDB modify only the pte which
-** has a break point on it...otherwise we might mask worse bugs.
-*/
 				/*
 				 * Map the fault vector writable so we can
 				 * write the HPMC checksum.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/vmlinux.lds linux-2.4.21-rc3/arch/parisc/vmlinux.lds
--- linux-2.4.20/arch/parisc/vmlinux.lds	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/vmlinux.lds	2003-05-22 22:06:28.000000000 +0000
@@ -14,12 +14,12 @@
 	*(.gnu.warning)
 	} = 0
 
+  _etext = .;			/* End of text section */
+  
   . = ALIGN(16);
   .rodata : { *(.rodata) *(.rodata.*) }
   .kstrtab : { *(.kstrtab) }
 
-  _etext = .;			/* End of text section */
-  
   .data BLOCK(8192) : {			/* Data without special */
 	data_start = .;
 	*(.data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/vmlinux64.lds linux-2.4.21-rc3/arch/parisc/vmlinux64.lds
--- linux-2.4.20/arch/parisc/vmlinux64.lds	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/parisc/vmlinux64.lds	2003-05-22 22:06:27.000000000 +0000
@@ -15,12 +15,12 @@
 	*(.gnu.warning)
 	} = 0
 
+  _etext = .;			/* End of text section */
+
   . = ALIGN(16);
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
-  _etext = .;			/* End of text section */
-  
   .data BLOCK(8192) : {			/* Data without special */
 	data_start = .;
 	*(.data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/Config.in linux-2.4.21-rc3/arch/ppc/8260_io/Config.in
--- linux-2.4.20/arch/ppc/8260_io/Config.in	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/Config.in	2003-05-22 22:06:25.000000000 +0000
@@ -23,7 +23,4 @@
     bool 'Ethernet on FCC3' CONFIG_FCC3_ENET
   fi
 fi
-
-comment 'Generic MPC8260 Options'
-bool 'Disable data cache' CONFIG_DCACHE_DISABLE
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/Makefile linux-2.4.21-rc3/arch/ppc/8260_io/Makefile
--- linux-2.4.20/arch/ppc/8260_io/Makefile	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/Makefile	2003-05-22 22:06:50.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/commproc.c linux-2.4.21-rc3/arch/ppc/8260_io/commproc.c
--- linux-2.4.20/arch/ppc/8260_io/commproc.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/commproc.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.10 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * 8260 Communication Processor Module.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/enet.c linux-2.4.21-rc3/arch/ppc/8260_io/enet.c
--- linux-2.4.20/arch/ppc/8260_io/enet.c	2001-10-08 18:40:13.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/enet.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.enet.c 1.9 09/14/01 18:01:16 trini
- */
-/*
  * Ethernet driver for Motorola MPC8260.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com)
@@ -810,7 +807,7 @@
 
 	/* Install our interrupt handler.
 	*/
-	request_8xxirq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev);
+	request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev);
 
 	/* Set GSMR_H to enable all normal operating modes.
 	 * Set GSMR_L to enable Ethernet to MC68160.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/fcc_enet.c linux-2.4.21-rc3/arch/ppc/8260_io/fcc_enet.c
--- linux-2.4.20/arch/ppc/8260_io/fcc_enet.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/fcc_enet.c	2003-05-22 22:06:43.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.fcc_enet.c 1.7 05/17/01 18:14:20 cort
- */
-/*
  * Fast Ethernet Controller (FCC) driver for Motorola MPC8260.
  * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
  *
@@ -1442,8 +1439,8 @@
 
 	/* Install our interrupt handler.
 	*/
-	if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0,
-							"fenet", dev) < 0)
+	if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet",
+				dev) < 0)
 		printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);
 
 	/* Set GFMR to enable Ethernet operating mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/uart.c linux-2.4.21-rc3/arch/ppc/8260_io/uart.c
--- linux-2.4.20/arch/ppc/8260_io/uart.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8260_io/uart.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uart.c 1.13 12/29/01 14:50:03 trini
- */
-/*
  *  UART driver for MPC8260 CPM SCC or SMC
  *  Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *  Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com)
@@ -2594,7 +2591,8 @@
 
 			/* Install interrupt handler.
 			*/
-			request_8xxirq(state->irq, rs_8xx_interrupt, 0, "uart", info);
+			request_irq(state->irq, rs_8xx_interrupt, 0, "uart",
+					info);
 
 			/* Set up the baud rate generator.
 			*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/Makefile linux-2.4.21-rc3/arch/ppc/8xx_io/Makefile
--- linux-2.4.20/arch/ppc/8xx_io/Makefile	2001-09-08 19:39:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8xx_io/Makefile	2003-05-22 22:06:42.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.6 08/30/01 09:33:48 trini
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/commproc.c linux-2.4.21-rc3/arch/ppc/8xx_io/commproc.c
--- linux-2.4.20/arch/ppc/8xx_io/commproc.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8xx_io/commproc.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.15 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
@@ -31,7 +27,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
 #include <asm/mpc8xx.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -47,14 +43,65 @@
 cpm8xx_t	*cpmp;		/* Pointer to comm processor space */
 
 /* CPM interrupt vector functions.
-*/
+ *
+ * The cpm_vecs structure is only needed to support the cpm_install_handler()
+ * mechanism of installing CPM interrupt handlers.
+ */
 struct	cpm_action {
 	void	(*handler)(void *, struct pt_regs * regs);
 	void	*dev_id;
 };
 static	struct	cpm_action cpm_vecs[CPMVEC_NR];
 static	void	cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static	void	cpm_error_interrupt(void *, struct pt_regs * regs);
+static	void	cpm_error_interrupt(int irq, void *, struct pt_regs * regs);
+
+/* Define a table of names to identify CPM interrupt handlers in
+ * /proc/interrupts.
+ */
+const char *cpm_int_name[] =
+	{ "error",	"PC4",		"PC5",		"SMC2",
+	  "SMC1",	"SPI",		"PC6",		"Timer 4",
+	  "",		"PC7",		"PC8",		"PC9",
+	  "Timer 3",	"",		"PC10",		"PC11",
+	  "I2C",	"RISC Timer",	"Timer 2",	"",
+	  "IDMA2",	"IDMA1",	"SDMA error",	"PC12",
+	  "PC13",	"Timer 1",	"PC14",		"SCC4",
+	  "SCC3",	"SCC2",		"SCC1",		"PC15"
+	};
+
+static void
+cpm_mask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec);
+}
+
+static void
+cpm_unmask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec);
+}
+
+static void
+cpm_eoi(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec);
+}
+
+struct hw_interrupt_type cpm_pic = {
+	" CPM      ",
+	NULL,
+	NULL,
+	cpm_unmask_irq,
+	cpm_mask_irq,
+	NULL,
+	cpm_eoi
+};
 
 void
 m8xx_cpm_reset(uint host_page_addr)
@@ -118,6 +165,8 @@
 void
 cpm_interrupt_init(void)
 {
+	int i;
+
 	/* Initialize the CPM interrupt controller.
 	*/
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
@@ -125,41 +174,54 @@
 		((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
 
+        /* install the CPM interrupt controller routines for the CPM
+         * interrupt vectors
+         */
+        for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
+                irq_desc[i].handler = &cpm_pic;
+
 	/* Set our interrupt handler with the core CPU.
 	*/
-	if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+	if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "CPM cascade",
+				NULL) != 0)
 		panic("Could not allocate CPM IRQ!");
 
 	/* Install our own error handler.
 	*/
-	cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+	if (request_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, cpm_error_interrupt,
+				0, cpm_int_name[CPMVEC_ERROR], NULL) != 0)
+		panic("Could not allocate CPM error IRQ!");
+
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
 }
 
-/* CPM interrupt controller interrupt.
-*/
-static	void
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+/*
+ * Get the CPM interrupt vector.
+ */
+int
+cpm_get_irq(struct pt_regs *regs)
 {
-	uint	vec;
+	int cpm_vec;
 
 	/* Get the vector by setting the ACK bit and then reading
 	 * the register.
 	 */
 	((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
-	vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
-	vec >>= 11;
+	cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
+	cpm_vec >>= 11;
 
-	if (cpm_vecs[vec].handler != 0)
-		(*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs);
-	else
-		((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	return cpm_vec;
+}
 
-	/* After servicing the interrupt, we have to remove the status
-	 * indicator.
+/* CPM interrupt controller cascade interrupt.
+*/
+static	void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	/* This interrupt handler never actually gets called.  It is
+	 * installed only to unmask the CPM cascade interrupt in the SIU
+	 * and to make the CPM cascade interrupt visible in /proc/interrupts.
 	 */
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec);
-	
 }
 
 /* The CPM can generate the error interrupt when there is a race condition
@@ -168,40 +230,69 @@
  * tests in the interrupt handler.
  */
 static	void
-cpm_error_interrupt(void *dev, struct pt_regs *regs)
+cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
 }
 
+/* A helper function to translate the handler prototype required by
+ * request_irq() to the handler prototype required by cpm_install_handler().
+ */
+static void
+cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	(*cpm_vecs[cpm_vec].handler)(dev_id, regs);
+}
+
 /* Install a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.  Rather than using
+ * this routine to install a CPM interrupt handler, you can now use
+ * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
+ * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
+ *
+ * Notice that the prototype of the interrupt handler function must be
+ * different depending on whether you install the handler with
+ * request_irq() or cpm_install_handler().
+ */
 void
-cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs),
+cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
 		    void *dev_id)
 {
+	int err;
 
 	/* If null handler, assume we are trying to free the IRQ.
 	*/
 	if (!handler) {
-		cpm_free_handler(vec);
+		free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
 		return;
 	}
 
-	if (cpm_vecs[vec].handler != 0)
-		printk("CPM interrupt %x replacing %x\n",
-			(uint)handler, (uint)cpm_vecs[vec].handler);
-	cpm_vecs[vec].handler = handler;
-	cpm_vecs[vec].dev_id = dev_id;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
+	if (cpm_vecs[cpm_vec].handler != 0)
+		printk(KERN_INFO "CPM interrupt %x replacing %x\n",
+			(uint)handler, (uint)cpm_vecs[cpm_vec].handler);
+	cpm_vecs[cpm_vec].handler = handler;
+	cpm_vecs[cpm_vec].dev_id = dev_id;
+
+	if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
+					0, cpm_int_name[cpm_vec], dev_id)))
+		printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
+				err, cpm_vec);
 }
 
 /* Free a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.
+ */
 void
-cpm_free_handler(int vec)
+cpm_free_handler(int cpm_vec)
 {
-	cpm_vecs[vec].handler = NULL;
-	cpm_vecs[vec].dev_id = NULL;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
+		cpm_vecs[cpm_vec].dev_id);
+
+	cpm_vecs[cpm_vec].handler = NULL;
+	cpm_vecs[cpm_vec].dev_id = NULL;
 }
 
 /* Allocate some memory from the dual ported ram.  We may want to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/enet.c linux-2.4.21-rc3/arch/ppc/8xx_io/enet.c
--- linux-2.4.20/arch/ppc/8xx_io/enet.c	2001-10-17 21:37:01.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8xx_io/enet.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.enet.c 1.17 10/11/01 11:55:47 trini
- */
-/*
  * Ethernet driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -48,6 +45,7 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
+#include <asm/irq.h>
 
 /*
  *				Theory of Operation
@@ -140,14 +138,13 @@
 	cbd_t	*dirty_tx;	/* The ring entries to be free()ed. */
 	scc_t	*sccp;
 	struct	net_device_stats stats;
-	uint	tx_full;
+	uint	tx_free;
 	spinlock_t lock;
 };
 
 static int scc_enet_open(struct net_device *dev);
 static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int scc_enet_rx(struct net_device *dev);
-static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs);
 static int scc_enet_close(struct net_device *dev);
 static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -201,9 +198,9 @@
 	bdp = cep->cur_tx;
 
 #ifndef final_version
-	if (bdp->cbd_sc & BD_ENET_TX_READY) {
+	if (!cep->tx_free || (bdp->cbd_sc & BD_ENET_TX_READY)) {
 		/* Ooops.  All transmit buffers are full.  Bail out.
-		 * This should not happen, since cep->tx_busy should be set.
+		 * This should not happen, since the tx queue should be stopped.
 		 */
 		printk("%s: tx queue full!.\n", dev->name);
 		return 1;
@@ -255,10 +252,8 @@
 	else
 		bdp++;
 
-	if (bdp->cbd_sc & BD_ENET_TX_READY) {
+	if (!--cep->tx_free)
 		netif_stop_queue(dev);
-		cep->tx_full = 1;
-	}
 
 	cep->cur_tx = (cbd_t *)bdp;
 
@@ -278,8 +273,8 @@
 	{
 		int	i;
 		cbd_t	*bdp;
-		printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
-		       cep->cur_tx, cep->tx_full ? " (full)" : "",
+		printk(" Ring data dump: cur_tx %p tx_free %d cur_rx %p.\n",
+		       cep->cur_tx, cep->tx_free,
 		       cep->cur_rx);
 		bdp = cep->tx_bd_base;
 		for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
@@ -295,7 +290,7 @@
 			       bdp->cbd_bufaddr);
 	}
 #endif
-	if (!cep->tx_full)
+	if (cep->tx_free)
 		netif_wake_queue(dev);
 }
 
@@ -303,7 +298,7 @@
  * This is called from the CPM handler, not the MPC core interrupt.
  */
 static void
-scc_enet_interrupt(void *dev_id, struct pt_regs *regs)
+scc_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct	net_device *dev = dev_id;
 	volatile struct	scc_enet_private *cep;
@@ -339,7 +334,7 @@
 	    spin_lock(&cep->lock);
 	    bdp = cep->dirty_tx;
 	    while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
-		if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+		if (cep->tx_free == TX_RING_SIZE)
 		    break;
 
 		if (bdp->cbd_sc & BD_ENET_TX_HB)	/* No heartbeat */
@@ -395,8 +390,7 @@
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
-		if (cep->tx_full) {
-			cep->tx_full = 0;
+		if (!cep->tx_free++) {
 			if (netif_queue_stopped(dev))
 				netif_wake_queue(dev);
 		}
@@ -422,13 +416,10 @@
 	}
 
 	/* Check for receive busy, i.e. packets coming but no place to
-	 * put them.  This "can't happen" because the receive interrupt
-	 * is tossing previous frames.
+	 * put them.
 	 */
-	if (int_events & SCCE_ENET_BSY) {
+	if (int_events & SCCE_ENET_BSY)
 		cep->stats.rx_dropped++;
-		printk("CPM ENET: BSY can't happen.\n");
-	}
 
 	return;
 }
@@ -752,6 +743,7 @@
 	cep->tx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
 
 	cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
+	cep->tx_free = TX_RING_SIZE;
 	cep->cur_rx = cep->rx_bd_base;
 
 	/* Issue init Rx BD command for SCC.
@@ -880,7 +872,9 @@
 
 	/* Install our interrupt handler.
 	*/
-	cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev);
+	if ((request_irq(CPM_IRQ_OFFSET + CPMVEC_ENET, scc_enet_interrupt,
+			0, cpm_int_name[CPMVEC_ENET], dev)) != 0)
+		panic("Could not allocate SCC ethernet IRQ!");
 
 	/* Set GSMR_H to enable all normal operating modes.
 	 * Set GSMR_L to enable Ethernet to MC68160.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/fec.c linux-2.4.21-rc3/arch/ppc/8xx_io/fec.c
--- linux-2.4.20/arch/ppc/8xx_io/fec.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8xx_io/fec.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -1365,11 +1362,7 @@
 /* This interrupt occurs when the PHY detects a link change.
 */
 static void
-#ifdef CONFIG_RPXCLASSIC
-mii_link_interrupt(void *dev_id)
-#else
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
-#endif
 {
 #ifdef	CONFIG_USE_MDIO
 	struct	net_device *dev = dev_id;
@@ -1815,7 +1808,7 @@
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	/* Install our interrupt handler. */
-	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
+	if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
 
 #ifdef CONFIG_RPXCLASSIC
@@ -1825,7 +1818,9 @@
 	immap->im_ioport.iop_pcdir &= ~0x0001;
 	immap->im_ioport.iop_pcso  &= ~0x0001;
 	immap->im_ioport.iop_pcint |=  0x0001;
-	cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);
+	if (request_irq(CPM_IRQ_OFFSET + CPMVEC_PIO_PC15, mii_link_interrupt,
+			0, cpm_int_name[CPMVEC_PIO_PC15], dev) != 0)
+		panic("Could not allocate Port C FEC IRQ!");
 
 	/* Make LEDS reflect Link status.
 	*/
@@ -1836,7 +1831,7 @@
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
 		(0x80000000 >> PHY_INTERRUPT);
 
-	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
+	if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
 		panic("Could not allocate MII IRQ!");
 #endif
 
@@ -1906,9 +1901,9 @@
 	fep->phy_id_done = 0;
 	fep->phy_addr = 0;
 	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
-#endif	/* CONFIG_USE_MDIO */
 
 	fep->old_status = 0;
+#endif	/* CONFIG_USE_MDIO */
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/uart.c linux-2.4.21-rc3/arch/ppc/8xx_io/uart.c
--- linux-2.4.20/arch/ppc/8xx_io/uart.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/8xx_io/uart.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uart.c 1.23 12/29/01 14:50:03 trini
- */
-/*
  *  UART driver for MPC860 CPM SCC or SMC
  *  Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -44,15 +41,13 @@
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
 #include <asm/commproc.h>
+#include <asm/irq.h>
+#include <asm/kgdb.h>
 #ifdef CONFIG_MAGIC_SYSRQ
 #include <linux/sysrq.h>
 #endif
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int  kgdb_output_string (const char* s, unsigned int count);
-#endif
+extern int kgdb_output_string (const char* s, unsigned int count);
 
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
@@ -134,6 +129,18 @@
 #define smc_scc_num	hub6
 #define NUM_IS_SCC	((int)0x00010000)
 #define PORT_NUM(P)	((P) & 0x0000ffff)
+#define PORT_IS_SCC(P)	((P) & NUM_IS_SCC)
+
+/* The serial port to use for KGDB. */
+#ifdef CONFIG_KGDB_TTYS1
+#define KGDB_SER_IDX	1	/* SCC1/SMC1 */
+#elif CONFIG_KGDB_TTYS2
+#define KGDB_SER_IDX	2	/* SCC2/SMC2 */
+#elif CONFIG_KGDB_TTYS3
+#define KGDB_SER_IDX	3	/* SCC4/SMC4 (future?) */
+#else				/* Unset, or ttyS0, use SCC1/SMC1 */
+#define KGDB_SER_IDX	0
+#endif
 
 /* Processors other than the 860 only get SMCs configured by default.
  * Either they don't have SCCs or they are allocated somewhere else.
@@ -277,7 +284,7 @@
 	
 	save_flags(flags); cli();
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_sccm &= ~UART_SCCM_TX;
 	}
@@ -301,7 +308,7 @@
 	
 	idx = PORT_NUM(info->state->smc_scc_num);
 	save_flags(flags); cli();
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_sccm |= UART_SCCM_TX;
 	}
@@ -390,6 +397,14 @@
 		cp = (unsigned char *)__va(bdp->cbd_bufaddr);
 		status = bdp->cbd_sc;
 
+#ifdef CONFIG_KGDB
+		if (info->state->smc_scc_num == KGDB_SER_IDX) {
+			if (*cp == 0x03 || *cp == '$')
+				breakpoint();
+			return;
+		}
+#endif
+
 		/* Check to see if there is room in the tty buffer for
 		 * the characters in our BD buffer.  If not, we exit
 		 * now, leaving the BD with the characters.  We'll pick
@@ -615,7 +630,7 @@
 /*
  * This is the serial driver's interrupt routine for a single port
  */
-static void rs_8xx_interrupt(void *dev_id, struct pt_regs *regs)
+static void rs_8xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	u_char	events;
 	int	idx;
@@ -626,7 +641,7 @@
 	info = (ser_info_t *)dev_id;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		events = sccp->scc_scce;
 		if (events & SMCM_BRKE)
@@ -772,7 +787,7 @@
 	change_speed(info);
 	
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		scup = (scc_uart_t *)&cpmp->cp_dparam[state->port];
 		scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
@@ -836,7 +851,7 @@
 	save_flags(flags); cli(); /* Disable interrupts */
 
 	idx = PORT_NUM(state->smc_scc_num);
-	if (state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -991,7 +1006,7 @@
 	 */
 	bits++;
 	idx = PORT_NUM(state->smc_scc_num);
-	if (state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		new_mode = (sbits << 12) | scval;
 		prev_mode = sccp->scc_pmsr;
@@ -1059,7 +1074,7 @@
 	ser_info_t *info = (ser_info_t *)tty->driver_data;
 	volatile cbd_t *bdp;
 
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_KGDB_CONSOLE
         /* Try to let stub handle output. Returns true if it did. */ 
         if (kgdb_output_string(buf, count))
             return ret;
@@ -1390,7 +1405,7 @@
 	cp = cpmp;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
+	if (PORT_IS_SCC(info->state->smc_scc_num))
 		chan = scc_chan_map[idx];
 	else
 		chan = smc_chan_map[idx];
@@ -1407,7 +1422,7 @@
 	cp = cpmp;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
+	if (PORT_IS_SCC(info->state->smc_scc_num))
 		chan = scc_chan_map[idx];
 	else
 		chan = smc_chan_map[idx];
@@ -1712,7 +1727,7 @@
 	info->read_status_mask &= ~BD_SC_EMPTY;
 	if (info->flags & ASYNC_INITIALIZED) {
 		idx = PORT_NUM(info->state->smc_scc_num);
-		if (info->state->smc_scc_num & NUM_IS_SCC) {
+		if (PORT_IS_SCC(info->state->smc_scc_num)) {
 			sccp = &cpmp->cp_scc[idx];
 			sccp->scc_sccm &= ~UART_SCCM_RX;
 			sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
@@ -1903,7 +1918,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR)) ||
-	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
+	    !(PORT_IS_SCC(info->state->smc_scc_num))) {
 		if (info->flags & ASYNC_CALLOUT_ACTIVE)
 			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
@@ -2081,7 +2096,7 @@
 
 	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
 		      state->line,
-		      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
+		      (PORT_IS_SCC(state->smc_scc_num)) ? "SCC" : "SMC",
 		      (unsigned int)(state->port), state->irq);
 
 	if (!state->port || (state->type == PORT_UNKNOWN)) {
@@ -2302,7 +2317,7 @@
 static void serial_console_write(struct console *c, const char *s,
 				unsigned count)
 {
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_KGDB_CONSOLE
 	/* Try to let stub handle output. Returns true if it did. */ 
 	if (kgdb_output_string(s, count))
 		return;
@@ -2319,14 +2334,7 @@
 }
 #endif
 
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
-	my_console_write(0, &ch, 1);
-}
-#endif
-
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
 /*
  * Receive character from the serial port.  This only works well
  * before the port is initialized for real use.
@@ -2399,6 +2407,7 @@
 
 	return((int)c);
 }
+#endif /* CONFIG_KGDB || CONFIG_XMON */
 
 #ifdef CONFIG_XMON
 int
@@ -2418,7 +2427,13 @@
 static char kgdb_buf[RX_BUF_SIZE], *kgdp;
 static int kgdb_chars;
 
-unsigned char
+void
+putDebugChar(char ch)
+{
+	my_console_write(0, &ch, 1);
+}
+
+char
 getDebugChar(void)
 {
 	if (kgdb_chars <= 0) {
@@ -2430,9 +2445,18 @@
 	return(*kgdp++);
 }
 
-void kgdb_interruptible(int state)
+void kgdb_interruptible(int yes)
 {
+	volatile smc_t	*smcp;
+
+	smcp = &cpmp->cp_smc[KGDB_SER_IDX];
+
+	if (yes == 1)
+		smcp->smc_smcm |= SMCM_RX;
+	else
+		smcp->smc_smcm &= ~SMCM_RX;
 }
+
 void kgdb_map_scc(void)
 {
 	struct		serial_state *ser;
@@ -2459,7 +2483,7 @@
 	/* Allocate space for an input FIFO, plus a few bytes for output.
 	 * Allocate bytes to maintain word alignment.
 	 */
-	mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+	mem_addr = (uint)(&cpmp->cp_dpmem[0xa00]);
 
 	/* Set the physical address of the host memory buffers in
 	 * the buffer descriptors.
@@ -2489,7 +2513,7 @@
 	return kmem_start;
 }
 
-#endif
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 /* Index in baud rate table of the default console baud rate.
 */
@@ -2646,7 +2670,7 @@
 		state->icount.overrun = state->icount.brk = 0;
 		printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
 		       i, (unsigned int)(state->port),
-		       (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
+		       PORT_IS_SCC(state->smc_scc_num) ? "SCC" : "SMC");
 #ifdef CONFIG_SERIAL_CONSOLE
 		/* If we just printed the message on the console port, and
 		 * we are about to initialize it for general use, we have
@@ -2698,7 +2722,7 @@
 			bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
 
 			idx = PORT_NUM(info->state->smc_scc_num);
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
+			if (PORT_IS_SCC(info->state->smc_scc_num)) {
 				scp = &cp->cp_scc[idx];
 				sup = (scc_uart_t *)&cp->cp_dparam[state->port];
 				sup->scc_genscc.scc_rbase = dp_addr;
@@ -2731,7 +2755,7 @@
 			bdp->cbd_bufaddr = __pa(mem_addr);
 			bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
 
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
+			if (PORT_IS_SCC(info->state->smc_scc_num)) {
 				sup->scc_genscc.scc_tbase = dp_addr;
 
 				/* Set up the uart parameters in the
@@ -2874,7 +2898,8 @@
 
 			/* Install interrupt handler.
 			*/
-			cpm_install_handler(state->irq, rs_8xx_interrupt, info);
+			if ((request_irq(CPM_IRQ_OFFSET + state->irq, rs_8xx_interrupt, 0, cpm_int_name[state->irq], info)) != 0)
+				panic("Could not allocate UART IRQ!");
 
 			/* Set up the baud rate generator.
 			*/
@@ -2919,7 +2944,7 @@
 	cp = cpmp;	/* Get pointer to Communication Processor */
 
 	idx = PORT_NUM(ser->smc_scc_num);
-	if (ser->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(ser->smc_scc_num)) {
 		scp = &cp->cp_scc[idx];
 		sup = (scc_uart_t *)&cp->cp_dparam[ser->port];
 	}
@@ -2957,7 +2982,7 @@
 
 	/* Set up the uart parameters in the parameter ram.
 	*/
-	if (ser->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(ser->smc_scc_num)) {
 
 		sup->scc_genscc.scc_rbase = dp_addr;
 		sup->scc_genscc.scc_tbase = dp_addr + sizeof(cbd_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/Makefile linux-2.4.21-rc3/arch/ppc/Makefile
--- linux-2.4.20/arch/ppc/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/Makefile linux-2.4.21-rc3/arch/ppc/amiga/Makefile
--- linux-2.4.20/arch/ppc/amiga/Makefile	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/Makefile	2003-05-22 22:06:42.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.5 05/21/01 00:48:24 cort
-#
 #
 # Makefile for Linux arch/m68k/amiga source directory
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c linux-2.4.21-rc3/arch/ppc/amiga/amiga_ksyms.c
--- linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/amiga_ksyms.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amiga_ksyms.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amiints.c linux-2.4.21-rc3/arch/ppc/amiga/amiints.c
--- linux-2.4.20/arch/ppc/amiga/amiints.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/amiints.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amisound.c linux-2.4.21-rc3/arch/ppc/amiga/amisound.c
--- linux-2.4.20/arch/ppc/amiga/amisound.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/amisound.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amisound.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/bootinfo.c linux-2.4.21-rc3/arch/ppc/amiga/bootinfo.c
--- linux-2.4.20/arch/ppc/amiga/bootinfo.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/bootinfo.c	2003-05-22 22:06:49.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort
- */
-/*
  *  linux/arch/ppc/amiga/bootinfo.c
  *
  *  Extracted from arch/m68k/kernel/setup.c.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/chipram.c linux-2.4.21-rc3/arch/ppc/amiga/chipram.c
--- linux-2.4.20/arch/ppc/amiga/chipram.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/chipram.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort
- */
 #include "../../m68k/amiga/chipram.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/cia.c linux-2.4.21-rc3/arch/ppc/amiga/cia.c
--- linux-2.4.20/arch/ppc/amiga/cia.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/cia.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/m68k/amiga/cia.c - CIA support
  *
  *  Copyright (C) 1996 Roman Zippel
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/config.c linux-2.4.21-rc3/arch/ppc/amiga/config.c
--- linux-2.4.20/arch/ppc/amiga/config.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/config.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #define m68k_debug_device debug_device
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/ints.c linux-2.4.21-rc3/arch/ppc/amiga/ints.c
--- linux-2.4.20/arch/ppc/amiga/ints.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/ints.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort
- */
-/*
  *  linux/arch/ppc/amiga/ints.c
  *
  *  Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/pcmcia.c linux-2.4.21-rc3/arch/ppc/amiga/pcmcia.c
--- linux-2.4.20/arch/ppc/amiga/pcmcia.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/pcmcia.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/pcmcia.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/time.c linux-2.4.21-rc3/arch/ppc/amiga/time.c
--- linux-2.4.20/arch/ppc/amiga/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/amiga/time.c	2003-05-22 22:06:46.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/Makefile linux-2.4.21-rc3/arch/ppc/boot/Makefile
--- linux-2.4.20/arch/ppc/boot/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/Makefile	2003-05-22 22:06:25.000000000 +0000
@@ -31,6 +31,7 @@
 subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_4xx)		:= mktree
+tools-$(CONFIG_LOPEC)		:= mkbugboot mkprep
 tools-$(CONFIG_SPRUCE)		:= mktree
 
 # These are dirs we don't want to go into on BOOT_TARGETS.  We have them for
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/Makefile linux-2.4.21-rc3/arch/ppc/boot/chrp/Makefile
--- linux-2.4.20/arch/ppc/boot/chrp/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/chrp/Makefile	2003-05-22 22:06:50.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.15 01/11/02 10:46:06 trini
 #
 # Makefile for making ELF bootable images for booting on CHRP
 # using Open Firmware.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/main.c linux-2.4.21-rc3/arch/ppc/boot/chrp/main.c
--- linux-2.4.20/arch/ppc/boot/chrp/main.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/chrp/main.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.main.c 1.16 01/12/02 10:36:33 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/misc.S linux-2.4.21-rc3/arch/ppc/boot/chrp/misc.S
--- linux-2.4.20/arch/ppc/boot/chrp/misc.S	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/chrp/misc.S	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/start.c linux-2.4.21-rc3/arch/ppc/boot/chrp/start.c
--- linux-2.4.20/arch/ppc/boot/chrp/start.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/chrp/start.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.8 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/crt0.S linux-2.4.21-rc3/arch/ppc/boot/common/crt0.S
--- linux-2.4.20/arch/ppc/boot/common/crt0.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/crt0.S	2003-05-22 22:06:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.crt0.S 1.14 01/11/02 10:46:07 trini
- */
 /*    Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Initial Power Macintosh COFF version.
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/dummy.c linux-2.4.21-rc3/arch/ppc/boot/common/dummy.c
--- linux-2.4.20/arch/ppc/boot/common/dummy.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/dummy.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 int main(void)
 {
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/misc-common.c linux-2.4.21-rc3/arch/ppc/boot/common/misc-common.c
--- linux-2.4.20/arch/ppc/boot/common/misc-common.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/misc-common.c	2003-05-22 22:06:46.000000000 +0000
@@ -8,27 +8,10 @@
  *
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2000-2001 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <stdarg.h>	/* for va_ bits */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/misc-simple.c linux-2.4.21-rc3/arch/ppc/boot/common/misc-simple.c
--- linux-2.4.20/arch/ppc/boot/common/misc-simple.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/misc-simple.c	2003-05-22 22:06:51.000000000 +0000
@@ -10,12 +10,10 @@
  * Author: Matt Porter <mporter@mvista.com>
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/types.h>
@@ -27,6 +25,7 @@
 #include <asm/mmu.h>
 #include <asm/bootinfo.h>
 
+#include "mpc10x.h"
 #include "nonstdio.h"
 #include "zlib.h"
 
@@ -44,6 +43,12 @@
 #define HAS_KEYB 0
 #endif
 
+/* Will / Can the user give input? */
+#if (defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
+	&& !defined(CONFIG_GEMINI)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 char *avail_ram;
 char *end_avail;
 char *zimage_start;
@@ -64,21 +69,42 @@
 extern unsigned long start;
 
 extern int CRT_tstc(void);
+extern unsigned long mpc10x_get_mem_size(int map);
 extern unsigned long serial_init(int chan, void *ignored);
 extern void serial_close(unsigned long com_port);
 extern void gunzip(void *, int, unsigned char *, int *);
 extern void serial_fixups(void);
 
+/* Allow decompress_kernel to be hooked into.  This is the default. */
+void * __attribute__ ((weak))
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *bp)
+{
+	return decompress_kernel(load_addr, num_words, cksum, bp);
+}
+
 struct bi_record *
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
-	char *cp, ch;
-	struct bi_record *rec, *birecs;
+	char ch;
+#endif
+	char *cp;
+	struct bi_record *rec;
+	unsigned long rec_loc, initrd_loc, TotalMemory = 0;
 
 	serial_fixups();
 	com_port = serial_init(0, NULL);
 
+#ifdef CONFIG_LOPEC
+	/*
+	 * This should work on any board with an MPC10X which is properly
+	 * initalized.
+	 */
+	TotalMemory = mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
+#endif
+
 	/* assume the chunk below 8M is free */
 	end_avail = (char *)0x00800000;
 
@@ -148,8 +174,7 @@
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
 	while ( *cp ) putc(*cp++);
 
-#if (defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
-	&& !defined(CONFIG_GEMINI)
+#ifdef INTERACTIVE_CONSOLE
 	/*
 	 * If they have a console, allow them to edit the command line.
 	 * Otherwise, don't bother wasting the five seconds.
@@ -189,14 +214,40 @@
 	/*
 	 * Create bi_recs for cmd_line and initrds
 	 */
-	rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) +
+	rec_loc = _ALIGN((unsigned long)(zimage_size) +
 			(1 << 20) - 1, (1 << 20));
-	birecs = rec;
+	rec = (struct bi_record *)rec_loc;
 
+	/* We need to make sure that the initrd and bi_recs do not
+	 * overlap. */
+	if ( initrd_size ) {
+		initrd_loc = (unsigned long)(&__ramdisk_begin);
+		/* If the bi_recs are in the middle of the current
+		 * initrd, move the initrd to the next MB
+		 * boundary. */
+		if ((rec_loc > initrd_loc) &&
+				((initrd_loc + initrd_size) > rec_loc)) {
+			initrd_loc = _ALIGN((unsigned long)(zimage_size)
+					+ (2 << 20) - 1, (2 << 20));
+		 	memmove((void *)initrd_loc, &__ramdisk_begin,
+				 initrd_size);
+	         	puts("initrd moved:  "); puthex(initrd_loc);
+		 	puts(" "); puthex(initrd_loc + initrd_size);
+		 	puts("\n");
+		}
+	}
+ 
 	rec->tag = BI_FIRST;
 	rec->size = sizeof(struct bi_record);
 	rec = (struct bi_record *)((unsigned long)rec + rec->size);
 
+	if ( TotalMemory ) {
+		rec->tag = BI_MEMSIZE;
+		rec->data[0] = TotalMemory;
+		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+
 	rec->tag = BI_CMD_LINE;
 	memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
 	rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
@@ -204,7 +255,7 @@
 
 	if ( initrd_size ) {
 		rec->tag = BI_INITRD;
-		rec->data[0] = (unsigned long)(&__ramdisk_begin);
+		rec->data[0] = initrd_loc;
 		rec->data[1] = initrd_size;
 		rec->size = sizeof(struct bi_record) + 2 *
 			sizeof(unsigned long);
@@ -218,5 +269,5 @@
 	puts("Now booting the kernel\n");
 	serial_close(com_port);
 
-	return birecs;
+	return (struct bi_record *)rec_loc;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/mpc10x_memory.c linux-2.4.21-rc3/arch/ppc/boot/common/mpc10x_memory.c
--- linux-2.4.20/arch/ppc/boot/common/mpc10x_memory.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/mpc10x_memory.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * arch/ppc/boot/common/mpc10x_common.c
+ * 
+ * A routine to find out how much memory the machine has.
+ *
+ * Based on:
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * 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/pci.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "mpc10x.h"
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+
+/*
+ * PCI config space macros, similar to indirect_xxx and early_xxx macros.
+ * We assume bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(unsigned int *cfg_addr, 			\
+		unsigned int *cfg_data, int devfn, int offset,		\
+		type val)						\
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read, byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ */
+unsigned long
+mpc10x_get_mem_size(unsigned int mem_map)
+{
+	unsigned int *config_addr, *config_data, val;
+	unsigned long start, end, total, offset;
+	int i;
+	unsigned char bank_enables;
+
+	switch (mem_map) {
+		case MPC10X_MEM_MAP_A:
+			config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR;
+			config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA;
+			break;
+		case MPC10X_MEM_MAP_B:
+			config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR;
+			config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA;
+			break;
+		default:
+			return 0;
+	}
+
+	mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
+			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
+
+	total = 0;
+
+	for (i = 0; i < 8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/ns16550.c linux-2.4.21-rc3/arch/ppc/boot/common/ns16550.c
--- linux-2.4.20/arch/ppc/boot/common/ns16550.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/ns16550.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ns16550.c 1.16 03/13/02 09:17:06 trini
- */
-/*
  * COM1 NS16550 support
  */
 
@@ -98,8 +95,3 @@
 {
 	return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/ofcommon.c linux-2.4.21-rc3/arch/ppc/boot/common/ofcommon.c
--- linux-2.4.20/arch/ppc/boot/common/ofcommon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/ofcommon.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: SCCS/s.ofcommon.c 1.2 01/11/02 10:46:07 trini
- *
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/relocate.S linux-2.4.21-rc3/arch/ppc/boot/common/relocate.S
--- linux-2.4.20/arch/ppc/boot/common/relocate.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/relocate.S	2003-05-22 22:06:50.000000000 +0000
@@ -9,12 +9,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -191,7 +189,7 @@
 	mr	r4,r7		/* Program length */
 	mr	r5,r6		/* Checksum */
 	mr	r6,r11		/* Residual data */
-	bl	decompress_kernel
+	bl	load_kernel
 
 	/*
 	 * Make sure the kernel knows we don't have things set  in
@@ -201,10 +199,10 @@
 	li	r6,0
 
 	/*
-	 * Start at the begining.
+	 * Start at the beginning of real code (the first
+	 * three instructions are 'nop' since we 
+	 * sometimes overwrite them).
 	 */
-	li	r9,0x0000
-	mtlr	r9
-	blr
+	ba	0x000c
 
 	.comm	.stack,4096*2,4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/serial_stub.c linux-2.4.21-rc3/arch/ppc/boot/common/serial_stub.c
--- linux-2.4.20/arch/ppc/boot/common/serial_stub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/serial_stub.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,28 @@
+/*
+ * arch/ppc/boot/common/serial_stub.c
+ *
+ * This is a few stub routines to make the boot code cleaner looking when
+ * there is no serial port support doesn't need to be closed, for example.
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * 2003 (c) MontaVista, Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed "as
+ * is" without any warranty of any kind, whether express or implied.
+ */
+
+void __attribute__ ((weak))
+serial_fixups(void)
+{
+}
+
+unsigned long __attribute__ ((weak))
+serial_init(int chan, void *ignored)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+serial_close(unsigned long com_port)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/string.S linux-2.4.21-rc3/arch/ppc/boot/common/string.S
--- linux-2.4.20/arch/ppc/boot/common/string.S	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/string.S	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/util.S linux-2.4.21-rc3/arch/ppc/boot/common/util.S
--- linux-2.4.20/arch/ppc/boot/common/util.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/common/util.S	2003-05-22 22:06:26.000000000 +0000
@@ -14,12 +14,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <asm/processor.h>
@@ -100,7 +98,7 @@
 	isync
 	mfspr	r8,L2CR
 	rlwinm	r8,r8,0,1,31
-	oris	r8,r8,0x0020
+	oris	r8,r8,L2CR_L2I@h
 	sync
 	isync
 	mtspr	L2CR,r8
@@ -108,11 +106,25 @@
 	isync
 
 	/* Wait for the invalidation to complete */
-1:	mfspr	r8,L2CR
-	rlwinm.	r9,r8,0,31,31
+	mfspr   r8,PVR
+	srwi    r8,r8,16
+	cmpli	cr0,r8,0x8000			/* 7450 */
+	cmpli	cr1,r8,0x8001			/* 7455 */
+	cmpli	cr2,r8,0x8002			/* 7457 */
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq	/* Now test if any are true. */
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	bne     2f
+
+1:	mfspr	r8,L2CR		/* On 745x, poll L2I bit (bit 10) */
+	rlwinm.	r9,r8,0,10,10
 	bne	1b
+	b	3f
+
+2:      mfspr   r8,L2CR		/* On 75x & 74[01]0, poll L2IP bit (bit 31) */
+	rlwinm. r9,r8,0,31,31
+	bne     2b
 
-	rlwinm	r8,r8,0,11,9		/* Turn off L2I bit */
+3:	rlwinm	r8,r8,0,11,9	/* Turn off L2I bit */
 	sync
 	isync
 	mtspr	L2CR,r8
@@ -120,6 +132,33 @@
 	isync
 	blr
 
+	.globl	_setup_L3CR
+_setup_L3CR:
+	/* Invalidate/disable L3 cache */
+	sync
+	isync
+	mfspr	r8,L3CR
+	rlwinm	r8,r8,0,1,31
+	ori	r8,r8,L3CR_L3I@l
+	sync
+	isync
+	mtspr	L3CR,r8
+	sync
+	isync
+
+	/* Wait for the invalidation to complete */
+1:	mfspr	r8,L3CR
+	rlwinm.	r9,r8,0,21,21
+	bne	1b
+
+	rlwinm	r8,r8,0,22,20		/* Turn off L3I bit */
+	sync
+	isync
+	mtspr	L3CR,r8
+	sync
+	isync
+	blr
+
 
 /*
  * Delay for a number of microseconds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/mpc10x.h linux-2.4.21-rc3/arch/ppc/boot/include/mpc10x.h
--- linux-2.4.20/arch/ppc/boot/include/mpc10x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/include/mpc10x.h	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/boot/include/mpc10.h
+ *
+ * Common defines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
+ * ctrl/EPIC/etc.
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * This is a heavily stripped down version of:
+ * include/asm-ppc/mpc10x.h
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * 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.
+ */
+#ifndef __BOOT_MPC10X_H__
+#define __BOOT_MPC10X_H__
+
+/*
+ * The values here don't completely map everything but should work in most
+ * cases.
+ *
+ * MAP A (PReP Map)
+ *   Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff
+ *   Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff
+ *   PCI MEM:   0x80000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ *
+ * MAP B (CHRP Map)
+ *   Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff
+ *   Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff
+ *   PCI MEM:   0x00000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ */
+
+/* Define the type of map to use */
+#define	MPC10X_MEM_MAP_A		1
+#define	MPC10X_MEM_MAP_B		2
+
+/* Map A (PReP Map) Defines */
+#define	MPC10X_MAPA_CNFG_ADDR		0x80000cf8
+#define	MPC10X_MAPA_CNFG_DATA		0x80000cfc
+
+/* Map B (CHRP Map) Defines */
+#define	MPC10X_MAPB_CNFG_ADDR		0xfec00000
+#define	MPC10X_MAPB_CNFG_DATA		0xfee00000
+
+/* Define offsets for the memory controller registers in the config space */
+#define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_START_2	0x84	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_START_1	0x88	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_END_2i		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_BANK_ENABLES	0xa0
+
+#endif	/* __BOOT_MPC10X_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/nonstdio.h linux-2.4.21-rc3/arch/ppc/boot/include/nonstdio.h
--- linux-2.4.20/arch/ppc/boot/include/nonstdio.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/include/nonstdio.h	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/rs6000.h linux-2.4.21-rc3/arch/ppc/boot/include/rs6000.h
--- linux-2.4.20/arch/ppc/boot/include/rs6000.h	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/include/rs6000.h	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort
- */
 /* IBM RS/6000 "XCOFF" file definitions for BFD.
    Copyright (C) 1990, 1991 Free Software Foundation, Inc.
    FIXME: Can someone provide a transliteration of this name into ASCII?
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/zlib.h linux-2.4.21-rc3/arch/ppc/boot/include/zlib.h
--- linux-2.4.20/arch/ppc/boot/include/zlib.h	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/include/zlib.h	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort
- */
-/*
  * This file is derived from zlib.h and zconf.h from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/ld.script linux-2.4.21-rc3/arch/ppc/boot/ld.script
--- linux-2.4.20/arch/ppc/boot/ld.script	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/ld.script	2003-05-22 22:06:42.000000000 +0000
@@ -39,7 +39,7 @@
   PROVIDE (etext = .);
 
   /* Read-write section, merged into data segment: */
-  . = ALIGN(8);
+  . = ALIGN(4096);
   .data    :
   {
     *(.data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/Makefile linux-2.4.21-rc3/arch/ppc/boot/lib/Makefile
--- linux-2.4.20/arch/ppc/boot/lib/Makefile	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/lib/Makefile	2003-05-22 22:06:39.000000000 +0000
@@ -2,8 +2,10 @@
 # Makefile for some libs needed by zImage.
 #
 
+USE_STANDARD_AS_RULE	:= true
+
 L_TARGET := zlib.a
 
-obj-y := zlib.o
+obj-y := zlib.o div64.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/div64.S linux-2.4.21-rc3/arch/ppc/boot/lib/div64.S
--- linux-2.4.20/arch/ppc/boot/lib/div64.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/lib/div64.S	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+_GLOBAL(__div64_32)
+	lwz	r5,0(r3)	# get the dividend into r5/r6
+	lwz	r6,4(r3)
+	cmplw	r5,r4
+	li	r7,0
+	li	r8,0
+	blt	1f
+	divwu	r7,r5,r4	# if dividend.hi >= divisor,
+	mullw	r0,r7,r4	# quotient.hi = dividend.hi / divisor
+	subf.	r5,r0,r5	# dividend.hi %= divisor
+	beq	3f
+1:	mr	r11,r5		# here dividend.hi != 0
+	andis.	r0,r5,0xc000
+	bne	2f
+	cntlzw	r0,r5		# we are shifting the dividend right
+	li	r10,-1		# to make it < 2^32, and shifting
+	srw	r10,r10,r0	# the divisor right the same amount,
+	add	r9,r4,r10	# rounding up (so the estimate cannot
+	andc	r11,r6,r10	# ever be too large, only too small)
+	andc	r9,r9,r10
+	or	r11,r5,r11
+	rotlw	r9,r9,r0
+	rotlw	r11,r11,r0
+	divwu	r11,r11,r9	# then we divide the shifted quantities
+2:	mullw	r10,r11,r4	# to get an estimate of the quotient,
+	mulhwu	r9,r11,r4	# multiply the estimate by the divisor,
+	subfc	r6,r10,r6	# take the product from the divisor,
+	add	r8,r8,r11	# and add the estimate to the accumulated
+	subfe.	r5,r9,r5	# quotient
+	bne	1b
+3:	cmplw	r6,r4
+	blt	4f
+	divwu	r0,r6,r4	# perform the remaining 32-bit division
+	mullw	r10,r0,r4	# and get the remainder
+	add	r8,r8,r0
+	subf	r6,r10,r6
+4:	stw	r7,0(r3)	# return the quotient in *r3
+	stw	r8,4(r3)
+	mr	r3,r6		# return the remainder in r3
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/zlib.c linux-2.4.21-rc3/arch/ppc/boot/lib/zlib.c
--- linux-2.4.20/arch/ppc/boot/lib/zlib.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/lib/zlib.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.zlib.c 1.9 12/05/01 16:19:42 mporter
- */
-/*
  * This file is derived from various .h and .c files from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/Makefile linux-2.4.21-rc3/arch/ppc/boot/pmac/Makefile
--- linux-2.4.20/arch/ppc/boot/pmac/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/pmac/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.19 01/16/02 11:08:07 trini
 #
 # Makefile for making XCOFF bootable images for booting on PowerMacs
 # using Open Firmware.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c linux-2.4.21-rc3/arch/ppc/boot/pmac/chrpmain.c
--- linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/pmac/chrpmain.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.chrpmain.c 1.18 01/11/02 10:46:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/coffmain.c linux-2.4.21-rc3/arch/ppc/boot/pmac/coffmain.c
--- linux-2.4.20/arch/ppc/boot/pmac/coffmain.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/pmac/coffmain.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.coffmain.c 1.15 01/11/02 10:46:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/misc.S linux-2.4.21-rc3/arch/ppc/boot/pmac/misc.S
--- linux-2.4.20/arch/ppc/boot/pmac/misc.S	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/pmac/misc.S	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/start.c linux-2.4.21-rc3/arch/ppc/boot/pmac/start.c
--- linux-2.4.20/arch/ppc/boot/pmac/start.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/pmac/start.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.10 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/Makefile linux-2.4.21-rc3/arch/ppc/boot/prep/Makefile
--- linux-2.4.20/arch/ppc/boot/prep/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.30 01/26/02 12:27:41 trini
 #
 # arch/ppc/boot/Makefile
 #
@@ -19,13 +18,14 @@
 
 TFTPIMAGE			= /tftpboot/zImage.prep
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE			= $(TFTPBOOT).smp
+TFTPIMAGE			:= $(TFTPIMAGE).smp
 endif
 
 LD_ARGS				= -T ../ld.script -Ttext 0x00800000 -Bstatic
 obj-y				:= head.o ../simple/legacy.o misc.o of1275.o \
 					../common/util.o ../common/string.o \
-					../common/misc-common.o
+					../common/misc-common.o \
+					../common/serial_stub.o
 OBJCOPY_ARGS			= -O elf32-powerpc
 LIBS 				= ../lib/zlib.a
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/head.S linux-2.4.21-rc3/arch/ppc/boot/prep/head.S
--- linux-2.4.20/arch/ppc/boot/prep/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/head.S	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini
- */
-
 #include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/iso_font.h linux-2.4.21-rc3/arch/ppc/boot/prep/iso_font.h
--- linux-2.4.20/arch/ppc/boot/prep/iso_font.h	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/iso_font.h	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort
- */
 static const unsigned char font[] = {
 /* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/kbd.c linux-2.4.21-rc3/arch/ppc/boot/prep/kbd.c
--- linux-2.4.20/arch/ppc/boot/prep/kbd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/kbd.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.kbd.c 1.9 01/11/02 10:46:07 trini
- */
-
 #include <linux/keyboard.h>
 
 #include "defkeymap.c"	/* yeah I know it's bad -- Cort */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/misc.c linux-2.4.21-rc3/arch/ppc/boot/prep/misc.c
--- linux-2.4.20/arch/ppc/boot/prep/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/misc.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.c 1.25 01/26/02 12:27:41 trini
- *
  * arch/ppc/boot/prep/misc.c
  *
  * Adapted for PowerPC by Gary Thomas
@@ -23,6 +21,16 @@
 #include "nonstdio.h"
 #include "zlib.h"
 
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /*
  * Please send me load/board info and such data for hardware not
  * listed here so I can keep track since things are getting tricky
@@ -38,11 +46,6 @@
 extern char __ramdisk_begin, __ramdisk_end;
 extern char _end[];
 
-#ifdef CONFIG_CMDLINE
-#define CMDLINE CONFIG_CMDLINE
-#else
-#define CMDLINE ""
-#endif
 char cmd_preset[] = CMDLINE;
 char cmd_buf[256];
 char *cmd_line = cmd_buf;
@@ -56,9 +59,7 @@
 char *zimage_start;
 int zimage_size;
 
-#if defined(CONFIG_SERIAL_CONSOLE)
 unsigned long com_port;
-#endif /* CONFIG_SERIAL_CONSOLE */
 #ifdef CONFIG_VGA_CONSOLE
 char *vidmem = (char *)0xC00B8000;
 int lines = 25, cols = 80;
@@ -122,10 +123,14 @@
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
 		  RESIDUAL *residual, void *OFW_interface)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
+	char ch;
+#endif
 	extern unsigned long start;
-	char *cp, ch;
-	unsigned long TotalMemory;
+	char *cp;
+	/* Default to 32MiB memory. */
+	unsigned long TotalMemory = 0x02000000;
 	int dev_handle;
 	int mem_info[2];
 	int res, size;
@@ -135,9 +140,7 @@
 	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
 
 	serial_fixups();
-#if defined(CONFIG_SERIAL_CONSOLE)
 	com_port = serial_init(0, NULL);
-#endif /* CONFIG_SERIAL_CONSOLE */
 #if defined(CONFIG_VGA_CONSOLE)
 	vga_init((unsigned char *)0xC0000000);
 #endif /* CONFIG_VGA_CONSOLE */
@@ -215,13 +218,14 @@
 				start_multi = 1;
 		}
 		memcpy(hold_residual,residual,sizeof(RESIDUAL));
+
+		/* Copy the memory info. */
+		if (residual->TotalMemory)
+			TotalMemory = residual->TotalMemory;
 	} else {
 		/* Tell the user we didn't find anything. */
 		puts("No residual data found.\n");
 
-		/* Assume 32M in the absence of more info... */
-		TotalMemory = 0x02000000;
-
 		/*
 		 * This is a 'best guess' check.  We want to make sure
 		 * we don't try this on a PReP box without OF
@@ -254,9 +258,6 @@
 			break;
 		}
 
-		hold_residual->TotalMemory = TotalMemory;
-		residual = hold_residual;
-
 		/* Enforce a sane MSR for booting. */
 		_put_MSR(MSR_IP);
         }
@@ -304,6 +305,11 @@
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
 	while ( *cp )
 		putc(*cp++);
+#ifdef INTERACTIVE_CONSOLE
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -328,6 +334,7 @@
 		}
 		udelay(1000);  /* 1 msec */
 	}
+#endif
 	*cp = 0;
 	puts("\nUncompressing Linux...");
 
@@ -343,14 +350,41 @@
 
 	{
 		struct bi_record *rec;
-		
-		rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) +
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
 				(1 << 20) - 1, (1 << 20));
+		
+		rec = (struct bi_record *)rec_loc;
+
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
 		rec->size = sizeof(struct bi_record);
 		rec = (struct bi_record *)((unsigned long)rec + rec->size);
 
+		rec->tag = BI_MEMSIZE;
+		rec->data[0] = TotalMemory;
+		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
 		rec->tag = BI_BOOTLOADER_ID;
 		memcpy( (void *)rec->data, "prepboot", 9);
 		rec->size = sizeof(struct bi_record) + 8 + 1;
@@ -370,7 +404,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/of1275.c linux-2.4.21-rc3/arch/ppc/boot/prep/of1275.c
--- linux-2.4.20/arch/ppc/boot/prep/of1275.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/of1275.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort
- */
 /* Open Firmware Client Interface */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/of1275.h linux-2.4.21-rc3/arch/ppc/boot/prep/of1275.h
--- linux-2.4.20/arch/ppc/boot/prep/of1275.h	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/of1275.h	2003-05-22 22:06:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort
- */
 /* 6.3.2.1 Client interface */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/vreset.c linux-2.4.21-rc3/arch/ppc/boot/prep/vreset.c
--- linux-2.4.20/arch/ppc/boot/prep/vreset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/prep/vreset.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.vreset.c 1.13 01/11/02 10:46:08 trini
- */
-/*
  * vreset.c
  *
  * Initialize the VGA control registers to 80x25 text mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/Makefile linux-2.4.21-rc3/arch/ppc/boot/simple/Makefile
--- linux-2.4.20/arch/ppc/boot/simple/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/Makefile	2003-05-22 22:06:25.000000000 +0000
@@ -3,7 +3,10 @@
 #
 # Author: Tom Rini <trini@mvista.com>
 #
-# Copyright 2001-2002 MontaVista Software Inc.
+# 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+# the terms of the GNU General Public License version 2.  This program
+# is licensed "as is" without any warranty of any kind, whether express
+# or implied.
 #
 # Notes:
 # (1) For machine targets which produce more than one image, define
@@ -13,11 +16,6 @@
 # the machine name you want in the image, and you can optionally set
 # ENTRYPOINT which the image should be loaded at.  The optimal setting
 # for ENTRYPOINT is the link address.
-#
-# 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.
 
 USE_STANDARD_AS_RULE		:= true
 
@@ -33,19 +31,25 @@
 ifeq ($(CONFIG_GEMINI),y)
 ZIMAGE				:= zImage-SMON
 ZIMAGEINITRD			:= zImage.initrd-SMON
-EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.gemini
 endif
+ifeq ($(CONFIG_LOPEC),y)
+ZIMAGE				:= zImage-PPLUS
+ZIMAGEINITRD			:= zImage.initrd-PPLUS
+EXTRA				:= ../common/mpc10x_memory.o
+TFTPIMAGE			:= /tftpboot/zImage.pplus
+ZNETBOOT			:= zImage.pplus
+ZNETBOOTRD			:= zImage.initrd.pplus
+endif
+
 ifeq ($(CONFIG_PAL4),y)
 ZIMAGE				:= zImage-PAL4
 ZIMAGEINITRD			:= zImage.initrd-PAL4
-EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.pal4
 endif
 ifeq ($(CONFIG_SPRUCE),y)
 ZIMAGE				:= zImage-TREE
 ZIMAGEINITRD			:= zImage.initrd-TREE
-EXTRA				:= direct.o
 ENTRYPOINT			:= 0x00800000
 MISC				:= misc-spruce.o
 END				:= spruce
@@ -68,7 +72,8 @@
 # head.o and ../common/relocate.o must be at the start.
 obj-y				:= head.o ../common/relocate.o $(EXTRA) \
 				$(MISC) ../common/misc-common.o \
-				../common/string.o ../common/util.o
+				../common/string.o ../common/util.o \
+				../common/serial_stub.o
 obj-$(CONFIG_4xx)		+= embed_config.o
 obj-$(CONFIG_8xx)		+= embed_config.o
 obj-$(CONFIG_8260)		+= embed_config.o
@@ -86,6 +91,7 @@
 LIBS				:= ../lib/zlib.a
 
 # Tools
+MKBUGBOOT			:= ../utils/mkbugboot
 MKPREP				:= ../utils/mkprep
 MKTREE				:= ../utils/mktree
 
@@ -142,6 +148,14 @@
 zImage.initrd-PAL4: zvmlinux.initrd
 	cp zvmlinux.initrd ../images/zImage.initrd.pal4
 
+zImage-PPLUS: zvmlinux $(MKPREP) $(MKBUGBOOT)
+	$(MKPREP) -pbp zvmlinux ../images/zImage.pplus
+	$(MKBUGBOOT) zvmlinux ../images/zImage.bugboot
+
+zImage.initrd-PPLUS: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT)
+	$(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.pplus
+	$(MKBUGBOOT) zvmlinux.initrd ../images/zImage.initrd.bugboot
+
 zImage-SMON: zvmlinux
 	dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/direct.S linux-2.4.21-rc3/arch/ppc/boot/simple/direct.S
--- linux-2.4.20/arch/ppc/boot/simple/direct.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/direct.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
-/*
- * arch/ppc/boot/simple/direct.S
- *
- * Author: Tom Rini <trini@mvista.com>
- *
- * This is an empty function for machines which use SERIAL_IO_MEM
- * and don't need ISA_io set to anything but 0, or perform any other
- * serial fixups.
- */
-
-	.text
-
-	.globl serial_fixups
-serial_fixups:
-	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/embed_config.c linux-2.4.21-rc3/arch/ppc/boot/simple/embed_config.c
--- linux-2.4.20/arch/ppc/boot/simple/embed_config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/embed_config.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Board specific functions for those embedded 8xx boards that do
  * not have boot monitor support for board information.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/head.S linux-2.4.21-rc3/arch/ppc/boot/simple/head.S
--- linux-2.4.20/arch/ppc/boot/simple/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/head.S	2003-05-22 22:06:51.000000000 +0000
@@ -7,12 +7,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -75,6 +73,17 @@
 	bl	disable_6xx_l1cache
 #if defined(CONFIG_FORCE) || defined(CONFIG_K2) || defined(CONFIG_EV64260)
 	bl	_setup_L2CR
+
+	/* If 745x, turn off L3CR as well */
+	mfspr	r8,PVR
+	srwi	r8,r8,16
+
+	cmpli	cr0,r8,0x8000			/* 7450 */
+	cmpli	cr1,r8,0x8001			/* 7455 */
+	cmpli	cr2,r8,0x8002			/* 7457 */
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq	/* Now test if any are true. */
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	beql	_setup_L3CR
 #endif
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/iic.c linux-2.4.21-rc3/arch/ppc/boot/simple/iic.c
--- linux-2.4.20/arch/ppc/boot/simple/iic.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/iic.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Minimal support functions to read configuration from IIC EEPROMS
  * on MPC8xx boards.  Originally written for RPGC RPX-Lite.
  * Dan Malek (dmalek@jlc.net).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/m8260_tty.c linux-2.4.21-rc3/arch/ppc/boot/simple/m8260_tty.c
--- linux-2.4.20/arch/ppc/boot/simple/m8260_tty.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/m8260_tty.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on SMC1.
  */
@@ -316,8 +311,3 @@
 
 	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/m8xx_tty.c linux-2.4.21-rc3/arch/ppc/boot/simple/m8xx_tty.c
--- linux-2.4.20/arch/ppc/boot/simple/m8xx_tty.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/m8xx_tty.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on the MBX console.
  *
@@ -293,8 +288,3 @@
 
 	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c linux-2.4.21-rc3/arch/ppc/boot/simple/misc-embedded.c
--- linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/misc-embedded.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * Originally adapted by Gary Thomas.  Much additional work by
  * Cort Dougan <cort@fsmlabs.com>.  On top of that still more work by
  * Dan Malek <dmalek@jlc.net>.
@@ -28,6 +26,10 @@
 #include "nonstdio.h"
 #include "zlib.h"
 
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /* The linker tells us where the image is. */
 extern char __image_begin, __image_end;
 extern char __ramdisk_begin, __ramdisk_end;
@@ -77,19 +79,22 @@
 extern void embed_config(bd_t **bp);
 
 unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		bd_t *bp)
 {
-	char *cp, ch;
-	int timer = 0, zimage_size;
+#ifdef INTERACTIVE_CONSOLE
+	int timer = 0;
+	char ch;
+#endif
+	char *cp;
+	int zimage_size;
 	unsigned long initrd_size;
 
 	/* First, capture the embedded board information.  Then
 	 * initialize the serial console port.
 	 */
 	embed_config(&bp);
-#ifdef CONFIG_SERIAL_CONSOLE
 	com_port = serial_init(0, bp);
-#endif
 
 	/* copy board data */
 	if (bp)
@@ -172,7 +177,7 @@
 #endif
 	while ( *cp )
 		putc(*cp++);
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#ifdef INTERACTIVE_CONSOLE
 	/*
 	 * If they have a console, allow them to edit the command line.
 	 * Otherwise, don't bother wasting the five seconds.
@@ -209,9 +214,30 @@
 	puts("done.\n");
 	{
 		struct bi_record *rec;
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
+				(1 << 20) - 1, (1 << 20));
+		rec = (struct bi_record *)rec_loc;
 
-		rec = (struct bi_record *)_ALIGN((unsigned long)zimage_size +
-				(1 << 20) - 1,(1 << 20));
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
 		rec->size = sizeof(struct bi_record);
@@ -224,7 +250,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c linux-2.4.21-rc3/arch/ppc/boot/simple/misc-spruce.c
--- linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/simple/misc-spruce.c	2003-05-22 22:06:42.000000000 +0000
@@ -8,27 +8,10 @@
  *
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2000-2001 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/types.h>
@@ -43,6 +26,16 @@
 
 #include "zlib.h"
 
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /* Define some important locations of the Spruce. */
 #define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
 #define SPRUCE_PCI_CONFIG_DATA	0xfec00004
@@ -58,11 +51,6 @@
 extern char __ramdisk_begin, __ramdisk_end;
 extern char _end[];
 
-#ifdef CONFIG_CMDLINE
-#define CMDLINE CONFIG_CMDLINE
-#else
-#define CMDLINE ""
-#endif
 char cmd_preset[] = CMDLINE;
 char cmd_buf[256];
 char *cmd_line = cmd_buf;
@@ -164,11 +152,13 @@
 #define MEM_B2EA	0x60
 
 unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
-	char *cp, ch;
-
+	char ch;
+#endif
+	char *cp;
 	int loop;
 	int csr0;
 	int csr_id;
@@ -189,10 +179,8 @@
 	unsigned char header_type;
 	unsigned int bar0;
 
-#ifdef CONFIG_SERIAL_CONSOLE
 	/* Initialize the serial console port */
 	com_port = serial_init(0, NULL);
-#endif
 
 	/*
 	 * Gah, these firmware guys need to learn that hardware
@@ -367,7 +355,13 @@
 	puts("\nLinux/PPC load: ");
 	cp = cmd_line;
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-	while ( *cp ) putc(*cp++);
+	while ( *cp )
+		putc(*cp++);
+#ifdef INTERACTIVE_CONSOLE
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -385,6 +379,7 @@
 		}
 		udelay(1000);  /* 1 msec */
 	}
+#endif
 	*cp = 0;
 	puts("\n");
 
@@ -396,9 +391,30 @@
 
 	{
 		struct bi_record *rec;
-
-		rec = (struct bi_record *)_ALIGN((ulong)zimage_size +
-							(1<<20)-1,(1<<20));
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
+				(1 << 20) - 1, (1 << 20));
+		rec = (struct bi_record *)rec_loc;
+  
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
         	rec->size = sizeof(struct bi_record);
@@ -421,7 +437,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/Makefile linux-2.4.21-rc3/arch/ppc/boot/utils/Makefile
--- linux-2.4.20/arch/ppc/boot/utils/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -10,7 +10,7 @@
 all: dummy
 
 # Simple programs with 1 file and no extra CFLAGS
-UTILS = addnote hack-coff mkprep mknote mktree
+UTILS = addnote hack-coff mkbugboot mkprep mknote mktree
 
 $(UTILS):
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $@.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/addnote.c linux-2.4.21-rc3/arch/ppc/boot/utils/addnote.c
--- linux-2.4.20/arch/ppc/boot/utils/addnote.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/addnote.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Program to hack in a PT_NOTE program header entry in an ELF file.
  * This is needed for OF on RS/6000s to load an image correctly.
  * Note that OF needs a program header entry for the note, not an
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/hack-coff.c linux-2.4.21-rc3/arch/ppc/boot/utils/hack-coff.c
--- linux-2.4.20/arch/ppc/boot/utils/hack-coff.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/hack-coff.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch
- */
-/*
  * hack-coff.c - hack the header of an xcoff file to fill in
  * a few fields needed by the Open Firmware xcoff loader on
  * Power Macs but not initialized by objcopy.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mkbugboot.c linux-2.4.21-rc3/arch/ppc/boot/utils/mkbugboot.c
--- linux-2.4.20/arch/ppc/boot/utils/mkbugboot.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/mkbugboot.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,191 @@
+/*
+ * arch/ppc/pp3boot/mkbugboot.c
+ * 
+ * Makes a Motorola PPCBUG ROM bootable image which can be flashed 
+ * into one of the FLASH banks on a Motorola PowerPlus board. 
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#define ELF_HEADER_SIZE	65536
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef __i386__
+#define cpu_to_be32(x) le32_to_cpu(x)
+#define cpu_to_be16(x) le16_to_cpu(x)
+#else
+#define cpu_to_be32(x) (x)
+#define cpu_to_be16(x) (x)
+#endif
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+     	return (((x & 0x000000ffU) << 24) |
+		((x & 0x0000ff00U) <<  8) |
+		((x & 0x00ff0000U) >>  8) |
+		((x & 0xff000000U) >> 24));
+}
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+	return (((x & 0x00ff) << 8) |
+		((x & 0xff00) >> 8));
+}
+
+/* size of read buffer */
+#define SIZE 0x1000
+
+#ifndef __sun__
+/* typedef long int32_t; */
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+
+/* PPCBUG ROM boot header */
+typedef struct bug_boot_header {
+  uint8_t	magic_word[4];		/* "BOOT" */
+  uint32_t	entry_offset;		/* Offset from top of header to code */
+  uint32_t	routine_length;		/* Length of code */
+  uint8_t	routine_name[8];	/* Name of the boot code */
+} bug_boot_header_t;
+
+#define HEADER_SIZE	sizeof(bug_boot_header_t)
+
+uint32_t copy_image(int32_t in_fd, int32_t out_fd)
+{
+  uint8_t buf[SIZE];
+  int n;
+  uint32_t image_size = 0;
+  uint8_t zero = 0;
+
+  lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
+
+  /* Copy an image while recording its size */
+  while ( (n = read(in_fd, buf, SIZE)) > 0 )
+    {
+    image_size = image_size + n;
+    write(out_fd, buf, n);
+    }
+
+  /* BUG romboot requires that our size is divisible by 2 */
+  /* align image to 2 byte boundary */
+  if (image_size % 2)
+    {
+    image_size++;
+    write(out_fd, &zero, 1);
+    }
+
+  return image_size;
+}
+
+void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
+{
+  uint8_t header_block[HEADER_SIZE];
+  bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
+  
+  memset(header_block, 0, HEADER_SIZE);
+
+  /* Fill in the PPCBUG ROM boot header */
+  strncpy(bbh->magic_word, "BOOT", 4);		/* PPCBUG magic word */
+  bbh->entry_offset = cpu_to_be32(HEADER_SIZE);	/* Entry address */
+  bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2);	/* Routine length */
+  strncpy(bbh->routine_name, "LINUXROM", 8);		/* Routine name   */
+
+  /* Output the header and bootloader to the file */
+  write(out_fd, header_block, HEADER_SIZE);
+}
+
+uint16_t calc_checksum(int32_t bug_fd)
+{
+  uint32_t checksum_var = 0;
+  uint8_t buf[2];
+  int n;
+
+  /* Checksum loop */
+  while ( (n = read(bug_fd, buf, 2) ) )
+  {
+    checksum_var = checksum_var + *(uint16_t *)buf;
+
+    /* If we carry out, mask it and add one to the checksum */
+    if (checksum_var >> 16)
+      checksum_var = (checksum_var & 0x0000ffff) + 1;
+  }
+
+  return checksum_var;
+}
+
+int main(int argc, char *argv[])
+{
+  int32_t image_fd, bugboot_fd;
+  int argptr = 1;
+  uint32_t kernel_size = 0;
+  uint16_t checksum = 0;
+  uint8_t bugbootname[256];
+
+  if ( (argc != 3) )
+  {
+    fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
+    exit(-1);
+  }
+
+  /* Get file args */
+  
+  /* kernel image file */
+    if ((image_fd = open( argv[argptr] , 0)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* bugboot file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    bugboot_fd = 1;			/* stdout */
+  else
+    if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0)
+      exit(-1);
+    else
+      strcpy(bugbootname, argv[argptr]);
+  argptr++;
+
+  /* Set file position after ROM header block where zImage will be written */
+  lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
+
+  /* Copy kernel image into bugboot image */
+  kernel_size = copy_image(image_fd, bugboot_fd);
+  close(image_fd);
+
+  /* Set file position to beginning where header/romboot will be written */
+  lseek(bugboot_fd, 0, SEEK_SET);
+
+  /* Write out BUG header/romboot */
+  write_bugboot_header(bugboot_fd, kernel_size);
+
+  /* Close bugboot file */
+  close(bugboot_fd);
+
+  /* Reopen it as read/write */
+  bugboot_fd = open(bugbootname, O_RDWR);
+
+  /* Calculate checksum */
+  checksum = calc_checksum(bugboot_fd);  
+
+  /* Write out the calculated checksum */
+  write(bugboot_fd, &checksum, 2);
+
+  return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mknote.c linux-2.4.21-rc3/arch/ppc/boot/utils/mknote.c
--- linux-2.4.20/arch/ppc/boot/utils/mknote.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/mknote.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Copyright (C) Cort Dougan 1999.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mkprep.c linux-2.4.21-rc3/arch/ppc/boot/utils/mkprep.c
--- linux-2.4.20/arch/ppc/boot/utils/mkprep.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/mkprep.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch
- */
-/*
  * Makes a prep bootable image which can be dd'd onto
  * a disk device to make a bootdisk.  Will take
  * as input a elf executable, strip off the header
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mktree.c linux-2.4.21-rc3/arch/ppc/boot/utils/mktree.c
--- linux-2.4.20/arch/ppc/boot/utils/mktree.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/boot/utils/mktree.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- * 
  * Makes a tree bootable image for IBM Evaluation boards.
  * Basically, just take a zImage, skip the ELF header, and stuff
  * a 32 byte header on the front.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/config.in linux-2.4.21-rc3/arch/ppc/config.in
--- linux-2.4.20/arch/ppc/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/config.in	2003-05-22 22:06:47.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
@@ -58,9 +57,12 @@
 fi
 
 if [ "$CONFIG_4xx" = "y" ]; then
-    choice 'Machine Type'			\
+  choice 'Machine Type'			\
 	"Oak			CONFIG_OAK 	\
 	 Walnut			CONFIG_WALNUT"	Oak
+  if [ "$CONFIG_WALNUT" = "y" ]; then
+    define_bool CONFIG_IBM405_ERR77 y
+  fi
 fi
 
 if [ "$CONFIG_8xx" = "y" ]; then
@@ -99,10 +101,20 @@
 	"CHRP/PowerMac/PReP	CONFIG_ALL_PPC		\
   	 Amiga-APUS		CONFIG_APUS		\
 	 IBM-Spruce		CONFIG_SPRUCE		\
+	 Motorola-LoPEC		CONFIG_LOPEC		\
 	 SBS-Palomar4		CONFIG_PAL4		\
 	 Synergy-Gemini        	CONFIG_GEMINI"		CHRP/PowerMac/PReP
 fi
 
+if [ "$CONFIG_SPRUCE" = "y" ]; then
+  define_bool CONFIG_GEN550 y
+fi
+
+if [ "$CONFIG_LOPEC" = "y" ]; then
+  define_bool CONFIG_EPIC_SERIAL_MODE y
+  define_bool CONFIG_GEN550 y
+fi
+
 if [ "$CONFIG_PPC_STD_MMU" != "y" ]; then
   define_bool CONFIG_ALL_PPC n
 fi
@@ -184,12 +196,9 @@
 
 source drivers/parport/Config.in
 
-if [ "$CONFIG_4xx" != "y" ]; then
-  if [ "$CONFIG_APUS" != "y" ]; then
-    tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
-  else
-    bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
-  fi
+tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+if [ "$CONFIG_GEN_RTC" = "n" -a "$CONFIG_APUS" != "y" ]; then
+  tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" -a "$CONFIG_POWER3" = "n" ] ; then
@@ -199,9 +208,12 @@
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
   bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
   bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
-  bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
   bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
   dep_bool '  Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL
+  define_bool CONFIG_PPCBUG_NVRAM y
+fi
+if [ "$CONFIG_LOPEC" = "y" ]; then
+  bool 'Enable reading PPCBUG NVRAM during boot' CONFIG_PPCBUG_NVRAM
 fi
 
 bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
@@ -414,14 +426,38 @@
   fi
   bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ
   bool '  Include kgdb kernel debugger' CONFIG_KGDB
+  if [ "$CONFIG_KGDB" = "y" ]; then
+    choice '    Serial Port'		\
+	"ttyS0	CONFIG_KGDB_TTYS0	\
+	 ttyS1	CONFIG_KGDB_TTYS1	\
+	 ttyS2	CONFIG_KGDB_TTYS2	\
+	 ttyS3	CONFIG_KGDB_TTYS3"	ttyS1
+  fi
+  if [ "$CONFIG_8xx" = "y" ]; then
+    dep_bool '    Enable serial console thru kgdb port' CONFIG_KGDB_CONSOLE $CONFIG_KGDB
+  fi
   bool '  Include xmon kernel debugger' CONFIG_XMON
   bool '  Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH
+  # CONFIG_KGDB is much more useful with -g enbaled.  This makes the
+  # following look a little odd.
   if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \
 	-o "$CONFIG_BDI_SWITCH" = "y" ]; then
-    bool '    Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
+    bool '  Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
     if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
       string '    Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
+    else
+      if [ "$CONFIG_KGDB" = "y" ]; then
+        define_bool CONFIG_MORE_COMPILE_OPTIONS y
+	define_string CONFIG_COMPILE_OPTIONS "-g"
+      fi
     fi
   fi
 fi
+
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+  bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
+fi
+if [ "$CONFIG_GEN550" = "y" ]; then
+  bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
+fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/IVMS8_defconfig linux-2.4.21-rc3/arch/ppc/configs/IVMS8_defconfig
--- linux-2.4.20/arch/ppc/configs/IVMS8_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/IVMS8_defconfig	2003-05-22 22:06:26.000000000 +0000
@@ -76,7 +76,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -194,15 +194,6 @@
 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -227,6 +218,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -277,6 +269,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -379,11 +372,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/SM850_defconfig linux-2.4.21-rc3/arch/ppc/configs/SM850_defconfig
--- linux-2.4.20/arch/ppc/configs/SM850_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/SM850_defconfig	2003-05-22 22:06:41.000000000 +0000
@@ -77,7 +77,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -335,11 +336,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig linux-2.4.21-rc3/arch/ppc/configs/SPD823TS_defconfig
--- linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/SPD823TS_defconfig	2003-05-22 22:06:53.000000000 +0000
@@ -76,7 +76,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -232,6 +232,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -334,11 +335,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM823L_defconfig linux-2.4.21-rc3/arch/ppc/configs/TQM823L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM823L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/TQM823L_defconfig	2003-05-22 22:06:28.000000000 +0000
@@ -77,7 +77,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -335,11 +336,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM850L_defconfig linux-2.4.21-rc3/arch/ppc/configs/TQM850L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM850L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/TQM850L_defconfig	2003-05-22 22:06:48.000000000 +0000
@@ -77,7 +77,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -335,11 +336,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM860L_defconfig linux-2.4.21-rc3/arch/ppc/configs/TQM860L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM860L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/TQM860L_defconfig	2003-05-22 22:06:40.000000000 +0000
@@ -77,7 +77,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -195,15 +195,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -228,6 +219,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -278,6 +270,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -380,11 +373,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/apus_defconfig linux-2.4.21-rc3/arch/ppc/configs/apus_defconfig
--- linux-2.4.20/arch/ppc/configs/apus_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/apus_defconfig	2003-05-22 22:06:51.000000000 +0000
@@ -33,6 +33,7 @@
 # CONFIG_ALL_PPC is not set
 CONFIG_APUS=y
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -167,6 +168,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
@@ -194,10 +197,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
@@ -265,15 +270,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
@@ -287,7 +283,6 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_IDEDOUBLER=y
@@ -295,10 +290,11 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -336,6 +332,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -374,6 +371,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_A3000_SCSI=y
 CONFIG_A4000T_SCSI=y
@@ -444,6 +442,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -538,6 +537,7 @@
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
@@ -600,6 +600,7 @@
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
 # I2C support
@@ -655,11 +656,18 @@
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_INPUT_AMIJOY is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -855,6 +863,7 @@
 CONFIG_SOUND_TRACEINIT=y
 CONFIG_SOUND_DMAP=y
 # CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
 # CONFIG_SOUND_SGALAXY is not set
 # CONFIG_SOUND_ADLIB is not set
 # CONFIG_SOUND_ACI_MIXER is not set
@@ -872,6 +881,7 @@
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_SB is not set
 # CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_KAHLUA is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 # CONFIG_SOUND_MAUI is not set
 # CONFIG_SOUND_YM3812 is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/briq_defconfig linux-2.4.21-rc3/arch/ppc/configs/briq_defconfig
--- linux-2.4.20/arch/ppc/configs/briq_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/briq_defconfig	2003-05-22 22:06:49.000000000 +0000
@@ -33,6 +33,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -67,13 +68,13 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 CONFIG_PPC601_SYNC_FIX=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-CONFIG_BOOTX_TEXT=y
 # CONFIG_PREP_RESIDUAL is not set
 # CONFIG_PROC_PREPRESIDUAL is not set
+CONFIG_PPCBUG_NVRAM=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -143,6 +144,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -170,10 +173,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 # CONFIG_IP_NF_TARGET_ULOG is not set
@@ -236,15 +241,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -258,8 +254,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -268,28 +264,30 @@
 # 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_ADMA100 is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -306,6 +304,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -343,6 +342,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -379,6 +379,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -423,6 +424,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -431,6 +433,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -465,6 +468,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -556,7 +560,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_BRIQ_PANEL=y
 
 #
 # I2C support
@@ -594,11 +597,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -795,3 +805,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+CONFIG_BOOTX_TEXT=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/bseip_defconfig linux-2.4.21-rc3/arch/ppc/configs/bseip_defconfig
--- linux-2.4.20/arch/ppc/configs/bseip_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/bseip_defconfig	2003-05-22 22:06:38.000000000 +0000
@@ -74,7 +74,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -232,6 +232,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -334,11 +335,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/common_defconfig linux-2.4.21-rc3/arch/ppc/configs/common_defconfig
--- linux-2.4.20/arch/ppc/configs/common_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/common_defconfig	2003-05-22 22:06:39.000000000 +0000
@@ -33,6 +33,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -71,13 +72,13 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 CONFIG_PPC601_SYNC_FIX=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-CONFIG_BOOTX_TEXT=y
 CONFIG_PREP_RESIDUAL=y
 CONFIG_PROC_PREPRESIDUAL=y
+CONFIG_PPCBUG_NVRAM=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
 
@@ -148,6 +149,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -175,10 +178,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
@@ -242,15 +247,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -264,8 +260,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -274,28 +270,30 @@
 # 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_ADMA100 is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -314,6 +312,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -355,6 +354,10 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC79XX is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
@@ -396,6 +399,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -443,6 +447,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -453,6 +458,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -487,6 +493,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -578,15 +585,19 @@
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
-# CONFIG_FB_MATROX_I2C is not set
 # CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MAVEN is not set
+CONFIG_FB_MATROX_PROC=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_GX=y
 CONFIG_FB_ATY_CT=y
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
@@ -647,7 +658,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -707,11 +717,18 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -880,6 +897,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -915,7 +934,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -953,6 +971,8 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1006,6 +1026,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
@@ -1043,3 +1064,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+CONFIG_BOOTX_TEXT=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/est8260_defconfig linux-2.4.21-rc3/arch/ppc/configs/est8260_defconfig
--- linux-2.4.20/arch/ppc/configs/est8260_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/est8260_defconfig	2003-05-22 22:06:47.000000000 +0000
@@ -57,7 +57,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -215,6 +215,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -318,11 +319,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -453,11 +461,6 @@
 # CONFIG_FEC_ENET is not set
 
 #
-# Generic MPC8260 Options
-#
-# CONFIG_DCACHE_DISABLE is not set
-
-#
 # USB support
 #
 # CONFIG_USB is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/gemini_defconfig linux-2.4.21-rc3/arch/ppc/configs/gemini_defconfig
--- linux-2.4.20/arch/ppc/configs/gemini_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/gemini_defconfig	2003-05-22 22:06:42.000000000 +0000
@@ -33,6 +33,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 CONFIG_GEMINI=y
 # CONFIG_SMP is not set
@@ -67,6 +68,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
 # CONFIG_PPC_RTC is not set
 # CONFIG_CMDLINE_BOOL is not set
 
@@ -219,6 +221,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -257,6 +260,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -310,6 +314,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -415,11 +420,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig linux-2.4.21-rc3/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/ibmchrp_defconfig	2003-05-22 22:06:43.000000000 +0000
@@ -33,6 +33,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -65,13 +66,13 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_PPC601_SYNC_FIX is not set
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-# CONFIG_BOOTX_TEXT is not set
 # CONFIG_PREP_RESIDUAL is not set
 # CONFIG_PROC_PREPRESIDUAL is not set
+CONFIG_PPCBUG_NVRAM=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -141,6 +142,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -168,10 +171,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
@@ -260,6 +265,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -298,6 +304,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -342,6 +349,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -350,6 +358,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -384,6 +393,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -460,12 +470,15 @@
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_PROC=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
@@ -520,7 +533,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -575,11 +587,18 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -775,3 +794,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+# CONFIG_BOOTX_TEXT is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/mbx_defconfig linux-2.4.21-rc3/arch/ppc/configs/mbx_defconfig
--- linux-2.4.20/arch/ppc/configs/mbx_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/mbx_defconfig	2003-05-22 22:06:24.000000000 +0000
@@ -74,7 +74,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -229,6 +229,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -330,11 +331,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/oak_defconfig linux-2.4.21-rc3/arch/ppc/configs/oak_defconfig
--- linux-2.4.20/arch/ppc/configs/oak_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/oak_defconfig	2003-05-22 22:06:26.000000000 +0000
@@ -59,6 +59,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -215,6 +216,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -317,11 +319,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/pal4_defconfig linux-2.4.21-rc3/arch/ppc/configs/pal4_defconfig
--- linux-2.4.20/arch/ppc/configs/pal4_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/pal4_defconfig	2003-05-22 22:06:45.000000000 +0000
@@ -33,6 +33,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 CONFIG_PAL4=y
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -65,6 +66,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
 # CONFIG_PPC_RTC is not set
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="ip=on"
@@ -139,6 +141,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -166,10 +170,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
@@ -267,6 +273,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -275,6 +282,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -309,6 +317,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -428,11 +437,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/pmac_defconfig linux-2.4.21-rc3/arch/ppc/configs/pmac_defconfig
--- linux-2.4.20/arch/ppc/configs/pmac_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/pmac_defconfig	2003-05-22 22:06:39.000000000 +0000
@@ -33,6 +33,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -75,13 +76,13 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 CONFIG_PPC601_SYNC_FIX=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-CONFIG_BOOTX_TEXT=y
 # CONFIG_PREP_RESIDUAL is not set
 # CONFIG_PROC_PREPRESIDUAL is not set
+CONFIG_PPCBUG_NVRAM=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -151,6 +152,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -178,10 +181,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
@@ -245,15 +250,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 CONFIG_BLK_DEV_IDECS=m
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -267,8 +263,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -277,28 +273,30 @@
 # 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_ADMA100 is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -313,10 +311,12 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
 CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -358,6 +358,10 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC79XX is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
@@ -399,6 +403,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -472,6 +477,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -482,6 +488,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -516,6 +523,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -635,6 +643,7 @@
 # CONFIG_USB_IRDA is not set
 # CONFIG_NSC_FIR is not set
 # CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_OLD is not set
 # CONFIG_TOSHIBA_FIR is not set
 # CONFIG_SMC_IRCC_FIR is not set
 # CONFIG_ALI_FIR is not set
@@ -676,15 +685,19 @@
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
-# CONFIG_FB_MATROX_I2C is not set
 # CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MAVEN is not set
+CONFIG_FB_MATROX_PROC=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_GX=y
 CONFIG_FB_ATY_CT=y
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
@@ -748,7 +761,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -808,11 +820,18 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -988,6 +1007,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -1023,7 +1044,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -1061,6 +1081,8 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1114,6 +1136,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
@@ -1151,3 +1174,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+CONFIG_BOOTX_TEXT=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/power3_defconfig linux-2.4.21-rc3/arch/ppc/configs/power3_defconfig
--- linux-2.4.20/arch/ppc/configs/power3_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/power3_defconfig	2003-05-22 22:06:38.000000000 +0000
@@ -72,12 +72,12 @@
 # CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
 # CONFIG_PARPORT_1284 is not set
-# CONFIG_PPC_RTC is not set
+CONFIG_GEN_RTC=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-# CONFIG_BOOTX_TEXT is not set
 # CONFIG_PREP_RESIDUAL is not set
 # CONFIG_PROC_PREPRESIDUAL is not set
+CONFIG_PPCBUG_NVRAM=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -219,6 +219,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -259,6 +260,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -303,6 +305,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -311,6 +314,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -345,6 +349,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -421,14 +426,17 @@
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
 CONFIG_FB_MATROX_G100=y
 CONFIG_FB_MATROX_I2C=y
 # CONFIG_FB_MATROX_MAVEN is not set
-# CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_PROC=y
 CONFIG_FB_MATROX_MULTIHEAD=y
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
@@ -486,7 +494,7 @@
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
-# CONFIG_BRIQ_PANEL is not set
+# CONFIG_TIPAR is not set
 
 #
 # I2C support
@@ -496,6 +504,8 @@
 # CONFIG_I2C_PHILIPSPAR is not set
 # CONFIG_I2C_ELV is not set
 # CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_I2C is not set
+# CONFIG_SCx200_ACB is not set
 CONFIG_I2C_ALGOPCF=y
 # CONFIG_I2C_ELEKTOR is not set
 # CONFIG_I2C_KEYWEST is not set
@@ -547,11 +557,18 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -730,6 +747,7 @@
 CONFIG_SOUND_TRACEINIT=y
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
 # CONFIG_SOUND_SGALAXY is not set
 # CONFIG_SOUND_ADLIB is not set
 # CONFIG_SOUND_ACI_MIXER is not set
@@ -747,6 +765,7 @@
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_SB is not set
 # CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_KAHLUA is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 # CONFIG_SOUND_MAUI is not set
 # CONFIG_SOUND_YM3812 is not set
@@ -787,3 +806,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+# CONFIG_BOOTX_TEXT is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig linux-2.4.21-rc3/arch/ppc/configs/rpxcllf_defconfig
--- linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/rpxcllf_defconfig	2003-05-22 22:06:39.000000000 +0000
@@ -14,7 +14,9 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Platform support
@@ -67,14 +69,22 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_M8XX=m
 
 #
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -232,6 +242,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -243,7 +254,21 @@
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
@@ -259,6 +284,11 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -334,11 +364,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -353,6 +390,12 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/rpxlite_defconfig linux-2.4.21-rc3/arch/ppc/configs/rpxlite_defconfig
--- linux-2.4.20/arch/ppc/configs/rpxlite_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/rpxlite_defconfig	2003-05-22 22:06:37.000000000 +0000
@@ -14,7 +14,9 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Platform support
@@ -67,14 +69,22 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_M8XX=m
 
 #
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -232,6 +242,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -243,7 +254,21 @@
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
@@ -259,6 +284,11 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -334,11 +364,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -353,6 +390,12 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/spruce_defconfig linux-2.4.21-rc3/arch/ppc/configs/spruce_defconfig
--- linux-2.4.20/arch/ppc/configs/spruce_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/spruce_defconfig	2003-05-22 22:06:38.000000000 +0000
@@ -33,8 +33,10 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 CONFIG_SPRUCE=y
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
+CONFIG_GEN550=y
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
 # CONFIG_TAU is not set
@@ -65,7 +67,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="ip=on"
 
@@ -218,6 +220,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -226,6 +229,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -260,6 +264,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -368,11 +373,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -504,3 +516,4 @@
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/walnut_defconfig linux-2.4.21-rc3/arch/ppc/configs/walnut_defconfig
--- linux-2.4.20/arch/ppc/configs/walnut_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/configs/walnut_defconfig	2003-05-22 22:06:51.000000000 +0000
@@ -31,6 +31,7 @@
 # CONFIG_PPC_STD_MMU is not set
 # CONFIG_OAK is not set
 CONFIG_WALNUT=y
+CONFIG_IBM405_ERR77=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 # CONFIG_MATH_EMULATION is not set
@@ -59,6 +60,7 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
+CONFIG_GEN_RTC=y
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -215,6 +217,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -321,11 +324,18 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/defconfig linux-2.4.21-rc3/arch/ppc/defconfig
--- linux-2.4.20/arch/ppc/defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/defconfig	2003-05-22 22:06:39.000000000 +0000
@@ -33,6 +33,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
 # CONFIG_SMP is not set
@@ -71,13 +72,13 @@
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
+CONFIG_GEN_RTC=y
 CONFIG_PPC601_SYNC_FIX=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_PPC_RTAS=y
-CONFIG_BOOTX_TEXT=y
 CONFIG_PREP_RESIDUAL=y
 CONFIG_PROC_PREPRESIDUAL=y
+CONFIG_PPCBUG_NVRAM=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
 
@@ -148,6 +149,8 @@
 #
 CONFIG_IP_NF_CONNTRACK=m
 CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
 CONFIG_IP_NF_IRC=m
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
@@ -175,10 +178,12 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
 # CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
 CONFIG_IP_NF_TARGET_ULOG=m
@@ -242,15 +247,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -264,8 +260,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -274,28 +270,30 @@
 # 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_ADMA100 is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -314,6 +312,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -355,6 +354,10 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC79XX is not set
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
@@ -396,6 +399,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -443,6 +447,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -453,6 +458,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
@@ -487,6 +493,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -578,15 +585,19 @@
 CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MILLENIUM=y
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
-# CONFIG_FB_MATROX_I2C is not set
 # CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MAVEN is not set
+CONFIG_FB_MATROX_PROC=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_GX=y
 CONFIG_FB_ATY_CT=y
 CONFIG_FB_RADEON=y
 CONFIG_FB_ATY128=y
+# CONFIG_FB_INTEL is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 CONFIG_FB_3DFX=y
@@ -647,7 +658,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -707,11 +717,18 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -880,6 +897,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -915,7 +934,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -953,6 +971,8 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1006,6 +1026,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
@@ -1043,3 +1064,4 @@
 CONFIG_XMON=y
 # CONFIG_BDI_SWITCH is not set
 # CONFIG_MORE_COMPILE_OPTIONS is not set
+CONFIG_BOOTX_TEXT=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/Makefile linux-2.4.21-rc3/arch/ppc/kernel/Makefile
--- linux-2.4.20/arch/ppc/kernel/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux kernel.
 #
@@ -38,13 +36,18 @@
 					process.o signal.o ptrace.o align.o \
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o
-obj-$(CONFIG_6xx)		+= l2cr.o
+obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_PCI)		+= pci.o 
 obj-$(CONFIG_PCI)		+= pci-dma.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
+obj-$(CONFIG_PPCBUG_NVRAM)	+= prep_nvram.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_TAU)		+= temp.o
+ifeq ($(CONFIG_SERIAL)$(CONFIG_GEN550),yy)
+obj-$(CONFIG_KGDB)		+= gen550_kgdb.o gen550_dbg.o
+obj-$(CONFIG_SERIAL_TEXT_DEBUG)	+= gen550_dbg.o
+endif
 obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
@@ -55,8 +58,10 @@
 endif
 obj-$(CONFIG_MBX)		+= i8259.o
 obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
-					indirect_pci.o i8259.o prep_nvram.o
+					indirect_pci.o i8259.o
 obj-$(CONFIG_GEMINI)		+= open_pic.o
+obj-$(CONFIG_LOPEC)		+= mpc10x_common.o indirect_pci.o pci_auto.o \
+					open_pic.o i8259.o todc_time.o
 obj-$(CONFIG_PAL4)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_SPRUCE)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/align.c linux-2.4.21-rc3/arch/ppc/kernel/align.c
--- linux-2.4.20/arch/ppc/kernel/align.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/align.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.align.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  * align.c - handle alignment exceptions for the Power PC.
  *
  * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
@@ -28,7 +25,7 @@
 #define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)
 #define	RS(inst)	(((inst) & 0x03E00000) >> 21)
 #define	RA(inst)	(((inst) & 0x001F0000) >> 16)
-#define	IS_DFORM(code)	((code) >= 32 && (code) <= 47)
+#define	IS_XFORM(code)	((code) == 31)
 #endif
 
 #define INVALID	{ 0, 0 }
@@ -64,9 +61,9 @@
 	{ 4, ST+F+S },		/* 00 0 1010: stfs */
 	{ 8, ST+F },		/* 00 0 1011: stfd */
 	INVALID,		/* 00 0 1100 */
-	INVALID,		/* 00 0 1101 */
+	INVALID,		/* 00 0 1101: ld/ldu/lwa */
 	INVALID,		/* 00 0 1110 */
-	INVALID,		/* 00 0 1111 */
+	INVALID,		/* 00 0 1111: std/stdu */
 	{ 4, LD+U },		/* 00 1 0000: lwzu */
 	INVALID,		/* 00 1 0001 */
 	{ 4, ST+U },		/* 00 1 0010: stwu */
@@ -83,12 +80,12 @@
 	INVALID,		/* 00 1 1101 */
 	INVALID,		/* 00 1 1110 */
 	INVALID,		/* 00 1 1111 */
-	INVALID,		/* 01 0 0000 */
+	INVALID,		/* 01 0 0000: ldx */
 	INVALID,		/* 01 0 0001 */
-	INVALID,		/* 01 0 0010 */
+	INVALID,		/* 01 0 0010: stdx */
 	INVALID,		/* 01 0 0011 */
 	INVALID,		/* 01 0 0100 */
-	INVALID,		/* 01 0 0101: lwax?? */
+	INVALID,		/* 01 0 0101: lwax */
 	INVALID,		/* 01 0 0110 */
 	INVALID,		/* 01 0 0111 */
 	{ 0, LD+HARD },		/* 01 0 1000: lswx */
@@ -99,12 +96,12 @@
 	INVALID,		/* 01 0 1101 */
 	INVALID,		/* 01 0 1110 */
 	INVALID,		/* 01 0 1111 */
-	INVALID,		/* 01 1 0000 */
+	INVALID,		/* 01 1 0000: ldux */
 	INVALID,		/* 01 1 0001 */
-	INVALID,		/* 01 1 0010 */
+	INVALID,		/* 01 1 0010: stdux */
 	INVALID,		/* 01 1 0011 */
 	INVALID,		/* 01 1 0100 */
-	INVALID,		/* 01 1 0101: lwaux?? */
+	INVALID,		/* 01 1 0101: lwaux */
 	INVALID,		/* 01 1 0110 */
 	INVALID,		/* 01 1 0111 */
 	INVALID,		/* 01 1 1000 */
@@ -160,9 +157,9 @@
 	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
 	{ 8, ST+F },		/* 11 0 1011: stfdx */
 	INVALID,		/* 11 0 1100 */
-	INVALID,		/* 11 0 1101 */
+	INVALID,		/* 11 0 1101: lmd */
 	INVALID,		/* 11 0 1110 */
-	INVALID,		/* 11 0 1111 */
+	INVALID,		/* 11 0 1111: stmd */
 	{ 4, LD+U },		/* 11 1 0000: lwzux */
 	INVALID,		/* 11 1 0001 */
 	{ 4, ST+U },		/* 11 1 0010: stwux */
@@ -212,7 +209,7 @@
 	reg = RS(instr);
 	areg = RA(instr);
 
-	if (IS_DFORM(opcode)) {
+	if (!IS_XFORM(opcode)) {
 		f1 = 0;
 		f2 = (instr & 0x04000000) >> 26;
 		f3 = (instr & 0x78000000) >> 27;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/bitops.c linux-2.4.21-rc3/arch/ppc/kernel/bitops.c
--- linux-2.4.20/arch/ppc/kernel/bitops.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/bitops.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bitops.c 1.7 05/17/01 18:14:21 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 
@@ -21,8 +18,9 @@
 	
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	or	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	or	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -38,8 +36,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	andc	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	andc	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -55,8 +54,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	xor	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	xor	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -72,8 +72,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	or	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	or	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -91,8 +92,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	andc	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	andc	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -110,8 +112,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	xor	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	xor	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/btext.c linux-2.4.21-rc3/arch/ppc/kernel/btext.c
--- linux-2.4.20/arch/ppc/kernel/btext.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/btext.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for drawing on the screen early on in the boot process.
  *
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/checks.c linux-2.4.21-rc3/arch/ppc/kernel/checks.c
--- linux-2.4.20/arch/ppc/kernel/checks.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/checks.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.checks.c 1.6 05/17/01 18:14:21 cort
- */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/cpu_setup_6xx.S linux-2.4.21-rc3/arch/ppc/kernel/cpu_setup_6xx.S
--- linux-2.4.20/arch/ppc/kernel/cpu_setup_6xx.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/cpu_setup_6xx.S	2003-05-22 22:06:53.000000000 +0000
@@ -0,0 +1,415 @@
+/*
+ * This file contains low level CPU setup functions.
+ *    Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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 <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/cache.h>
+#include "ppc_defs.h"
+
+_GLOBAL(__setup_cpu_601)
+	blr
+_GLOBAL(__setup_cpu_603)
+	b	setup_common_caches
+_GLOBAL(__setup_cpu_604)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_604_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750cx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750cx
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750fx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750fx
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7400)
+	mflr	r4
+	bl	setup_7400_workarounds
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7410)
+	mflr	r4
+	bl	setup_7410_workarounds
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	li	r3,0
+	mtspr	SPRN_L2CR2,r3
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_745x)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_745x_specifics
+	mtlr	r4
+	blr
+
+/* Enable caches for 603's, 604, 750 & 7400 */
+setup_common_caches:
+	mfspr	r11,HID0
+	andi.	r0,r11,HID0_DCE
+	ori	r11,r11,HID0_ICE|HID0_DCE
+	ori	r8,r11,HID0_ICFI
+	bne	1f			/* don't invalidate the D-cache */
+	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
+1:	sync
+	mtspr	HID0,r8			/* enable and invalidate caches */
+	sync
+	mtspr	HID0,r11		/* enable caches */
+	sync
+	isync
+	blr
+
+/* 604, 604e, 604ev, ...
+ * Enable superscalar execution & branch history table
+ */
+setup_604_hid0:
+	mfspr	r11,HID0
+	ori	r11,r11,HID0_SIED|HID0_BHTE
+	ori	r8,r11,HID0_BTCD
+	sync
+	mtspr	HID0,r8		/* flush branch target address cache */
+	sync			/* on 604e/604r */
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
+ * erratas we work around here.
+ * Moto MPC710CE.pdf describes them, those are errata
+ * #3, #4 and #5
+ * Note that we assume the firmware didn't choose to
+ * apply other workarounds (there are other ones documented
+ * in the .pdf). It appear that Apple firmware only works
+ * around #3 and with the same fix we use. We may want to
+ * check if the CPU is using 60x bus mode in which case
+ * the workaround for errata #4 is useless. Also, we may
+ * want to explicitely clear HID0_NOPDST as this is not
+ * needed once we have applied workaround #5 (though it's
+ * not set by Apple's firmware at least).
+ */
+setup_7400_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0207
+	ble	1f
+	blr
+setup_7410_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0100
+	bnelr
+1:
+	mfspr	r11,SPRN_MSSSR0
+	/* Errata #3: Set L1OPQ_SIZE to 0x10 */
+	rlwinm	r11,r11,0,9,6
+	oris	r11,r11,0x0100
+	/* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */
+	oris	r11,r11,0x0002
+	/* Errata #5: Set DRLT_SIZE to 0x01 */
+	rlwinm	r11,r11,0,5,2
+	oris	r11,r11,0x0800
+	sync
+	mtspr	SPRN_MSSSR0,r11
+	sync
+	isync
+	blr
+	
+/* 740/750/7400/7410
+ * Enable Store Gathering (SGE), Address Brodcast (ABE),
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Clear Instruction cache throttling (ICTC)
+ */
+setup_750_7400_hid0:
+	mfspr	r11,HID0
+	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
+BEGIN_FTR_SECTION
+	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+	li	r3,HID0_SPD
+	andc	r11,r11,r3		/* clear SPD: enable speculative */
+ 	li	r3,0
+ 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+	isync
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 750cx specific
+ * Looks like we have to disable NAP feature for some PLL settings...
+ * (waiting for confirmation)
+ */
+setup_750cx:
+	mfspr	r10, SPRN_HID1
+	rlwinm	r10,r10,4,28,31
+	cmpi	cr0,r10,7
+	cmpi	cr1,r10,9
+	cmpi	cr2,r10,11
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	bnelr
+	lwz	r6,CPU_SPEC_FEATURES(r5)
+	li	r7,CPU_FTR_CAN_NAP
+	andc	r6,r6,r7
+	stw	r6,CPU_SPEC_FEATURES(r5)
+	blr
+
+/* 750fx specific
+ */
+setup_750fx:
+	blr
+
+/* MPC 745x
+ * Enable Store Gathering (SGE), Branch Folding (FOLD)
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Ensure our data cache instructions really operate.
+ * Timebase has to be running or we wouldn't have made it here,
+ * just ensure we don't disable it.
+ * Clear Instruction cache throttling (ICTC)
+ * Enable L2 HW prefetch
+ */
+setup_745x_specifics:
+	/* We check for the presence of an L3 cache setup by
+	 * the firmware. If any, we disable NAP capability as
+	 * it's known to be bogus on rev 2.1 and earlier
+	 */
+	mfspr	r11,SPRN_L3CR
+	andis.	r11,r11,L3CR_L3E@h
+	beq	1f
+	lwz	r6,CPU_SPEC_FEATURES(r5)
+	andi.	r0,r6,CPU_FTR_L3_DISABLE_NAP
+	beq	1f
+	li	r7,CPU_FTR_CAN_NAP
+	andc	r6,r6,r7
+	stw	r6,CPU_SPEC_FEATURES(r5)
+1:	
+	mfspr	r11,HID0
+
+	/* All of the bits we have to set.....
+	 */
+	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
+BEGIN_FTR_SECTION
+	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+
+	/* All of the bits we have to clear....
+	 */
+	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
+	andc	r11,r11,r3		/* clear SPD: enable speculative */
+ 	li	r3,0
+
+ 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+	isync
+	mtspr	HID0,r11
+	sync
+	isync
+
+	/* Enable L2 HW prefetch
+	 */
+	mfspr	r3,SPRN_MSSCR0
+	ori	r3,r3,3
+	sync
+	mtspr	SPRN_MSSCR0,r3
+	sync
+	isync
+	blr
+
+/* Definitions for the table use to save CPU states */
+#define CS_HID0		0
+#define CS_HID1		4
+#define	CS_MSSCR0	8
+#define CS_MSSSR0	12
+#define CS_ICTRL	16
+#define CS_LDSTCR	20
+#define CS_LDSTDB	24
+#define CS_SIZE		28
+
+	.data
+	.balign	L1_CACHE_LINE_SIZE
+cpu_state_storage:	
+	.space	CS_SIZE
+	.balign	L1_CACHE_LINE_SIZE,0
+	.text
+	
+/* Called in normal context to backup CPU 0 state. This
+ * does not include cache settings. This function is also
+ * called for machine sleep. This does not include the MMU
+ * setup, BATs, etc... but rather the "special" registers
+ * like HID0, HID1, MSSCR0, etc...
+ */
+_GLOBAL(__save_cpu_setup)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	lis	r5,cpu_state_storage@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* Save HID0 (common to all CONFIG_6xx cpus) */
+	mfspr	r3,SPRN_HID0
+	stw	r3,CS_HID0(r5)
+
+	/* Now deal with CPU type dependent registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x8002	/* 7457 */
+	cmpli	cr5,r3,0x7000	/* 750FX */
+	/* cr1 is 7400 || 7410 */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	/* cr0 is 74xx */
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr4+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	/* Backup 74xx specific regs */
+	mfspr	r4,SPRN_MSSCR0
+	stw	r4,CS_MSSCR0(r5)
+	mfspr	r4,SPRN_MSSSR0
+	stw	r4,CS_MSSSR0(r5)
+	beq	cr1,1f
+	/* Backup 745x specific registers */
+	mfspr	r4,SPRN_HID1
+	stw	r4,CS_HID1(r5)
+	mfspr	r4,SPRN_ICTRL
+	stw	r4,CS_ICTRL(r5)
+	mfspr	r4,SPRN_LDSTCR
+	stw	r4,CS_LDSTCR(r5)
+	mfspr	r4,SPRN_LDSTDB
+	stw	r4,CS_LDSTDB(r5)
+1:	
+	bne	cr5,1f
+	/* Backup 750FX specific registers */
+	mfspr	r4,SPRN_HID1
+	stw	r4,CS_HID1(r5)
+1:
+	mtcr	r7
+	blr
+
+/* Called with no MMU context (typically MSR:IR/DR off) to
+ * restore CPU state as backed up by the previous
+ * function. This does not include cache setting
+ */
+_GLOBAL(__restore_cpu_setup)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	lis	r5,(cpu_state_storage-KERNELBASE)@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* Restore HID0 */
+	lwz	r3,CS_HID0(r5)
+	sync
+	isync
+	mtspr	SPRN_HID0,r3
+	sync
+	isync
+
+	/* Now deal with CPU type dependent registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x8002	/* 7457 */
+	cmpli	cr5,r3,0x7000	/* 750FX */
+	/* cr1 is 7400 || 7410 */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	/* cr0 is 74xx */
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr4+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	2f
+	/* Restore 74xx specific regs */
+	lwz	r4,CS_MSSCR0(r5)
+	sync
+	mtspr	SPRN_MSSCR0,r4
+	sync
+	isync
+	lwz	r4,CS_MSSSR0(r5)
+	sync
+	mtspr	SPRN_MSSSR0,r4
+	sync
+	isync
+	bne	cr2,1f
+	/* Clear 7410 L2CR2 */
+	li	r4,0
+	mtspr	SPRN_L2CR2,r4
+1:	beq	cr1,2f
+	/* Restore 745x specific registers */
+	lwz	r4,CS_HID1(r5)
+	sync
+	mtspr	SPRN_HID1,r4
+	isync
+	sync
+	lwz	r4,CS_ICTRL(r5)
+	sync
+	mtspr	SPRN_ICTRL,r4
+	isync
+	sync
+	lwz	r4,CS_LDSTCR(r5)
+	sync
+	mtspr	SPRN_LDSTCR,r4
+	isync
+	sync
+	lwz	r4,CS_LDSTDB(r5)
+	sync
+	mtspr	SPRN_LDSTDB,r4
+	isync
+	sync
+2:	bne	cr5,1f
+	/* Restore 750FX specific registers
+	 * that is restore PLL config & switch
+	 * to PLL 0
+	 */
+	lwz	r4,CS_HID1(r5)
+	rlwinm  r5,r4,0,16,14
+	mtspr	SPRN_HID1,r5
+		/* Wait for PLL to stabilize */
+	mftbl	r5
+3:	mftbl	r6
+	sub	r6,r6,r5
+	cmpli	cr0,r6,10000
+	ble	3b
+	/* Setup final PLL */
+	mtspr	SPRN_HID1,r4
+1:
+	mtcr	r7
+	blr
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/cputable.c linux-2.4.21-rc3/arch/ppc/kernel/cputable.c
--- linux-2.4.20/arch/ppc/kernel/cputable.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/cputable.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/cputable.c
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
@@ -29,8 +26,7 @@
 extern void __setup_cpu_750fx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_7400(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_7410(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
-extern void __setup_cpu_7450(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
-extern void __setup_cpu_7455(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_745x(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_power3(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_power4(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_8xx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
@@ -38,7 +34,7 @@
 
 #define CLASSIC_PPC (!defined(CONFIG_8xx) && 	 \
 		     !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) &&  \
-		     !defined(CONFIG_POWER4) && !defined(CONFIG_PPC_ISERIES))
+		     !defined(CONFIG_POWER4))
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -144,11 +140,20 @@
 	32, 32,
 	__setup_cpu_750cx
     },
-    {	/* 750FX (All revs for now) */
+    {	/* 750FX rev 2.0 must disable HID0[DPM] */
+    	0xffffffff, 0x70000200, "750FX",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP |
+	CPU_FTR_NO_DPM,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_750
+    },
+    {	/* 750FX (All revs except 2.0) */
     	0xffff0000, 0x70000000, "750FX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
 	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP |
-	CPU_FTR_DUAL_PLL_750FX,
+	CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750fx
@@ -195,7 +200,7 @@
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7450
+	__setup_cpu_745x
     },
     {	/* 7450 2.1 */
     	0xffffffff, 0x80000201, "7450",
@@ -205,7 +210,7 @@
 	CPU_FTR_L3_DISABLE_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7450
+	__setup_cpu_745x
     },
     {	/* 7450 2.3 and newer */
     	0xffff0000, 0x80000000, "7450",
@@ -214,35 +219,46 @@
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7450
+	__setup_cpu_745x
     },
     {	/* 7455 rev 1.x */
     	0xffffff00, 0x80010100, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
 	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
-	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7455
+	__setup_cpu_745x
     },
     {	/* 7455 rev 2.0 */
     	0xffffffff, 0x80010200, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
 	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
-	CPU_FTR_L3_DISABLE_NAP,
+	CPU_FTR_L3_DISABLE_NAP | CPU_FTR_HAS_HIGH_BATS,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7455
+	__setup_cpu_745x
     },
     {	/* 7455 others */
     	0xffff0000, 0x80010000, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
 	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
-	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR,
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+	CPU_FTR_HAS_HIGH_BATS,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_745x
+    },
+    {	/* 7457 */
+    	0xffff0000, 0x80020000, "7457",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
+	CPU_FTR_HAS_HIGH_BATS,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7455
+	__setup_cpu_745x
     },
     {	/* 82xx (8240, 8245, 8260 are all 603e cores) */
 	0x7fff0000, 0x00810000, "82xx",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/entry.S linux-2.4.21-rc3/arch/ppc/kernel/entry.S
--- linux-2.4.20/arch/ppc/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/entry.S	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.entry.S 1.26 01/25/02 15:15:24 benh
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP
@@ -166,7 +163,6 @@
 	.globl	ret_from_syscall_2
 ret_from_syscall_2:
 	stw	r3,RESULT(r1)	/* Save result */	
-	stw	r3,GPR0(r1)	/* temporary gross hack to make strace work */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	60f
@@ -314,6 +310,7 @@
 	SYNC			/* Some chip revs have problems here... */
 	mtmsr	r0		/* Update machine state */
 
+	PPC405_ERR77(0,r1)
 	stwcx.	r0,0,r1		/* to clear the reservation */
 
 	/* if returning to user mode, set new sprg2 and save kernel SP */
@@ -377,6 +374,7 @@
 	lwz	r4,GPR4(r1)
 	lwz	r1,GPR1(r1)
 	SYNC
+	PPC405_ERR77_SYNC
 	RFI
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/find_name.c linux-2.4.21-rc3/arch/ppc/kernel/find_name.c
--- linux-2.4.20/arch/ppc/kernel/find_name.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/find_name.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.find_name.c 1.5 05/17/01 18:14:21 cort
- */
 #include <stdio.h>
 #include <asm/page.h>
 #include <sys/mman.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/galaxy_pci.c linux-2.4.21-rc3/arch/ppc/kernel/galaxy_pci.c
--- linux-2.4.20/arch/ppc/kernel/galaxy_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/galaxy_pci.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 2000 Grant Erickson <grant@borg.umn.edu>
  *    All rights reserved.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/gen550_dbg.c linux-2.4.21-rc3/arch/ppc/kernel/gen550_dbg.c
--- linux-2.4.20/arch/ppc/kernel/gen550_dbg.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/gen550_dbg.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,154 @@
+/*
+ * arch/ppc/kernel/gen550_dbg.c
+ *
+ * A library of polled 16550 serial routines.  These are intended to
+ * be used to support progress messages, xmon, kgdb, etc. on a
+ * variety of platforms.
+ *
+ * Adapted from lots of code ripped from the arch/ppc/boot/ polled
+ * 16550 support.
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * 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/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+
+#define SERIAL_BAUD	9600
+
+extern struct serial_state rs_table[];
+
+static void (*serial_outb)(unsigned long, unsigned char);
+static unsigned long (*serial_inb)(unsigned long);
+
+static int shift;
+
+unsigned long direct_inb(unsigned long addr)
+{
+	return readb(addr);
+}
+
+void direct_outb(unsigned long addr, unsigned char val)
+{
+	writeb(val, addr);
+}
+
+unsigned long io_inb(unsigned long port)
+{
+	return inb(port);
+}
+
+void io_outb(unsigned long port, unsigned char val)
+{
+	outb(val, port);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+	unsigned long com_port;
+
+	/* We need to find out which type io we're expecting.  If it's
+	 * 'SERIAL_IO_PORT', we get an offset from the isa_io_base.
+	 * If it's 'SERIAL_IO_MEM', we can the exact location.  -- Tom */
+	switch (rs_table[chan].io_type) {
+		case SERIAL_IO_PORT:
+			com_port = rs_table[chan].port;
+			serial_outb = io_outb;
+			serial_inb = io_inb;
+			break;
+		case SERIAL_IO_MEM:
+			com_port = (unsigned long)rs_table[chan].iomem_base;
+			serial_outb = direct_outb;
+			serial_inb = direct_inb;
+			break;
+		default:
+			/* We can't deal with it. */
+			return -1;
+	}
+
+	/* How far apart the registers are. */
+	shift = rs_table[chan].iomem_reg_shift;
+	
+	/* Access baud rate */
+	serial_outb(com_port + (UART_LCR << shift), 0x80);
+
+	/* Input clock. */
+	serial_outb(com_port + (UART_DLL << shift),
+			(rs_table[chan].baud_base / SERIAL_BAUD) & 0xFF);
+	serial_outb(com_port + (UART_DLM << shift),
+			(rs_table[chan].baud_base / SERIAL_BAUD) >> 8);
+	/* 8 data, 1 stop, no parity */
+	serial_outb(com_port + (UART_LCR << shift), 0x03);
+	/* RTS/DTR */
+	serial_outb(com_port + (UART_MCR << shift), 0x03);
+
+	/* Clear & enable FIFOs */
+	serial_outb(com_port + (UART_FCR << shift), 0x07);
+
+	return (com_port);
+}
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+	while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0)
+		;
+	serial_outb(com_port, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+	while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0)
+		;
+	return serial_inb(com_port);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+	return ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
+}
+
+void
+serial_close(unsigned long com_port)
+{
+}
+
+void
+gen550_init(int i, struct serial_struct *serial_req)
+{
+	rs_table[i].io_type = serial_req->io_type;
+	rs_table[i].port = serial_req->port;
+	rs_table[i].iomem_base = serial_req->iomem_base;
+	rs_table[i].iomem_reg_shift = serial_req->iomem_reg_shift;
+}
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+void
+gen550_progress(char *s, unsigned short hex)
+{
+	volatile unsigned int progress_debugport;
+	volatile char c;
+
+	progress_debugport = serial_init(0, NULL);
+
+	serial_putc(progress_debugport, '\r');
+
+	while ((c = *s++) != 0)
+		serial_putc(progress_debugport, c);
+
+	serial_putc(progress_debugport, '\n');
+	serial_putc(progress_debugport, '\r');
+}
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/gen550_kgdb.c linux-2.4.21-rc3/arch/ppc/kernel/gen550_kgdb.c
--- linux-2.4.20/arch/ppc/kernel/gen550_kgdb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/gen550_kgdb.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * arch/ppc/kernel/gen550_kgdb.c
+ *
+ * Generic 16550 kgdb support intended to be useful on a variety
+ * of platforms.  To enable this support, it is necessary to set
+ * the CONFIG_GEN550 option.  Any virtual mapping of the serial
+ * port(s) to be used can be accomplished by setting
+ * ppc_md.early_serial_map to a platform-specific mapping function.
+ *
+ * Adapted from ppc4xx_kgdb.c. 
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+
+#include <asm/machdep.h>
+
+extern unsigned long serial_init(int, void *);
+extern unsigned long serial_getc(unsigned long);
+extern unsigned long serial_putc(unsigned long, unsigned char);
+
+#if defined(CONFIG_KGDB_TTYS0)
+#define KGDB_PORT 0
+#elif defined(CONFIG_KGDB_TTYS1)
+#define KGDB_PORT 1
+#elif defined(CONFIG_KGDB_TTYS2)
+#define KGDB_PORT 2
+#elif defined(CONFIG_KGDB_TTYS3)
+#define KGDB_PORT 3
+#else
+#error "invalid kgdb_tty port"
+#endif
+
+static volatile unsigned int kgdb_debugport;
+
+void putDebugChar(unsigned char c)
+{
+	if (kgdb_debugport == 0)
+		kgdb_debugport = serial_init(KGDB_PORT, NULL);
+
+	serial_putc(kgdb_debugport, c);
+}
+
+int getDebugChar(void)
+{
+	if (kgdb_debugport == 0)
+		kgdb_debugport = serial_init(KGDB_PORT, NULL);
+
+	return(serial_getc(kgdb_debugport));
+}
+
+void kgdb_interruptible(int enable)
+{
+	return;
+}
+
+void putDebugString(char* str)
+{
+	while (*str != '\0') {
+		putDebugChar(*str);
+		str++;
+	}
+	putDebugChar('\r');
+	return;
+}
+
+void
+kgdb_map_scc(void)
+{
+	printk("kgdb init\n");
+	if (ppc_md.early_serial_map)
+		ppc_md.early_serial_map();
+	kgdb_debugport = serial_init(KGDB_PORT, NULL);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head.S linux-2.4.21-rc3/arch/ppc/kernel/head.S
--- linux-2.4.20/arch/ppc/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/head.S	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -144,7 +141,7 @@
  * early_init() does the early machine identification and does
  * the necessary low-level setup and clears the BSS
  *  -- Cort <cort@fsmlabs.com>
- */ 
+ */
 	bl	early_init
 
 #ifdef CONFIG_APUS
@@ -155,7 +152,6 @@
 	bl	fix_mem_constants
 #endif /* CONFIG_APUS */
 
-#ifndef CONFIG_GEMINI
 /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
  * the physical address we are running at, returned by early_init()
  */
@@ -163,7 +159,6 @@
 __after_mmu_off:
 	bl	clear_bats
 	bl	flush_tlbs
-#endif
 
 #ifndef CONFIG_POWER4
 	/* POWER4 doesn't have BATs */
@@ -203,8 +198,7 @@
  * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
  * the exception vectors at 0 (and therefore this copy
  * overwrites OF's exception vectors with our own).
- * If the MMU is already turned on, we copy stuff to KERNELBASE,
- * otherwise we copy it to 0.
+ * The MMU is off at this point.
  */
 	bl	reloc_offset
 	mr	r26,r3
@@ -794,6 +788,9 @@
 	stw	r22,THREAD_VRSAVE(r23)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
+#ifndef CONFIG_6xx
+2:
+#endif
 	.globl transfer_to_handler_cont
 transfer_to_handler_cont:
 	tovirt(r2,r2)
@@ -816,12 +813,12 @@
 	mtlr	r23
 	SYNC
 	RFI				/* jump to handler, enable MMU */
+
+#ifdef CONFIG_6xx
 2:
 	/* Out of line case when returning to kernel,
 	 * check return from power_save_6xx
 	 */
-#ifdef CONFIG_6xx
-	
 	mfspr	r24,SPRN_HID0
 	mtcr	r24
 BEGIN_FTR_SECTION
@@ -831,7 +828,6 @@
 	bt-	9,power_save_6xx_restore	/* Check NAP */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 	b	transfer_to_handler_cont
-
 #endif /* CONFIG_6xx */
 
 /*
@@ -853,11 +849,11 @@
 	RFI
 
 /*
- * Disable FP for the task which had the FPU previously,
+ * This task wants to use the FPU now.
+ * On UP, disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * Load up this task's FP registers from its thread_struct,
+ * enable the FPU for the current task and return to the task.
  */
 load_up_fpu:
 	mfmsr	r5
@@ -874,14 +870,13 @@
  * to another.  Instead we call giveup_fpu in switch_to.
  */
 #ifndef CONFIG_SMP
-	lis	r6,0                    /* get __pa constant */
-	tophys(r6,r6)
+	tophys(r6,0)			/* get __pa constant */
 	addis	r3,r6,last_task_used_math@ha
 	lwz	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
 	add	r4,r4,r6
-	addi	r4,r4,THREAD	        /* want THREAD of last_task_used_math */
+	addi	r4,r4,THREAD		/* want last_task_used_math->thread */
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,THREAD_FPSCR-4(r4)
@@ -894,8 +889,10 @@
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	lwz	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP		/* enable FP for current */
+	or	r23,r23,r4
 	lfd	fr0,THREAD_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
@@ -1075,9 +1072,10 @@
 giveup_fpu:
 	mfmsr	r5
 	ori	r5,r5,MSR_FP
-	SYNC
+	SYNC_601
+	ISYNC_601
 	mtmsr	r5			/* enable use of fpu now */
-	SYNC
+	SYNC_601
 	isync
 	cmpi	0,r3,0
 	beqlr-				/* if no previous owner, done */
@@ -1268,6 +1266,8 @@
 	MTMSRD(r0)
 	isync
 #endif
+	/* Copy some CPU settings from CPU 0 */
+	bl	__restore_cpu_setup
 
 	lis	r3,-KERNELBASE@h
 	mr	r4,r24
@@ -1314,191 +1314,20 @@
 #endif /* CONFIG_SMP */
 
 /*
- * Enable caches and 604-specific features if necessary.
+ * Those generic dummy functions are kept for CPUs not
+ * included in CONFIG_6xx
  */
-_GLOBAL(__setup_cpu_601)
-	blr
-_GLOBAL(__setup_cpu_603)
-	b	setup_common_caches
-_GLOBAL(__setup_cpu_604)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_604_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750cx)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	bl	setup_750cx
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750fx)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	bl	setup_750fx
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7400)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7410)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	li	r3,0
-	mtspr	SPRN_L2CR2,r3
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7450)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_745x_specifics
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7455)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_745x_specifics
-	mtlr	r4
-	blr
 _GLOBAL(__setup_cpu_power3)
 	blr
-_GLOBAL(__setup_cpu_power4)
-	blr
 _GLOBAL(__setup_cpu_generic)
 	blr
 
-/* Enable caches for 603's, 604, 750 & 7400 */
-setup_common_caches:
-	mfspr	r11,HID0
-	andi.	r0,r11,HID0_DCE
-#ifdef CONFIG_DCACHE_DISABLE
-	ori	r11,r11,HID0_ICE
-#else
-	ori	r11,r11,HID0_ICE|HID0_DCE
-#endif
-	ori	r8,r11,HID0_ICFI
-	bne	1f			/* don't invalidate the D-cache */
-	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
-1:	sync
-	mtspr	HID0,r8			/* enable and invalidate caches */
-	sync
-	mtspr	HID0,r11		/* enable caches */
-	sync
-	isync
-	blr
-
-/* 604, 604e, 604ev, ...
- * Enable superscalar execution & branch history table
- */
-setup_604_hid0:
-	mfspr	r11,HID0
-	ori	r11,r11,HID0_SIED|HID0_BHTE
-	ori	r8,r11,HID0_BTCD
-	sync
-	mtspr	HID0,r8		/* flush branch target address cache */
-	sync			/* on 604e/604r */
-	mtspr	HID0,r11
-	sync
-	isync
-	blr
-
-/* 740/750/7400/7410
- * Enable Store Gathering (SGE), Address Brodcast (ABE),
- * Branch History Table (BHTE), Branch Target ICache (BTIC)
- * Dynamic Power Management (DPM), Speculative (SPD)
- * Clear Instruction cache throttling (ICTC)
- */
-setup_750_7400_hid0:
-	mfspr	r11,HID0
-	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-	li	r3,HID0_SPD
-	andc	r11,r11,r3		/* clear SPD: enable speculative */
- 	li	r3,0
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-	isync
-	mtspr	HID0,r11
-	sync
-	isync
-	blr
-
-/* 750cx specific
- * Looks like we have to disable NAP feature for some PLL settings...
- * (waiting for confirmation)
- */
-setup_750cx:
+#ifndef CONFIG_6xx
+_GLOBAL(__save_cpu_setup)
 	blr
-
-/* 750fx specific
- */
-setup_750fx:
-	blr
-
-/* MPC 745x
- * Enable Store Gathering (SGE), Branch Folding (FOLD)
- * Branch History Table (BHTE), Branch Target ICache (BTIC)
- * Dynamic Power Management (DPM), Speculative (SPD)
- * Ensure our data cache instructions really operate.
- * Timebase has to be running or we wouldn't have made it here,
- * just ensure we don't disable it.
- * Clear Instruction cache throttling (ICTC)
- * Enable L2 HW prefetch
- */
-setup_745x_specifics:
-	/* We check for the presence of an L3 cache setup by
-	 * the firmware. If any, we disable NAP capability as
-	 * it's known to be bogus on rev 2.1 and earlier
-	 */
-	mfspr	r11,SPRN_L3CR
-	andis.	r11,r11,L3CR_L3E@h
-	beq	1f
-	lwz	r6,CPU_SPEC_FEATURES(r5)
-	andi.	r0,r6,CPU_FTR_L3_DISABLE_NAP
-	beq	1f
-	li	r7,CPU_FTR_CAN_NAP
-	andc	r6,r6,r7
-	stw	r6,CPU_SPEC_FEATURES(r5)
-1:	
-	mfspr	r11,HID0
-
-	/* All of the bits we have to set.....
-	 */
-	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-
-	/* All of the bits we have to clear....
-	 */
-	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
-	andc	r11,r11,r3		/* clear SPD: enable speculative */
- 	li	r3,0
-
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-	isync
-	mtspr	HID0,r11
-	sync
-	isync
-
-	/* Enable L2 HW prefetch
-	 */
-	mfspr	r3,SPRN_MSSCR0
-	ori	r3,r3,3
-	sync
-	mtspr	SPRN_MSSCR0,r3
-	sync
-	isync
+_GLOBAL(__restore_cpu_setup)
 	blr
+#endif /* CONFIG_6xx */
 
 /*
  * Load stuff into the MMU.  Intended to be called with
@@ -1510,7 +1339,7 @@
 	tophys(r6,r6)
 	lwz	r6,_SDR1@l(r6)
 	mtspr	SDR1,r6
-#ifdef CONFIG_PPC64BRIDGE	
+#ifdef CONFIG_PPC64BRIDGE
 	/* clear the ASR so we only use the pseudo-segment registers. */
 	li	r6,0
 	mtasr	r6
@@ -1678,7 +1507,6 @@
  *  -- Cort 
  */
 clear_bats:
-#if !defined(CONFIG_GEMINI)
 	li	r20,0
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
@@ -1702,10 +1530,32 @@
 	mtspr	IBAT2L,r20
 	mtspr	IBAT3U,r20
 	mtspr	IBAT3L,r20
-#endif /* !defined(CONFIG_GEMINI) */
+BEGIN_FTR_SECTION
+	/* Here's a tweak: at this point, CPU setup have
+	 * not been called yet, so HIGH_BAT_EN may not be
+	 * set in HID0 for the 745x processors. However, it
+	 * seems that doesn't affect our ability to actually
+	 * write to these SPRs.
+	 */
+	mtspr	SPRN_DBAT4U,r20
+	mtspr	SPRN_DBAT4L,r20
+	mtspr	SPRN_DBAT5U,r20
+	mtspr	SPRN_DBAT5L,r20
+	mtspr	SPRN_DBAT6U,r20
+	mtspr	SPRN_DBAT6L,r20
+	mtspr	SPRN_DBAT7U,r20
+	mtspr	SPRN_DBAT7L,r20
+	mtspr	SPRN_IBAT4U,r20
+	mtspr	SPRN_IBAT4L,r20
+	mtspr	SPRN_IBAT5U,r20
+	mtspr	SPRN_IBAT5L,r20
+	mtspr	SPRN_IBAT6U,r20
+	mtspr	SPRN_IBAT6L,r20
+	mtspr	SPRN_IBAT7U,r20
+	mtspr	SPRN_IBAT7L,r20
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
 	blr
 
-#ifndef CONFIG_GEMINI
 flush_tlbs:
 	lis	r20, 0x40
 1:	addic.	r20, r20, -0x1000
@@ -1724,7 +1574,6 @@
 	mtspr	SRR1,r3
 	sync
 	RFI
-#endif
 
 #ifndef CONFIG_POWER4	
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head_4xx.S linux-2.4.21-rc3/arch/ppc/kernel/head_4xx.S
--- linux-2.4.20/arch/ppc/kernel/head_4xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/head_4xx.S	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.head_4xx.S 1.6 05/21/01 11:50:00 paulus
- */
-/*
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
  *      Initial PowerPC version.
  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
@@ -70,6 +67,14 @@
 	.text
 _GLOBAL(_stext)
 _GLOBAL(_start)
+
+	/* To accomodate some SMP systems that overwrite the first few
+	 * locations before cpu 0 starts, the bootloader starts us at 0xc.
+	 */
+	nop
+	nop
+	nop
+
 	## Save residual data, init RAM disk, and command line parameters
 	
 	mr	r31,r3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head_8xx.S linux-2.4.21-rc3/arch/ppc/kernel/head_8xx.S
--- linux-2.4.20/arch/ppc/kernel/head_8xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/head_8xx.S	2003-05-22 22:06:43.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/except_8xx.S
  *
  *  PowerPC version 
@@ -82,6 +79,12 @@
 
 	.globl	__start
 __start:
+	/* To accomodate some SMP systems that overwrite the first few
+	 * locations before cpu 0 starts, the bootloader starts us at 0xc.
+	 */
+	nop
+	nop
+	nop
 	mr	r31,r3			/* save parameters */
 	mr	r30,r4
 	mr	r29,r5
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/i8259.c linux-2.4.21-rc3/arch/ppc/kernel/i8259.c
--- linux-2.4.20/arch/ppc/kernel/i8259.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/i8259.c	2003-05-22 22:06:43.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/irq.h>
@@ -21,17 +17,37 @@
 
 int i8259_pic_irq_offset;
 
-/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
- * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
+/*
+ * Acknowledge the IRQ using either the PCI host bridge's interrupt
+ * acknowledge feature or poll.  How i8259_init() is called determines
+ * which is called.  It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
  */
-int i8259_irq(struct pt_regs *regs)
+int
+i8259_irq(struct pt_regs *regs)
 {
 	int irq;
 
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
+	spin_lock(&i8259_lock);
+
+	/* Either int-ack or poll for the IRQ */
+	if (pci_intack)
+		irq = *pci_intack;
+	else {
+		/* Perform an interrupt acknowledge cycle on controller 1. */
+		outb(0x0C, 0x20);		/* prepare for poll */
+		irq = inb(0x20) & 7;
+		if (irq == 2 ) {
+			/*
+			 * Interrupt is cascaded so perform interrupt
+			 * acknowledge on controller 2.
+			 */
+			outb(0x0C, 0xA0);	/* prepare for poll */
+			irq = (inb(0xA0) & 7) + 8;
+		}
+	}
 
-	irq = *pci_intack;
-	if (irq==7) {
+	if (irq == 7) {
 		/*
 		 * This may be a spurious interrupt.
 		 *
@@ -39,47 +55,13 @@
 		 * significant bit is not set then there is no valid
 		 * interrupt.
 		 */
-		if(~inb(0x20)&0x80) {
+		if (!pci_intack)
+			outb(0x0B, 0x20);	/* ISR register */
+		if(~inb(0x20) & 0x80)
 			irq = -1;
-		}
 	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-	return irq;
-}
 
-/* Poke the 8259's directly using poll commands. */
-int i8259_poll(struct pt_regs *regs)
-{
-	int irq;
-
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
-	/*
-	 * Perform an interrupt acknowledge cycle on controller 1
-	 */
-	outb(0x0C, 0x20); /* prepare for poll */
-	irq = inb(0x20) & 7;
-	if (irq == 2) {
-		/*
-		 * Interrupt is cascaded so perform interrupt
-		 * acknowledge on controller 2
-		 */
-		outb(0x0C, 0xA0); /* prepare for poll */
-		irq = (inb(0xA0) & 7) + 8;
-	} else if (irq==7) {
-		/*
-		 * This may be a spurious interrupt
-		 *
-		 * Read the interrupt status register. If the most
-		 * significant bit is not set then there is no valid
-		 * interrupt
-		 */
-		outb(0x0b, 0x20);
-		if(~inb(0x20)&0x80) {
-			spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-			return -1;
-		}
-	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
+	spin_unlock(&i8259_lock);
 	return irq;
 }
 
@@ -159,6 +141,7 @@
 	NULL
 };
 
+#if 0 /* Do not request these before the host bridge resource have been setup */
 static struct resource pic1_iores = {
 	"8259 (master)", 0x20, 0x21, IORESOURCE_BUSY
 };
@@ -170,6 +153,7 @@
 static struct resource pic_edgectrl_iores = {
 	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
 };
+#endif
 
 void __init i8259_init(unsigned long intack_addr)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/idle.c linux-2.4.21-rc3/arch/ppc/kernel/idle.c
--- linux-2.4.20/arch/ppc/kernel/idle.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/idle.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/idle_6xx.S linux-2.4.21-rc3/arch/ppc/kernel/idle_6xx.S
--- linux-2.4.20/arch/ppc/kernel/idle_6xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/idle_6xx.S	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  This file contains the power_save function for 6xx & 7xxx CPUs
  *  rewritten in assembler
  *
@@ -107,13 +104,23 @@
 	andis.	r0,r3,HID0_NAP@h
 	beq	2f
 BEGIN_FTR_SECTION
-	/* Disable L2 prefetch on some 745x */
+	/* Disable L2 prefetch on some 745x and try to ensure
+	 * L2 prefetch engines are idle. As explained by errata
+	 * text, we can't be sure they are, we just hope very hard
+	 * that well be enough (sic !). At least I noticed Apple
+	 * doesn't even bother doing the dcbf's here...
+	 */
 	mfspr	r4,SPRN_MSSCR0
 	rlwinm	r4,r4,0,0,29
 	sync
 	mtspr	SPRN_MSSCR0,r4
 	sync
 	isync
+	lis	r4,KERNELBASE@h
+	dcbf	0,r4
+	dcbf	0,r4
+	dcbf	0,r4
+	dcbf	0,r4
 END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
 #ifdef DEBUG
 	lis	r6,nap_enter_count@ha
@@ -142,7 +149,9 @@
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
 	andc	r4,r4,r5
 	or	r4,r4,r3
-	oris	r4,r4,HID0_DPM@h	/* that should be done once for all ... */
+BEGIN_FTR_SECTION
+	oris	r4,r4,HID0_DPM@h	/* that should be done once for all  */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	mtspr	SPRN_HID0,r4
 BEGIN_FTR_SECTION
 	DSSALL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/indirect_pci.c linux-2.4.21-rc3/arch/ppc/kernel/indirect_pci.c
--- linux-2.4.20/arch/ppc/kernel/indirect_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/indirect_pci.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for indirect PCI bridges.
  *
  * Copyright (C) 1998 Gabriel Paubert.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/irq.c linux-2.4.21-rc3/arch/ppc/kernel/irq.c
--- linux-2.4.20/arch/ppc/kernel/irq.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/irq.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/irq.c
  *
  *  Derived from arch/i386/kernel/irq.c
@@ -177,15 +174,6 @@
 	return 0;
 }
 
-#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
-/* Name change so we can catch standard drivers that potentially mess up
- * the internal interrupt controller on 8xx and 8260.  Just bear with me,
- * I don't like this either and I am searching a better solution.  For
- * now, this is what I need. -- Dan
- */
-#define request_irq	request_8xxirq
-#endif
-
 void free_irq(unsigned int irq, void* dev_id)
 {
 	irq_desc_t *desc;
@@ -528,27 +516,21 @@
 	int irq, first = 1;
         hardirq_enter( cpu );
 
-	for (;;) {
-		/*
-		 * Every arch is required to implement ppc_md.get_irq.
-		 * This function will either return an irq number or -1 to
-		 * indicate there are no more pending.  But the first time
-		 * through the loop this means there wasn't and IRQ pending.
-		 * The value -2 is for buggy hardware and means that this IRQ
-		 * has already been handled. -- Tom
-		 */
-		irq = ppc_md.get_irq( regs );
-
-		if (irq >= 0)
-			ppc_irq_dispatch_handler( regs, irq );
-		else {
-			if (irq != -2 && first)
-				/* That's not SMP safe ... but who cares ? */
-				ppc_spurious_interrupts++;
-			break;
-		}
+	/*
+	 * Every platform is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.  But the first time
+	 * through the loop this means there wasn't an IRQ pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
+	while ((irq = ppc_md.get_irq(regs)) >= 0) {
+		ppc_irq_dispatch_handler(regs, irq);
 		first = 0;
 	}
+	if (irq != -2 && first)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
         hardirq_exit( cpu );
 
 	if (softirq_pending(cpu))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/l2cr.S linux-2.4.21-rc3/arch/ppc/kernel/l2cr.S
--- linux-2.4.20/arch/ppc/kernel/l2cr.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/l2cr.S	2003-05-22 22:06:48.000000000 +0000
@@ -40,9 +40,11 @@
 	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
 	Please e-mail updates to this file to me, thanks!
 */
+#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
+#include <asm/cache.h>
 
 /* Usage:
 	
@@ -101,6 +103,8 @@
 	blr
 END_FTR_SECTION_IFCLR(CPU_FTR_L2CR)
 
+	mflr	r9
+	
 	/* Stop DST streams */
 BEGIN_FTR_SECTION
 	DSSALL
@@ -115,6 +119,22 @@
 	mtmsr	r4
 	isync
 
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L2 cache tags.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
+	sync
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
+	/* Flush & disable L1 */
+	mr	r5,r3
+	bl	__flush_disable_L1
+	mr	r3,r5
+	
 	/* Get the current enable bit of the L2CR into r4 */
 	mfspr	r4,L2CR
 	
@@ -142,21 +162,22 @@
 
 	/* TODO: use HW flush assist when available */
 
-	lis	r4,0x0004
+	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
 1:
 	lwzx	r0,r0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
+	isync
 	
 	/* Now, flush the first 4MB of memory */
-	lis	r4,0x0004
+	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
 	sync
 1:
-	dcbf	r0,r4
+	dcbf	0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
 
@@ -166,25 +187,19 @@
 	 * L1 icache
 	 */
 	b	20f
-21:
+	.balign	L1_CACHE_LINE_SIZE
+22:
 	sync
 	mtspr	L2CR,r3
 	sync
-	b	22f
+	b	23f
 20:
-	b	21b
-22:
-	/* Before we perform the global invalidation, we must disable dynamic
-	 * power management via HID0[DPM] to work around a processor bug where
-	 * DPM can possibly interfere with the state machine in the processor
-	 * that invalidates the L2 cache tags.
-	 */
-	mfspr	r8,HID0			/* Save HID0 in r8 */
-	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
-	sync
-	mtspr	HID0,r4			/* Disable DPM */
-	sync
-
+	b	21f
+21:	sync
+	isync
+	b	22b
+		
+23:
 	/* Perform a global invalidation */
 	oris	r3,r3,0x0020
 	sync
@@ -211,11 +226,6 @@
 	mtspr	L2CR,r3
 	sync
 	
-	/* Restore HID0[DPM] to whatever it was before */
-	sync
-	mtspr	1008,r8
-	sync
-
 	/* See if we need to enable the cache */
 	cmplwi	r5,0
 	beq	4f
@@ -225,10 +235,20 @@
 	mtspr	L2CR,r3
 	sync
 
+4:
+	bl	__inval_enable_L1
+
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
 	/* Restore MSR (restores EE and DR bits to original state) */
-4:	SYNC
+	SYNC
 	mtmsr	r7
 	isync
+
+	mtlr	r9
 	blr
 
 _GLOBAL(_get_L2CR)
@@ -286,7 +306,7 @@
 	li	r4,0
 1:
 	lwzx	r0,r0,r4
-	dcbf	r0,r4
+	dcbf	0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
 	
@@ -360,3 +380,73 @@
 
 /* --- End of PowerLogix code ---
  */
+
+
+/* flush_disable_L1()	- Flush and disable L1 cache
+ *
+ * clobbers r0, r3, ctr, cr0
+ *
+ */
+ 	.globl	__flush_disable_L1
+ __flush_disable_L1:
+ 
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ 	sync
+ 	
+	/* Load counter to 0x1000 cache lines (128k) and
+	 * load cache with datas
+	 */
+	lis	r3,0x0002
+//	li	r3,0x1000	/* 128kB / 32B */
+	mtctr	r3
+	li	r3, 0
+1:
+	lwz	r0,0(r3)
+	addi	r3,r3,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	isync
+	sync
+
+	/* Now flush those cache lines */
+	lis	r3,0x0002
+//	li	r3,0x1000	/* 128kB / 32B */
+	mtctr	r3
+	li	r3, 0
+1:
+	dcbf	0,r3
+	addi	r3,r3,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+
+	/* We can now disable the L1 cache (HID0:DCE, HID0:ICE) */
+	mfspr	r3,SPRN_HID0
+	rlwinm	r3,r3,0,18,15
+	mtspr	SPRN_HID0,r3
+	sync
+	isync	
+ 	blr
+
+/* inval_enable_L1	- Invalidate and enable L1 cache
+ *
+ * Assumes L1 is already disabled and MSR:EE is off
+ *
+ * clobbers r3
+ */
+ 	.globl	__inval_enable_L1
+ __inval_enable_L1:
+	/* Enable and then Flash inval the instruction & data cache */
+	mfspr	r3,SPRN_HID0
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
+	isync
+	mtspr	SPRN_HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	SPRN_HID0,r3
+	sync
+
+ 	blr
+
+ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/m8260_setup.c linux-2.4.21-rc3/arch/ppc/kernel/m8260_setup.c
--- linux-2.4.20/arch/ppc/kernel/m8260_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/m8260_setup.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -269,11 +266,3 @@
 	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
 }
 
-/* Mainly for ksyms.
-*/
-int
-request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flag, const char *naem, void *dev)
-{
-	panic("request IRQ\n");
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/m8xx_setup.c linux-2.4.21-rc3/arch/ppc/kernel/m8xx_setup.c
--- linux-2.4.20/arch/ppc/kernel/m8xx_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/m8xx_setup.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *  linux/arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -48,6 +46,8 @@
 
 #include "ppc8xx_pic.h"
 
+extern int i8259_pic_irq_offset; /* defined in arch/ppc/kernel/i8259.c */
+
 static int m8xx_set_rtc_time(unsigned long time);
 static unsigned long m8xx_get_rtc_time(void);
 void m8xx_calibrate_decr(void);
@@ -63,9 +63,9 @@
 m8xx_setup_arch(void)
 {
 	int	cpm_page;
-	
+
 	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
-	
+
 	/* Reset the Communication Processor Module.
 	*/
 	m8xx_cpm_reset(cpm_page);
@@ -73,10 +73,10 @@
 #ifdef notdef
 	ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
 #endif
-	
+
 #ifdef CONFIG_BLK_DEV_INITRD
 #if 0
-	ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+	ROOT_DEV = to_kdev_t(0x0200); /* floppy */
 	rd_prompt = 1;
 	rd_doload = 1;
 	rd_image_start = 0;
@@ -106,6 +106,9 @@
 	xmon(0);
 #endif
 	machine_restart(NULL);
+
+	/* not reached */
+	for (;;);
 }
 
 /* A place holder for time base interrupts, if they are ever enabled. */
@@ -178,7 +181,8 @@
 				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
 					 (TBSCR_TBF | TBSCR_TBE));
 
-	if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint",
+				NULL) != 0)
 		panic("Could not allocate timer IRQ!");
 }
 
@@ -218,7 +222,7 @@
 	__asm__("mtmsr %0" : : "r" (msr) );
 
 	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
-	printk("Restart failed\n"); 
+	printk("Restart failed\n");
 	while(1);
 }
 
@@ -241,9 +245,9 @@
 	bd_t	*bp;
 
 	bp = (bd_t *)__res;
-			
-	seq_printf(m, "clock\t\t: %ldMHz\n"
-		   "bus clock\t: %ldMHz\n",
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t: %dMHz\n",
 		   bp->bi_intfreq / 1000000,
 		   bp->bi_busfreq / 1000000);
 
@@ -262,23 +266,26 @@
 	int i;
 	void cpm_interrupt_init(void);
 
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &ppc8xx_pic;
-	
-	/* We could probably incorporate the CPM into the multilevel
-	 * interrupt structure.
-	 */
+	for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
+		irq_desc[i].handler = &ppc8xx_pic;
+
 	cpm_interrupt_init();
-        unmask_irq(CPM_INTERRUPT);
 
 #if defined(CONFIG_PCI)
-        for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
-                irq_desc[i].handler = &i8259_pic;
-        i8259_pic.irq_offset = NR_SIU_INTS;
-        i8259_init();
-        request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-        enable_irq(ISA_BRIDGE_INT);
-#endif
+	for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_pic_irq_offset = I8259_IRQ_OFFSET;
+	i8259_init(0);
+
+	/* The i8259 cascade interrupt must be level sensitive. */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &= 
+		~(0x80000000 >> ISA_BRIDGE_INT);
+
+	if (request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "i8259 cascade",
+				NULL) != 0)
+		panic("Could not allocate 8259 IRQ!");
+#endif	/* CONFIG_PCI */
 }
 
 /* -------------------------------------------------------------------- */
@@ -297,7 +304,7 @@
 {
 	bd_t	*binfo;
 	extern unsigned char __res[];
-	
+
 	binfo = (bd_t *)__res;
 
 	return binfo->bi_memsize;
@@ -348,7 +355,7 @@
 
 	if ( r3 )
 		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-	
+
 #ifdef CONFIG_PCI
 	m8xx_setup_pci_ptrs();
 #endif
@@ -363,7 +370,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 	/* take care of cmd line */
 	if ( r6 )
-	{	
+	{
 		*(char *)(r7+KERNELBASE) = 0;
 		strcpy(cmd_line, (char *)(r6+KERNELBASE));
 	}
@@ -397,5 +404,5 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	m8xx_ide_init();
-#endif		
+#endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/misc.S linux-2.4.21-rc3/arch/ppc/kernel/misc.S
--- linux-2.4.20/arch/ppc/kernel/misc.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/misc.S	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains miscellaneous low-level functions.
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -364,6 +361,7 @@
 10:	lwarx	r7,0,r9
 	cmpi	0,r7,0
 	bne-	10b
+	/* No 405 Erratum 77 fix needed here, because 4xx can't do SMP */
 	stwcx.	r8,0,r9
 	bne-	10b
 #endif /* CONFIG_SMP */
@@ -651,6 +649,7 @@
 _GLOBAL(xchg_u32)
 	mr	r5,r3		/* Save pointer */
 10:	lwarx	r3,0,r5		/* Fetch old value & reserve */
+	PPC405_ERR77(0,r5)
 	stwcx.	r4,0,r5		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
 	blr
@@ -662,12 +661,14 @@
 _GLOBAL(atomic_clear_mask)
 10:	lwarx	r5,0,r4
 	andc	r5,r5,r3
+	PPC405_ERR77(0,r4)
 	stwcx.	r5,0,r4
 	bne-	10b
 	blr
 _GLOBAL(atomic_set_mask)
 10:	lwarx	r5,0,r4
 	or	r5,r5,r3
+	PPC405_ERR77(0,r4)
 	stwcx.	r5,0,r4
 	bne-	10b
 	blr
@@ -898,9 +899,9 @@
 
 /*
  * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
+ *   arch_kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(arch_kernel_thread)
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
@@ -1062,10 +1063,10 @@
 	.long sys_newlstat
 	.long sys_newfstat
 	.long sys_uname
-	.long sys_iopl		/* 110 */
+	.long sys_ni_syscall	/* 110 old iopl syscall */
 	.long sys_vhangup
 	.long sys_ni_syscall	/* old 'idle' syscall */
-	.long sys_vm86
+	.long sys_ni_syscall	/* old vm86 syscall */
 	.long sys_wait4
 	.long sys_swapoff	/* 115 */
 	.long sys_sysinfo
@@ -1075,7 +1076,7 @@
 	.long sys_clone		/* 120 */
 	.long sys_setdomainname
 	.long sys_newuname
-	.long sys_modify_ldt
+	.long sys_ni_syscall	/* old modify_ldt syscall */
 	.long sys_adjtimex
 	.long sys_mprotect	/* 125 */
 	.long sys_sigprocmask
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/mk_defs.c linux-2.4.21-rc3/arch/ppc/kernel/mk_defs.c
--- linux-2.4.20/arch/ppc/kernel/mk_defs.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/mk_defs.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mk_defs.c 1.11 08/19/01 22:43:23 paulus
- */
-/*
  * This program is used to generate definitions needed by
  * assembly language modules.
  *
@@ -52,6 +49,7 @@
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 #ifdef CONFIG_ALTIVEC
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/mpc10x_common.c linux-2.4.21-rc3/arch/ppc/kernel/mpc10x_common.c
--- linux-2.4.20/arch/ppc/kernel/mpc10x_common.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/mpc10x_common.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,402 @@
+
+/*
+ * arch/ppc/kernel/mpc10x_common.c
+ * 
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/mpc10x.h>
+
+
+/* Set resources to match bridge memory map */
+void __init
+mpc10x_bridge_set_resources(int map, struct pci_controller *hose)
+{
+
+	switch (map) {
+		case MPC10X_MEM_MAP_A:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x3f7fffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0xc0000000,
+					0xfeffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		case MPC10X_MEM_MAP_B:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x00bfffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0x80000000,
+					0xfcffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		default:
+			printk("mpc10x_bridge_set_resources: "
+					"Invalid map specified\n");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+	}
+}
+/*
+ * Do some initialization and put the EUMB registers at the specified address
+ * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set).
+ *
+ * The EPIC is not on the 106, only the 8240 and 107.
+ */
+int __init
+mpc10x_bridge_init(struct pci_controller *hose,
+		   uint current_map,
+		   uint new_map,
+		   uint phys_eumb_base)
+{
+	int	host_bridge, picr1, picr1_bit;
+	ulong	pci_config_addr, pci_config_data;
+	u_char	pir, byte;
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100);
+
+	/* Set up for current map so we can get at config regs */
+	switch (current_map) {
+		case MPC10X_MEM_MAP_A:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPA_CNFG_ADDR,
+					   MPC10X_MAPA_CNFG_DATA);
+			break;
+		case MPC10X_MEM_MAP_B:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPB_CNFG_ADDR,
+					   MPC10X_MAPB_CNFG_DATA);
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid current map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+			return -1;
+	}
+
+	/* Make sure its a supported bridge */
+	early_read_config_dword(hose,
+			        0,
+			        PCI_DEVFN(0,0),
+			        PCI_VENDOR_ID,
+			        &host_bridge);
+
+	switch (host_bridge) {
+		case MPC10X_BRIDGE_106:
+		case MPC10X_BRIDGE_8240:
+		case MPC10X_BRIDGE_107:
+		case MPC10X_BRIDGE_8245:
+			break;
+		default:
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit2", 0x100);
+			return -1;
+	}
+
+	switch (new_map) {
+		case MPC10X_MEM_MAP_A:
+			MPC10X_SETUP_HOSE(hose, A);
+			pci_config_addr = MPC10X_MAPA_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPA_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A;
+			break;
+		case MPC10X_MEM_MAP_B:
+			MPC10X_SETUP_HOSE(hose, B);
+			pci_config_addr = MPC10X_MAPB_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPB_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B;
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid new map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit3", 0x100);
+			return -1;
+	}
+
+	/* Make bridge use the 'new_map', if not already usng it */
+	if (current_map != new_map) {
+		early_read_config_dword(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_PICR1_REG,
+					&picr1);
+
+		picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) |
+			 picr1_bit;
+
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_PICR1_REG,
+					 picr1);
+
+		asm volatile("sync");
+
+		/* Undo old mappings & map in new cfg data/addr regs */
+		iounmap((void *)hose->cfg_addr);
+		iounmap((void *)hose->cfg_data);
+
+		setup_indirect_pci(hose,
+				   pci_config_addr,
+				   pci_config_data);
+	}
+
+	/* Setup resources to match map */
+	mpc10x_bridge_set_resources(new_map, hose);
+
+	/*
+	 * Want processor accesses of 0xFDxxxxxx to be mapped
+	 * to PCI memory space at 0x00000000.  Do not want
+	 * host bridge to respond to PCI memory accesses of
+	 * 0xFDxxxxxx.  Do not want host bridge to respond
+	 * to PCI memory addresses 0xFD000000-0xFDFFFFFF;
+	 * want processor accesses from 0x000A0000-0x000BFFFF
+	 * to be forwarded to system memory.
+	 *
+	 * Only valid if not in agent mode and using MAP B.
+	 */
+	if (new_map == MPC10X_MEM_MAP_B) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_MAPB_OPTIONS_REG,
+				       &byte);
+
+		byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE  |
+			  MPC10X_CFG_MAPB_OPTIONS_PCICH |
+			  MPC10X_CFG_MAPB_OPTIONS_PROCCH);
+
+		if (host_bridge != MPC10X_BRIDGE_106) {
+			byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE;
+		}
+
+		early_write_config_byte(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_MAPB_OPTIONS_REG,
+					byte);
+	}
+
+	if (host_bridge != MPC10X_BRIDGE_106) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_PIR_REG,
+				       &pir);
+
+		if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) {
+			printk("Host bridge in Agent mode\n");
+			/* Read or Set LMBAR & PCSRBAR? */
+		}
+		       
+		/* Set base addr of the 8240/107 EUMB.  */
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_EUMBBAR,
+					 phys_eumb_base);
+
+		/* Map EPIC register part of EUMB into vitual memory */
+		OpenPIC_Addr = 
+			ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
+				MPC10X_EUMB_EPIC_SIZE);
+	}
+
+#ifdef CONFIG_MPC10X_STORE_GATHERING
+	mpc10x_enable_store_gathering(hose);
+#else
+	mpc10x_disable_store_gathering(hose);
+#endif
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100);
+	return 0;
+}
+
+/*
+ * Need to make our own PCI config space access macros because
+ * mpc10x_get_mem_size() is called before the data structures are set up for
+ * the 'early_xxx' and 'indirect_xxx' routines to work.
+ * Assumes bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read,  byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read,  dword, u32 *, in_le32, 0)
+#if 0	/* Not used */
+MPC10X_PCI_OP(write, byte,  u8, out_8, 3)
+MPC10X_PCI_OP(read,  word,  u16 *, in_le16, 2)
+MPC10X_PCI_OP(write, word,  u16, out_le16, 2)
+MPC10X_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ */
+unsigned long __init
+mpc10x_get_mem_size(uint mem_map)
+{
+	uint			*config_addr, *config_data, val;
+	ulong			start, end, total, offset;
+	int			i;
+	u_char			bank_enables;
+
+	switch (mem_map) {
+		case MPC10X_MEM_MAP_A:
+			config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPA_CNFG_DATA;
+			break;
+		case MPC10X_MEM_MAP_B:
+			config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPB_CNFG_DATA;
+			break;
+		default:
+			return 0;
+	}
+
+	mpc10x_read_config_byte(config_addr,
+				config_data,
+				PCI_DEVFN(0,0),
+			        MPC10X_MCTLR_MEM_BANK_ENABLES,
+			        &bank_enables);
+
+	total = 0;
+
+	for (i=0; i<8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
+
+int __init
+mpc10x_enable_store_gathering(struct pci_controller *hose)
+{
+	uint picr1;
+
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+			        MPC10X_CFG_PICR1_REG,
+			        &picr1);
+
+	picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN;
+
+	early_write_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				MPC10X_CFG_PICR1_REG,
+				picr1);
+
+	return 0;
+}
+
+int __init
+mpc10x_disable_store_gathering(struct pci_controller *hose)
+{
+	uint picr1;
+
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+			        MPC10X_CFG_PICR1_REG,
+			        &picr1);
+
+	picr1 &= ~MPC10X_CFG_PICR1_ST_GATH_EN;
+
+	early_write_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				MPC10X_CFG_PICR1_REG,
+				picr1);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/open_pic.c linux-2.4.21-rc3/arch/ppc/kernel/open_pic.c
--- linux-2.4.20/arch/ppc/kernel/open_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/open_pic.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
@@ -30,6 +27,11 @@
 
 void* OpenPIC_Addr;
 static volatile struct OpenPIC *OpenPIC = NULL;
+/*
+ * We define OpenPIC_InitSenses table thusly:
+ * bit 0x1: sense, 0 for edge and 1 for level.
+ * bit 0x2: polarity, 0 for negative, 1 for positive.
+ */
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
 extern int use_of_interrupt_tree;
@@ -38,7 +40,8 @@
 static u_int NumSources;
 static int open_pic_irq_offset;
 static volatile OpenPIC_Source *ISR[NR_IRQS];
-static volatile unsigned char* chrp_int_ack_special;
+static int openpic_cascade_irq = -1;
+static int (*openpic_cascade_fn)(struct pt_regs *);
 
 /* Global Operations */
 static void openpic_disable_8259_pass_through(void);
@@ -143,7 +146,8 @@
  */
 extern unsigned long* _get_SP(void);
 #define check_arg_irq(irq) \
-    if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
+    if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
+	|| ISR[irq - open_pic_irq_offset] == 0) { \
       printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
       print_backtrace(_get_SP()); }
 #define check_arg_cpu(cpu) \
@@ -247,6 +251,31 @@
 }
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_EPIC_SERIAL_MODE
+static void __init openpic_eicr_set_clk(u_int clkval)
+{
+	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
+			OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
+}
+
+static void __init openpic_enable_sie(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
+			OPENPIC_EICR_SIE);
+}
+#endif
+
+#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK)
+static void openpic_reset(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
+}
+#endif
+
 void __init openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
 {
 	volatile OpenPIC_Source *src = first_ISR;
@@ -261,8 +290,14 @@
 		ISR[i] = src;
 }
 
-void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
-			 int programmer_switch_irq)
+/*
+ * The `offset' parameter defines where the interrupts handled by the
+ * OpenPIC start in the space of interrupt numbers that the kernel knows
+ * about.  In other words, the OpenPIC's IRQ0 is numbered `offset' in the
+ * kernel's interrupt numbering scheme.
+ * We assume there is only one OpenPIC.
+ */
+void __init openpic_init(int offset)
 {
 	u_int t, i;
 	u_int timerfreq;
@@ -274,6 +309,12 @@
 	}
 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
 
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	/* Have to start from ground zero.
+	*/
+	openpic_reset();
+#endif
+
 	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
@@ -305,11 +346,7 @@
 		printk("OpenPIC timer frequency is %d.%06d MHz\n",
 		       timerfreq / 1000000, timerfreq % 1000000);
 
-	if (!main_pic)
-		return;
-
 	open_pic_irq_offset = offset;
-	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
 
 	/* Initialize timer interrupts */
 	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
@@ -333,19 +370,13 @@
 #endif
 
 	/* Initialize external interrupts */
-	if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
+	if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
 
 	openpic_set_priority(0xf);
 
-	/* SIOint (8259 cascade) is special */
-	if (offset) {
-		openpic_initirq(0, 8, offset, 1, 1);
-		openpic_mapirq(0, 1<<0, 0);
-	}
-
-	/* Init all external sources */
-	for (i = 1; i < NumSources; i++) {
-		int pri, sense;
+	/* Init all external sources, including possibly the cascade. */
+	for (i = 0; i < NumSources; i++) {
+		int sense;
 
 		if (ISR[i] == 0)
 			continue;
@@ -353,13 +384,15 @@
 		/* the bootloader may have left it enabled (bad !) */
 		openpic_disable_irq(i+offset);
 
-		pri = (i == programmer_switch_irq)? 9: 8;
-		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
-		if (sense)
+		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
+				(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
+
+		if (sense & IRQ_SENSE_MASK)
 			irq_desc[i+offset].status = IRQ_LEVEL;
 
-		/* Enabled, Priority 8 or 9 */
-		openpic_initirq(i, pri, i+offset, !sense, sense);
+		/* Enabled, Priority 8 */
+		openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+				(sense & IRQ_SENSE_MASK));
 		/* Processor 0 */
 		openpic_mapirq(i, 1<<0, 0);
 	}
@@ -372,25 +405,14 @@
 	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
 
-	/* Initialize the cascade */
-	if (offset) {
-		if (request_irq(offset, no_action, SA_INTERRUPT,
-				"82c59 cascade", NULL))
-			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
-	}
-	openpic_set_priority(0);
 	openpic_disable_8259_pass_through();
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
+	openpic_enable_sie();
+#endif
+	openpic_set_priority(0);
 
-	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
-}
-
-static void openpic_reset(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-			 OPENPIC_CONFIG_RESET);
-	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
-				 OPENPIC_CONFIG_RESET))
-		mb();
+	if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
 }
 
 #ifdef notused
@@ -544,14 +566,19 @@
 	if (OpenPIC == NULL)
 		return;
 
+	/* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
-		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI0 (call function)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
-		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI1 (reschedule)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
-		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI2 (invalidate tlb)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
-		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI3 (xmon break)", 0);
 
 	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
 		openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
@@ -614,6 +641,20 @@
 		      physmask(cpumask));
 }
 
+/*
+ * Initalize the interrupt source which will generate an NMI.
+ * This raises the interrupt's priority from 8 to 9.
+ *
+ * irq: The logical IRQ which generates an NMI.
+ */
+void __init
+openpic_init_nmi_irq(u_int irq)
+{
+	check_arg_irq(irq);
+	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK,
+				9 << OPENPIC_PRIORITY_SHIFT);
+}
 
 /*
  *
@@ -621,6 +662,19 @@
  *
  */
 
+/*
+ * Hookup a cascade to the OpenPIC.
+ */
+void __init
+openpic_hookup_cascade(u_int irq, char *name,
+	int (*cascade_fn)(struct pt_regs *))
+{
+	openpic_cascade_irq = irq;
+	openpic_cascade_fn = cascade_fn;
+	if (request_irq(irq, no_action, SA_INTERRUPT, name, NULL))
+		printk("Unable to get OpenPIC IRQ %d for cascade\n",
+				irq - open_pic_irq_offset);
+}
 
 /*
  *  Enable/disable an external interrupt source
@@ -762,32 +816,25 @@
 
 #endif /* CONFIG_SMP */
 
-/* This one may be merged with PReP and CHRP */
 int
 openpic_get_irq(struct pt_regs *regs)
 {
-/*
- * Clean up needed. -VAL
- */
 	int irq = openpic_irq();
 
-	/* Management of the cascade should be moved out of here */
-
-	/* Yep - because openpic !=> i8259, for one thing. -VAL */
-        if (open_pic_irq_offset && irq == open_pic_irq_offset)
-        {
-                /*
-                 * This magic address generates a PCI IACK cycle.
-                 */
-		if ( chrp_int_ack_special )
-			irq = *chrp_int_ack_special;
-#ifndef CONFIG_GEMINI
-		else
-			irq = i8259_poll(regs);
-#endif
-		openpic_eoi();
-        }
-	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
+	/*
+	 * Check for the cascade interrupt and call the cascaded
+	 * interrupt controller function (usually i8259_irq) if so.
+	 * This should move to irq.c eventually.  -- paulus
+	 */
+	if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
+		int cirq = openpic_cascade_fn(regs);
+
+		/* Allow for the cascade being shared with other devices */
+		if (cirq != -1) {
+			irq = cirq;
+			openpic_eoi();
+		}
+        } else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
 		irq = -1;
 	return irq;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/open_pic_defs.h linux-2.4.21-rc3/arch/ppc/kernel/open_pic_defs.h
--- linux-2.4.20/arch/ppc/kernel/open_pic_defs.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/open_pic_defs.h	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.open_pic_defs.h 1.8 08/20/01 22:33:28 paulus
- */
-/*
  *  linux/openpic.h -- OpenPIC definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
@@ -209,6 +206,14 @@
 #define OPENPIC_CONFIG_BASE_MASK		0x000fffff
 
     /*
+     *  Global Configuration Register 1
+     *  This is the EICR on EPICs.
+     */
+
+#define OPENPIC_EICR_S_CLK_MASK			0x70000000
+#define OPENPIC_EICR_SIE			0x08000000
+
+    /*
      *  Vendor Identification Register
      */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci-dma.c linux-2.4.21-rc3/arch/ppc/kernel/pci-dma.c
--- linux-2.4.20/arch/ppc/kernel/pci-dma.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/pci-dma.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pci-dma.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  * Copyright (C) 2000   Ani Joshi <ajoshi@unixbox.com>
  *
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci.c linux-2.4.21-rc3/arch/ppc/kernel/pci.c
--- linux-2.4.20/arch/ppc/kernel/pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/pci.c	2003-05-22 22:06:43.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -39,8 +36,13 @@
 
 void pcibios_make_OF_bus_map(void);
 
+static int pci_relocate_bridge_resource(struct pci_bus *bus, int i);
+static int probe_resource(struct pci_bus *parent, struct resource *pr,
+			  struct resource *res, struct resource **conflict);
+static void update_bridge_base(struct pci_bus *bus, int i);
 static void pcibios_fixup_resources(struct pci_dev* dev);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
+static int reparent_resources(struct resource *parent, struct resource *res);
 static void fixup_rev1_53c810(struct pci_dev* dev);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_ALL_PPC
@@ -107,7 +109,7 @@
 
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-			     struct resource *res, int resource)
+			struct resource *res, int resource)
 {
 	u32 new, check;
 	int reg;
@@ -115,6 +117,7 @@
 	unsigned long io_offset;
 	
 	new = res->start;
+	res->flags &= ~IORESOURCE_UNSET;
 	if (hose && res->flags & IORESOURCE_IO) {
 		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
 		new -= io_offset;
@@ -139,6 +142,9 @@
 		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
 		       new, check);
 	}
+	printk(KERN_INFO "PCI: moved device %s resource %d (%lx) to %x\n",
+	       dev->slot_name, resource, res->flags,
+	       new & ~PCI_REGION_FLAG_MASK);
 }
 
 static void
@@ -154,13 +160,14 @@
 	}
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 		struct resource *res = dev->resource + i;
-		if (!res->start || !res->flags)
+		if (!res->flags)
 			continue;
-		if (res->end == 0xffffffff) {
+		if (!res->start || res->end == 0xffffffff) {
 			DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
 			    dev->slot_name, i, res->start, res->end);
 			res->end -= res->start;
 			res->start = 0;
+			res->flags |= IORESOURCE_UNSET;
 			continue;
 		}
 		offset = 0;
@@ -304,7 +311,8 @@
 	for (ln = bus_list->next; ln != bus_list; ln=ln->next) {
 		bus = pci_bus_b(ln);
 		for (i = 0; i < 4; ++i) {
-			if ((res = bus->resource[i]) == NULL || !res->flags)
+			if ((res = bus->resource[i]) == NULL || !res->flags
+			    || res->start > res->end)
 				continue;
 			if (bus->parent == NULL)
 				pr = (res->flags & IORESOURCE_IO)?
@@ -319,18 +327,238 @@
 					continue;
 				}
 			}
-			
-			if (pr && request_resource(pr, res) == 0)
-				continue;
+
+			DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
+			    res->start, res->end, res->flags, pr);
+			if (pr) {
+				if (request_resource(pr, res) == 0)
+					continue;
+				/*
+				 * Must be a conflict with an existing entry.
+				 * Move that entry (or entries) under the
+				 * bridge resource and try again.
+				 */
+				if (reparent_resources(pr, res) == 0)
+					continue;
+			}
 			printk(KERN_ERR "PCI: Cannot allocate resource region "
 			       "%d of PCI bridge %d\n", i, bus->number);
-			DBG("PCI: resource is %lx..%lx (%lx), parent %p\n",
-			    res->start, res->end, res->flags, pr);
+			if (pci_relocate_bridge_resource(bus, i))
+				bus->resource[i] = NULL;
 		}
 		pcibios_allocate_bus_resources(&bus->children);
 	}
 }
 
+/*
+ * Reparent resource children of pr that conflict with res
+ * under res, and make res replace those children.
+ */
+static int __init
+reparent_resources(struct resource *parent, struct resource *res)
+{
+	struct resource *p, **pp;
+	struct resource **firstpp = NULL;
+
+	for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
+		if (p->end < res->start)
+			continue;
+		if (res->end < p->start)
+			break;
+		if (p->start < res->start || p->end > res->end)
+			return -1;	/* not completely contained */
+		if (firstpp == NULL)
+			firstpp = pp;
+	}
+	if (firstpp == NULL)
+		return -1;	/* didn't find any conflicting entries? */
+	res->parent = parent;
+	res->child = *firstpp;
+	res->sibling = *pp;
+	*firstpp = res;
+	*pp = NULL;
+	for (p = res->child; p != NULL; p = p->sibling) {
+		p->parent = res;
+		DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+		    p->name, p->start, p->end, res->name);
+	}
+	return 0;
+}
+
+/*
+ * A bridge has been allocated a range which is outside the range
+ * of its parent bridge, so it needs to be moved.
+ */
+static int __init
+pci_relocate_bridge_resource(struct pci_bus *bus, int i)
+{
+	struct resource *res, *pr, *conflict;
+	unsigned long try, size;
+	int j;
+	struct pci_bus *parent = bus->parent;
+
+	if (parent == NULL) {
+		/* shouldn't ever happen */
+		printk(KERN_ERR "PCI: can't move host bridge resource\n");
+		return -1;
+	}
+	res = bus->resource[i];
+	pr = NULL;
+	for (j = 0; j < 4; j++) {
+		struct resource *r = parent->resource[j];
+		if (!r)
+			continue;
+		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;
+		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) {
+			pr = r;
+			break;
+		}
+		if (res->flags & IORESOURCE_PREFETCH)
+			pr = r;
+	}
+	if (pr == NULL)
+		return -1;
+	size = res->end - res->start;
+	if (pr->start > pr->end || size > pr->end - pr->start)
+		return -1;
+	try = pr->end + 1;
+	for (;;) {
+		try &= ~0xfffUL;
+		if (res->flags & IORESOURCE_MEM)
+			try &= ~0xfffffUL;
+		res->start = try - size - 1;
+		res->end = try - 1;
+		if (try <= size || res->start < pr->start)
+			return -1;
+		if (probe_resource(bus->parent, pr, res, &conflict) == 0)
+			break;
+		if (conflict->start <= pr->start + size)
+			return -1;
+		try = conflict->start;
+	}
+	if (request_resource(pr, res)) {
+		DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+		    res->start, res->end);
+		return -1;		/* "can't happen" */
+	}
+	update_bridge_base(bus, i);
+	printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
+	       bus->number, i, res->start, res->end);
+	return 0;
+}
+
+static int __init
+probe_resource(struct pci_bus *parent, struct resource *pr,
+	       struct resource *res, struct resource **conflict)
+{
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	struct resource *r;
+	struct list_head *ln;
+	int i;
+
+	for (r = pr->child; r != NULL; r = r->sibling) {
+		if (r->end >= res->start && res->end >= r->start) {
+			*conflict = r;
+			return 1;
+		}
+	}
+	for (ln = parent->children.next; ln != &parent->children;
+	     ln = ln->next) {
+		bus = pci_bus_b(ln);
+		for (i = 0; i < 4; ++i) {
+			if ((r = bus->resource[i]) == NULL)
+				continue;
+			if (!r->flags || r->start > r->end || r == res)
+				continue;
+			if (pci_find_parent_resource(bus->self, r) != pr)
+				continue;
+			if (r->end >= res->start && res->end >= r->start) {
+				*conflict = r;
+				return 1;
+			}
+		}
+	}
+	for (ln = parent->devices.next; ln != &parent->devices; ln=ln->next) {
+		dev = pci_dev_b(ln);
+		for (i = 0; i < 6; ++i) {
+			r = &dev->resource[i];
+			if (!r->flags || (r->flags & IORESOURCE_UNSET))
+				continue;
+			if (pci_find_parent_resource(bus->self, r) != pr)
+				continue;
+			if (r->end >= res->start && res->end >= r->start) {
+				*conflict = r;
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static void __init
+update_bridge_base(struct pci_bus *bus, int i)
+{
+	struct resource *res = bus->resource[i];
+	u8 io_base_lo, io_limit_lo;
+	u16 mem_base, mem_limit;
+	u16 cmd;
+	unsigned long start, end, off;
+	struct pci_dev *dev = bus->self;
+	struct pci_controller *hose = dev->sysdata;
+
+	if (!hose) {
+		printk("update_bridge_base: no hose?\n");
+		return;
+	}
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	pci_write_config_word(dev, PCI_COMMAND,
+			      cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+	if (res->flags & IORESOURCE_IO) {
+		u16 bu;
+		off = (unsigned long) hose->io_base_virt - isa_io_base;
+		start = res->start - off;
+		end = res->end - off;
+		pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+		pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &bu);
+		io_limit_lo &= PCI_IO_RANGE_TYPE_MASK;
+		if (io_base_lo == PCI_IO_RANGE_TYPE_16 && end > 0xffff) {
+			printk(KERN_ERR "bridge only supports 16-bit I/O!\n");
+			goto out;
+		}
+		io_base_lo |= (start >> 8) & PCI_IO_RANGE_MASK;
+		io_limit_lo |= (end >> 8) & PCI_IO_RANGE_MASK;
+		pci_write_config_word(dev, PCI_IO_BASE_UPPER16, start >> 16);
+		pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, end >> 16);
+		pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
+		pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
+
+	} else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+		   == IORESOURCE_MEM) {
+		off = hose->pci_mem_offset;
+		mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+		mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+		pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
+		pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
+
+	} else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+		   == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) {
+		off = hose->pci_mem_offset;
+		mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK;
+		mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK;
+		pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base);
+		pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit);
+
+	} else {
+		DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n",
+		    dev->slot_name, i, res->flags);
+	}
+ out:
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
 static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
 	struct resource *pr, *r = &dev->resource[idx];
@@ -345,6 +573,7 @@
 			DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
 			    pr, pr->start, pr->end, pr->flags);
 		/* We'll assign a new address later */
+		r->flags |= IORESOURCE_UNSET;
 		r->end -= r->start;
 		r->start = 0;
 	}
@@ -364,8 +593,8 @@
 			r = &dev->resource[idx];
 			if (r->parent)		/* Already allocated */
 				continue;
-			if (!r->start)		/* Not assigned at all */
-				continue;
+			if (!r->flags || (r->flags & IORESOURCE_UNSET))
+				continue;	/* Not assigned at all */
 			if (r->flags & IORESOURCE_IO)
 				disabled = !(command & PCI_COMMAND_IO);
 			else
@@ -411,7 +640,7 @@
 			 * or because we have decided the old address was
 			 * unusable for some reason.
 			 */
-			if (!r->start && r->end &&
+			if ((r->flags & IORESOURCE_UNSET) && r->end &&
 			    (!ppc_md.pcibios_enable_device_hook ||
 			     !ppc_md.pcibios_enable_device_hook(dev, 1)))
 				pci_assign_resource(dev, idx);
@@ -437,9 +666,9 @@
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
-	for(idx=0; idx<6; idx++) {
+	for (idx=0; idx<6; idx++) {
 		r = &dev->resource[idx];
-		if (!r->start && r->end) {
+		if (r->flags & IORESOURCE_UNSET) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
 		}
@@ -490,7 +719,7 @@
 	bus_range = (int *) get_property(node, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get bus-range for %s\n",
-			       node->full_name);
+		       node->full_name);
 		return;
 	}
 	pci_to_OF_bus_map[pci_bus] = bus_range[0];
@@ -717,8 +946,9 @@
 	int rlen = 0;
 	int memno = 0;
 	struct resource *res;
-	int np, na = prom_n_addr_cells(dev);
-	np = na + 5;
+	int na = prom_n_addr_cells(dev);
+	int np = na + 5;
+	unsigned int size;
 
 	/* First we try to merge ranges to fix a problem with some pmacs
 	 * that can have more than 3 ranges, fortunately using contiguous
@@ -754,12 +984,16 @@
 	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
 	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
+		size = ranges[na+4];
 		switch (ranges[0] >> 24) {
 		case 1:		/* I/O space */
 			if (ranges[2] != 0)
 				break;
 			hose->io_base_phys = ranges[na+2];
-			hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]);
+			/* limit I/O to 16MB */
+			if (size > 0x01000000)
+				size = 0x01000000;
+			hose->io_base_virt = ioremap(ranges[na+2], size);
 			if (primary)
 				isa_io_base = (unsigned long) hose->io_base_virt;
 			res = &hose->io_resource;
@@ -788,7 +1022,7 @@
 		}
 		if (res != NULL) {
 			res->name = dev->full_name;
-			res->end = res->start + ranges[na+4] - 1;
+			res->end = res->start + size - 1;
 			res->parent = NULL;
 			res->sibling = NULL;
 			res->child = NULL;
@@ -894,7 +1128,8 @@
 		struct pci_dev *dev = pci_dev_b(ln);
 		u16 class = dev->class >> 8;
 
-		if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA)
+		if (class == PCI_CLASS_DISPLAY_VGA ||
+		    class == PCI_CLASS_NOT_DEFINED_VGA)
 			*found_vga = 1;
 		if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
 			rc |= check_for_io_childs(dev->subordinate, res, found_vga);
@@ -905,7 +1140,8 @@
 			struct resource *r;
 			unsigned long r_size;
 
-			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES)
+			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI
+			    && i >= PCI_BRIDGE_RESOURCES)
 				continue;
 			r = &dev->resource[i];
 			r_size = r->end - r->start;
@@ -931,30 +1167,45 @@
 do_fixup_p2p_level(struct pci_bus *bus)
 {
 	struct list_head *ln;
-	int i;
+	int i, parent_io;
 	int has_vga = 0;
+
+	for (parent_io=0; parent_io<4; parent_io++)
+		if (bus->resource[parent_io]->flags & IORESOURCE_IO)
+			break;
+	if (parent_io >= 4)
+		return;
 	
 	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
 		struct pci_bus *b = pci_bus_b(ln);
 		struct pci_dev *d = b->self;
 		struct pci_controller* hose = (struct pci_controller *)d->sysdata;
 		struct resource *res = b->resource[0];
+		struct resource tmp_res;
 		unsigned long max;
 		int found_vga = 0;
 
-		res->end = 0;
-		res->start = 0x1000;
+		memset(&tmp_res, 0, sizeof(tmp_res));
+		tmp_res.start = bus->resource[parent_io]->start;
+
+		/* We don't let low addresses go through that closed P2P bridge, well,
+		 * that may not be necessary but I feel safer that way
+		 */
+		if (tmp_res.start == 0)
+			tmp_res.start = 0x1000;
 		
-		if (!list_empty(&b->devices) && res && res->flags == 0 && res != bus->resource[0] &&
+		if (!list_empty(&b->devices) && res && res->flags == 0 &&
+		    res != bus->resource[parent_io] &&
 		    (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-		    check_for_io_childs(b, res, &found_vga)) {
+		    check_for_io_childs(b, &tmp_res, &found_vga)) {
 			u8 io_base_lo;
 
 			printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
 
 			if (found_vga) {
 				if (has_vga) {
-					printk(KERN_WARNING "Skipping VGA, already active on bus segment\n");
+					printk(KERN_WARNING "Skipping VGA, already active"
+					    " on bus segment\n");
 					found_vga = 0;
 				} else
 					has_vga = 1;
@@ -962,10 +1213,13 @@
 			pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
 
 			if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
-				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffffffff;
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffffffff;
 			else
-				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffff;
-			
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffff;
+
+			*res = tmp_res;
 			res->flags = IORESOURCE_IO;
 			res->name = b->name;
 			
@@ -976,10 +1230,12 @@
 					continue;
 				if ((r->flags & IORESOURCE_IO) == 0)
 					continue;
-				DBG("Trying to allocate from %08lx, size %08lx from parent res %d: %08lx -> %08lx\n",
+				DBG("Trying to allocate from %08lx, size %08lx from parent"
+				    " res %d: %08lx -> %08lx\n",
 					res->start, res->end, i, r->start, r->end);
 				
-				if (allocate_resource(r, res, res->end + 1, res->start, max, res->end + 1, NULL, NULL) < 0) {
+				if (allocate_resource(r, res, res->end + 1, res->start, max,
+				    res->end + 1, NULL, NULL) < 0) {
 					DBG("Failed !\n");
 					continue;
 				}
@@ -1191,7 +1447,7 @@
 			continue;
 			
 		r = &dev->resource[idx];
-		if (!r->start && r->end) {
+		if (r->flags & IORESOURCE_UNSET) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
 		}
@@ -1298,51 +1554,41 @@
 {
 	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	unsigned long io_offset = 0;
-	int i, res_bit;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long base;
+	struct resource *res;
+	int i;
+	int ret = -EINVAL;
 
 	if (hose == 0)
 		return -EINVAL;		/* should never happen */
+	if (offset + size <= offset)
+		return -EINVAL;
 
-	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
+		/* PCI memory space */
+		base = hose->pci_mem_offset;
+		for (i = 0; i < 3; ++i) {
+			res = &hose->mem_resources[i];
+			if (offset >= res->start - base
+			    && offset + size - 1 <= res->end - base) {
+				ret = 0;
+				break;
+			}
+		}
 		offset += hose->pci_mem_offset;
-		res_bit = IORESOURCE_MEM;
 	} else {
-		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-		offset += io_offset;
-		res_bit = IORESOURCE_IO;
+		/* PCI I/O space */
+		base = (unsigned long)hose->io_base_virt - isa_io_base;
+		res = &hose->io_resource;
+		if (offset >= res->start - base
+		    && offset + size - 1 <= res->end - base)
+			ret = 0;
+		offset += hose->io_base_phys;
 	}
 
-	/*
-	 * Check that the offset requested corresponds to one of the
-	 * resources of the device.
-	 */
-	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-		struct resource *rp = &dev->resource[i];
-		int flags = rp->flags;
-
-		/* treat ROM as memory (should be already) */
-		if (i == PCI_ROM_RESOURCE)
-			flags |= IORESOURCE_MEM;
-
-		/* Active and same type? */
-		if ((flags & res_bit) == 0)
-			continue;
-
-		/* In the range of this resource? */
-		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
-			continue;
-
-		/* found it! construct the final physical address */
-		if (mmap_state == pci_mmap_io)
-			offset += hose->io_base_phys - io_offset;
-
-		vma->vm_pgoff = offset >> PAGE_SHIFT;
-		return 0;
-	}
-
-	return -EINVAL;
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	return ret;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci.h linux-2.4.21-rc3/arch/ppc/kernel/pci.h
--- linux-2.4.20/arch/ppc/kernel/pci.h	2001-08-12 19:43:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/pci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-/*
- * BK Id: SCCS/s.pci.h 1.10 08/08/01 16:35:43 paulus
- */
-
-#ifndef __PPC_KERNEL_PCI_H__
-#define __PPC_KERNEL_PCI_H__
-
-/* Configure those in your xxx_init() or xxx_setup_arch() function */
-extern unsigned long isa_io_base;
-extern unsigned long isa_mem_base;
-extern unsigned long pci_dram_offset;
-
-/* Set this to 1 if you want the kernel to re-assign all PCI
- * bus numbers
- */
-extern int pci_assign_all_busses;
-
-
-extern struct pci_controller* pcibios_alloc_controller(void);
-extern struct pci_controller* pci_find_hose_for_OF_device(
-			struct device_node* node);
-
-extern void setup_indirect_pci(struct pci_controller* hose,
-			u32 cfg_addr, u32 cfg_data);
-extern void setup_grackle(struct pci_controller *hose);
-
-#endif /* __PPC_KERNEL_PCI_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci_auto.c linux-2.4.21-rc3/arch/ppc/kernel/pci_auto.c
--- linux-2.4.20/arch/ppc/kernel/pci_auto.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/pci_auto.c	2003-05-22 22:06:27.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Matt Porter <mporter@mvista.com>
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc-stub.c linux-2.4.21-rc3/arch/ppc/kernel/ppc-stub.c
--- linux-2.4.20/arch/ppc/kernel/ppc-stub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc-stub.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc-stub.c 1.6 05/17/01 18:14:21 cort
- */
-/*
  * ppc-stub.c:  KGDB support for the Linux kernel.
  *
  * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
@@ -137,6 +134,9 @@
 /* struct tt_entry kgdb_savettable[256]; */
 /* typedef void (*trapfunc_t)(void); */
 
+static void kgdb_fault_handler(struct pt_regs *regs);
+static void handle_exception (struct pt_regs *regs);
+
 #if 0
 /* Install an exception handler for kgdb */
 static void exceptionHandler(int tnum, unsigned int *tfunc)
@@ -185,7 +185,7 @@
  * return 0.
  */
 static unsigned char *
-mem2hex(char *mem, char *buf, int count)
+mem2hex(const char *mem, char *buf, int count)
 {
 	unsigned char ch;
 
@@ -347,18 +347,6 @@
 	flush_instruction_cache();
 }
 
-static inline int get_msr(void)
-{
-	int msr;
-	asm volatile("mfmsr %0" : "=r" (msr):);
-	return msr;
-}
-
-static inline void set_msr(int msr)
-{
-	asm volatile("mtmsr %0" : : "r" (msr));
-}
-
 /* Set up exception handlers for tracing and breakpoints
  * [could be called kgdb_init()]
  */
@@ -498,8 +486,8 @@
 
 	kgdb_interruptible(0);
 	lock_kernel();
-	msr = get_msr();
-	set_msr(msr & ~MSR_EE);	/* disable interrupts */
+	msr = mfmsr();
+	mtmsr(msr & ~MSR_EE);	/* disable interrupts */
 
 	if (regs->nip == (unsigned long)breakinst) {
 		/* Skip over breakpoint trap insn */
@@ -526,7 +514,7 @@
 	*ptr++ = hexchars[SP_REGNUM >> 4];
 	*ptr++ = hexchars[SP_REGNUM & 0xf];
 	*ptr++ = ':';
-	ptr = mem2hex(((char *)&regs) + SP_REGNUM*4, ptr, 4);
+	ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
 	*ptr++ = ';';
 #endif
 
@@ -685,7 +673,7 @@
  * some location may have changed something that is in the instruction cache.
  */
 			kgdb_flush_cache_all();
-			set_msr(msr);
+			mtmsr(msr);
 			kgdb_interruptible(1);
 			unlock_kernel();
 			kgdb_active = 0;
@@ -694,9 +682,6 @@
 		case 's':
 			kgdb_flush_cache_all();
 			regs->msr |= MSR_SE;
-#if 0
-			set_msr(msr | MSR_SE);
-#endif
 			unlock_kernel();
 			kgdb_active = 0;
 			return;
@@ -727,13 +712,15 @@
 		return;
 	}
 
-	asm("	.globl breakinst
-	     breakinst: .long 0x7d821008
-            ");
+	asm("	.globl breakinst	\n\
+	     breakinst: .long 0x7d821008");
 }
 
-/* Output string in GDB O-packet format if GDB has connected. If nothing
-   output, returns 0 (caller must then handle output). */
+#ifdef CONFIG_KGDB_CONSOLE 
+/* 
+ * Output string in GDB O-packet format if GDB has connected. If nothing
+ * output, returns 0 (caller must then handle output) 
+ */
 int
 kgdb_output_string (const char* s, unsigned int count)
 {
@@ -750,15 +737,5 @@
 	putpacket(buffer);
 
         return 1;
- }
-
-#ifndef CONFIG_8xx
-
-/* I don't know why other platforms don't need this.  The function for
- * the 8xx is found in arch/ppc/8xx_io/uart.c.  -- Dan
- */
-void
-kgdb_map_scc(void)
-{
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.21-rc3/arch/ppc/kernel/ppc4xx_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc4xx_pic.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc4xx_pic.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c linux-2.4.21-rc3/arch/ppc/kernel/ppc8260_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc8260_pic.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc8260_pic.c 1.5 05/17/01 18:14:21 cort
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -112,7 +108,7 @@
 	0
 };
 
-
+/* Return an interrupt vector or -1 if no interrupt is pending. */
 int
 m8260_get_irq(struct pt_regs *regs)
 {
@@ -124,11 +120,9 @@
         bits = immr->im_intctl.ic_sivec;
         irq = bits >> 26;
 
-	if (irq == 0)
-		return(-1);
-#if 0
-        irq += ppc8260_pic.irq_offset;
-#endif
+	if (irq == 0)	/* 0 --> no irq is pending */
+		irq = -1;
+
 	return irq;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h linux-2.4.21-rc3/arch/ppc/kernel/ppc8260_pic.h
--- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc8260_pic.h	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifndef _PPC_KERNEL_PPC8260_H
 #define _PPC_KERNEL_PPC8260_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c linux-2.4.21-rc3/arch/ppc/kernel/ppc8xx_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc8xx_pic.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini
- */
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -11,6 +8,8 @@
 #include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
+extern int cpm_get_irq(struct pt_regs *regs);
+
 /* The 8xx internal interrupt controller.  It is usually
  * the only interrupt controller.  Some boards, like the MBX and
  * Sandpoint have the 8259 as a secondary controller.  Depending
@@ -83,36 +82,6 @@
 	0
 };
 
-#if 0
-void
-m8xx_do_IRQ(struct pt_regs *regs,
-	   int            cpu)
-{
-	int irq;
-        unsigned long bits = 0;
-
-        /* For MPC8xx, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-        irq = bits >> 26;
-#if 0
-        irq += ppc8xx_pic.irq_offset;
-#endif
-        bits = 1UL << irq;
-
-	if (irq < 0) {
-		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-		       irq, regs->nip);
-		ppc_spurious_interrupts++;
-	}
-	else {
-                ppc_irq_dispatch_handler( regs, irq );
-	}
-
-}
-#endif
-
-
 /*
  * We either return a valid interrupt or -1 if there is nothing pending
  */
@@ -130,70 +99,31 @@
 	 * When we read the sivec without an interrupt to process, we will 
 	 * get back SIU_LEVEL7.  In this case, return -1
 	 */
-	if (irq == SIU_LEVEL7)
-		return -1;
+        if (irq == CPM_INTERRUPT)
+        	irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
+#if defined(CONFIG_PCI)
+	else if (irq == ISA_BRIDGE_INT) {
+		int isa_irq;
+
+		if ((isa_irq = i8259_poll(regs)) >= 0)
+			irq = I8259_IRQ_OFFSET + isa_irq;
+	}
+#endif	/* CONFIG_PCI */
+	else if (irq == SIU_LEVEL7)
+		irq = -1;
 
 	return irq;
 }
 
-/* The MBX is the only 8xx board that uses the 8259.
-*/
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int bits, irq;
-
-	/* A bug in the QSpan chip causes it to give us 0xff always
-	 * when doing a character read.  So read 32 bits and shift.
-	 * This doesn't seem to return useful values anyway, but
-	 * read it to make sure things are acked.
-	 * -- Cort
-	 */
-	irq = (inl(0x508) >> 24)&0xff;
-	if ( irq != 0xff ) printk("iack %d\n", irq);
-	
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		irq = (irq&7) + 8;
-	}
-	bits = 1UL << irq;
-	irq += i8259_pic.irq_offset;
-	ppc_irq_dispatch_handler( regs, irq );
-}
-#endif
-
-/* Only the MBX uses the external 8259.  This allows us to catch standard
- * drivers that may mess up the internal interrupt controllers, and also
- * allow them to run without modification on the MBX.
+#if defined(CONFIG_PCI)
+/* Handler for the MPC8xx SIU cascade interrupt for the 8259 interrupt
+ * controller
  */
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
+void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-	irq += i8259_pic.irq_offset;
-	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
-#else
-	/*
-	 * Handle other "well-known" interrupts, but panic on unknown ones.
+	/* This interrupt handler never actually gets called.  It is
+	 * installed only to unmask the 8259 cascade interrupt in the SIU
+	 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
 	 */
-	switch (irq) {
-#ifdef	IDE0_INTERRUPT
-		case IDE0_INTERRUPT:	/* IDE0 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-#ifdef	IDE1_INTERRUPT
-		case IDE1_INTERRUPT:	/* IDE1 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-	default:			/* unknown IRQ -> panic */
-		panic("request_irq");
-	}
-#endif
 }
+#endif	/* CONFIG_PCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h linux-2.4.21-rc3/arch/ppc/kernel/ppc8xx_pic.h
--- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc8xx_pic.h	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc_htab.c linux-2.4.21-rc3/arch/ppc/kernel/ppc_htab.c
--- linux-2.4.20/arch/ppc/kernel/ppc_htab.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc_htab.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini
- */
-/*
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c linux-2.4.21-rc3/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ppc_ksyms.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/threads.h>
@@ -50,6 +47,7 @@
 #include <asm/time.h>
 #include <asm/cputable.h>
 #include <asm/btext.h>
+#include <asm/div64.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
@@ -58,7 +56,6 @@
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 extern void transfer_to_handler(void);
 extern void syscall_trace(void);
 extern void do_IRQ(struct pt_regs *regs);
@@ -131,6 +128,7 @@
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strcasecmp);
+EXPORT_SYMBOL(__div64_32);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
 EXPORT_SYMBOL(csum_partial_copy_generic);
@@ -170,7 +168,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
 	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
-EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
 #endif
 
 #ifdef CONFIG_PCI
@@ -343,11 +340,15 @@
 
 #ifdef  CONFIG_8xx
 EXPORT_SYMBOL(__res);
-EXPORT_SYMBOL(request_8xxirq);
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
+EXPORT_SYMBOL(m8xx_cpm_hostalloc);
 #endif /* CONFIG_8xx */
 
+/* Those should really be inline */
+EXPORT_SYMBOL(atomic_clear_mask);
+EXPORT_SYMBOL(atomic_set_mask);
+
 EXPORT_SYMBOL(ret_to_user_hook);
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prep_nvram.c linux-2.4.21-rc3/arch/ppc/kernel/prep_nvram.c
--- linux-2.4.20/arch/ppc/kernel/prep_nvram.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/prep_nvram.c	2003-05-22 22:06:46.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/prep_nvram.c
  *
  *  Copyright (C) 1998  Corey Minyard
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/process.c linux-2.4.21-rc3/arch/ppc/kernel/process.c
--- linux-2.4.20/arch/ppc/kernel/process.c	2001-11-26 13:29:17.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/process.c	2003-05-22 22:06:44.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.process.c 1.34 11/23/01 16:38:29 paulus
- */
-/*
  *  linux/arch/ppc/kernel/process.c
  *
  *  Derived from "arch/i386/kernel/process.c"
@@ -34,6 +31,7 @@
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/init.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -400,13 +398,53 @@
 		last_task_used_math = 0;
 	if (last_task_used_altivec == current)
 		last_task_used_altivec = 0;
+	memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
 	current->thread.fpscr = 0;
+#ifdef CONFIG_ALTIVEC
+	memset(current->thread.vr, 0, sizeof(current->thread.vr));
+	memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
+	current->thread.vrsave = 0;
+#endif /* CONFIG_ALTIVEC */
+}
+
+/*
+ * Support for the PR_GET/SET_FPEXC prctl() calls.
+ */
+static inline unsigned int __unpack_fe01(unsigned int msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned int __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
 }
 
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
-	return do_fork(p1, regs->gpr[1], regs, 0);
+	return do_fork(p1, p2, regs, 0);
 }
 
 int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
@@ -452,6 +490,8 @@
 	int cnt = 0;
 	unsigned long i;
 
+	if (sp == NULL)
+		asm("mr %0,1" : "=r" (sp));
 	printk("Call backtrace: ");
 	while (sp) {
 		if (__get_user( i, &sp[1] ))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prom.c linux-2.4.21-rc3/arch/ppc/kernel/prom.c
--- linux-2.4.20/arch/ppc/kernel/prom.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/prom.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
  *
@@ -506,6 +503,38 @@
 }
 
 static unsigned long __init
+map_addr(struct device_node *np, unsigned long space, unsigned long addr)
+{
+	int na;
+	unsigned int *ranges;
+	int rlen = 0;
+	unsigned int type;
+
+	type = (space >> 24) & 3;
+	if (type == 0)
+		return addr;
+
+	while ((np = np->parent) != NULL) {
+		if (strcmp(np->type, "pci") != 0)
+			continue;
+		/* PCI bridge: map the address through the ranges property */
+		na = prom_n_addr_cells(np);
+		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
+		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
+			if (((ranges[0] >> 24) & 3) == type
+			    && ranges[2] <= addr
+			    && addr - ranges[2] < ranges[na+4]) {
+				/* ok, this matches, translate it */
+				addr += ranges[na+2] - ranges[2];
+				break;
+			}
+			ranges += na + 5;
+		}
+	}
+	return addr;
+}
+
+static unsigned long __init
 interpret_pci_props(struct device_node *np, unsigned long mem_start,
 		    int naddrc, int nsizec)
 {
@@ -519,9 +548,9 @@
 		i = 0;
 		adr = (struct address_range *) mem_start;
 		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			/* XXX assumes PCI addresses mapped 1-1 to physical */
 			adr[i].space = pci_addrs[i].addr.a_hi;
-			adr[i].address = pci_addrs[i].addr.a_lo;
+			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
+						  pci_addrs[i].addr.a_lo);
 			adr[i].size = pci_addrs[i].size_lo;
 			++i;
 		}
@@ -758,8 +787,15 @@
 	for (np = allnodes; np != 0; np = np->allnext) {
 		for (j = 0; j < np->n_intrs; j++) {
 			i = np->intrs[j].line;
-			if (i >= off && i < max)
-				senses[i-off] = np->intrs[j].sense;
+			if (i >= off && i < max) {
+				if (np->intrs[j].sense == 1) {
+					senses[i-off] = (IRQ_SENSE_LEVEL |
+							IRQ_POLARITY_NEGATIVE);
+				} else {
+					senses[i-off] = (IRQ_SENSE_EDGE |
+							IRQ_POLARITY_POSITIVE);
+				}
+			}
 		}
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prom_init.c linux-2.4.21-rc3/arch/ppc/kernel/prom_init.c
--- linux-2.4.20/arch/ppc/kernel/prom_init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/prom_init.c	2003-05-22 22:06:52.000000000 +0000
@@ -266,7 +266,7 @@
 {
 	phandle node;
 	ihandle ih;
-	int i;
+	int i, j;
 	char type[16], *path;
 	static unsigned char default_colors[] = {
 		0x00, 0x00, 0x00,
@@ -325,26 +325,26 @@
 			break;
 	}
 
-try_again:
 	/*
 	 * Open the first display and set its colormap.
 	 */
-	if (prom_num_displays > 0) {
-		path = prom_display_paths[0];
+	for (j=0; j<prom_num_displays; j++) {
+		path = prom_display_paths[j];
 		prom_print("opening display ");
 		prom_print(path);
 		ih = call_prom("open", 1, 1, path);
 		if (ih == 0 || ih == (ihandle) -1) {
 			prom_print("... failed\n");
-			for (i=1; i<prom_num_displays; i++) {
+			for (i=j+1; i<prom_num_displays; i++) {
 				prom_display_paths[i-1] = prom_display_paths[i];
 				prom_display_nodes[i-1] = prom_display_nodes[i];
 			}
-			if (--prom_num_displays > 0)
-				prom_disp_node = prom_display_nodes[0];
-			else
+			if (--prom_num_displays > 0) {
+				prom_disp_node = prom_display_nodes[j];
+				j--;
+			} else
 				prom_disp_node = NULL;
-			goto try_again;
+			continue;
 		} else {
 			prom_print("... ok\n");
 			/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ptrace.c linux-2.4.21-rc3/arch/ppc/kernel/ptrace.c
--- linux-2.4.20/arch/ppc/kernel/ptrace.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/ptrace.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus
- */
-/*
  *  linux/arch/ppc/kernel/ptrace.c
  *
  *  PowerPC version
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/qspan_pci.c linux-2.4.21-rc3/arch/ppc/kernel/qspan_pci.c
--- linux-2.4.20/arch/ppc/kernel/qspan_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/qspan_pci.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * QSpan pci routines.
  * Most 8xx boards use the QSpan PCI bridge.  The config address register
  * is located 0x500 from the base of the bridge control/status registers.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/semaphore.c linux-2.4.21-rc3/arch/ppc/kernel/semaphore.c
--- linux-2.4.20/arch/ppc/kernel/semaphore.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/semaphore.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort
- */
-/*
  * PowerPC-specific semaphore code.
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
@@ -39,6 +36,7 @@
 "	srawi	%1,%0,31\n"
 "	andc	%1,%0,%1\n"
 "	add	%1,%1,%4\n"
+	PPC405_ERR77(0,%3)
 "	stwcx.	%1,0,%3\n"
 "	bne	1b"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/setup.c linux-2.4.21-rc3/arch/ppc/kernel/setup.c
--- linux-2.4.20/arch/ppc/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/setup.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -35,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/pmac_feature.h>
+#include <asm/kgdb.h>
 
 extern void platform_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7);
@@ -478,6 +476,12 @@
 		case BI_MEMSIZE:
 			boot_mem_size = data[0];
 			break;
+		case BI_BOARD_INFO:
+			/* data is typically a bd_t */
+			if (ppc_md.board_info)
+				ppc_md.board_info((void *)data,
+					rec->size - sizeof(struct bi_record));
+			break;
 		}
 		rec = (struct bi_record *)((ulong)rec + rec->size);
 	}
@@ -562,7 +566,14 @@
 #if defined(CONFIG_KGDB)
 	kgdb_map_scc();
 	set_debug_traps();
-	breakpoint();
+	if (strstr(cmd_line, "nokgdb"))
+		printk("kgdb default breakpoint deactivated on command line\n");
+	else {
+		if (ppc_md.progress)
+			ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
+		printk("kgdb default breakpoint activated\n");
+		breakpoint();
+	}
 #endif
 
 	/*
@@ -603,101 +614,3 @@
 	/* this is for modules since _machine can be a define -- Cort */
 	ppc_md.ppc_machine = _machine;
 }
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
-	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	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);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[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);
-}
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/signal.c linux-2.4.21-rc3/arch/ppc/kernel/signal.c
--- linux-2.4.20/arch/ppc/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/signal.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/ppc/kernel/signal.c
  *
  *  PowerPC version 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/smp.c linux-2.4.21-rc3/arch/ppc/kernel/smp.c
--- linux-2.4.20/arch/ppc/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/smp.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.smp.c 1.40 03/28/02 16:54:23 hozer
- */
-/*
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
@@ -66,6 +63,9 @@
 extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
 
+/* Low level assembly function used to backup CPU 0 state */
+extern void __save_cpu_setup(void);
+
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  * 
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
@@ -330,6 +330,9 @@
 	/* Probe arch for CPUs */
 	cpu_nr = smp_ops->probe();
 
+	/* Backup CPU 0 state */
+	__save_cpu_setup();
+	
 	/*
 	 * only check for cpus we know exist.  We keep the callin map
 	 * with cpus at the bottom -- Cort
@@ -371,7 +374,7 @@
 		 * use this value that I found through experimentation.
 		 * -- Cort
 		 */
-		for ( c = 1000; c && !cpu_callin_map[i] ; c-- )
+		for ( c = 10000; c && !cpu_callin_map[i] ; c-- )
 			udelay(100);
 		
 		if ( cpu_callin_map[i] )
@@ -505,19 +508,11 @@
 	int cpu = current->processor;
 	
         smp_store_cpu_info(cpu);
+	smp_ops->setup_cpu(cpu);
 	set_dec(tb_ticks_per_jiffy);
+	cpu_online_map |= 1UL << cpu;
+	mb();
 	cpu_callin_map[cpu] = 1;
-
-	smp_ops->setup_cpu(cpu);
-
-	/*
-	 * This cpu is now "online".  Only set them online
-	 * before they enter the loop below since write access
-	 * to the below variable is _not_ guaranteed to be
-	 * atomic.
-	 *   -- Cort <cort@fsmlabs.com>
-	 */
-	cpu_online_map |= 1UL << smp_processor_id();
 	
 	while(!smp_commenced)
 		barrier();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/softemu8xx.c linux-2.4.21-rc3/arch/ppc/kernel/softemu8xx.c
--- linux-2.4.20/arch/ppc/kernel/softemu8xx.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/softemu8xx.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.softemu8xx.c 1.8 05/17/01 18:14:22 cort
- */
-/*
  * Software emulation of some PPC instructions for the 8xx core.
  *
  * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
@@ -35,6 +32,11 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 
+extern void
+print_8xx_pte(struct mm_struct *mm, unsigned long addr);
+extern int
+get_8xx_pte(struct mm_struct *mm, unsigned long addr);
+
 /* Eventually we may need a look-up table, but this works for now.
 */
 #define LFS	48
@@ -117,7 +119,7 @@
 	default:
 		retval = 1;
 		printk("Bad emulation %s/%d\n"
-		       " NIP: %08x instruction: %08x opcode: %x "
+		       " NIP: %08lx instruction: %08x opcode: %x "
 		       "A: %x B: %x C: %x code: %x rc: %x\n",
 		       current->comm,current->pid,
 		       regs->nip,
@@ -128,13 +130,12 @@
 		       (instword>>1)&0x3ff,
 		       instword&1);
 		{
-			int pa;
+			unsigned long pa;
 			print_8xx_pte(current->mm,regs->nip);
-			pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
-			pa |= (regs->nip & ~PAGE_MASK);
-			pa = __va(pa);
-			printk("Kernel VA for NIP %x ", pa);
-			print_8xx_pte(current->mm,pa);
+			pa = (get_8xx_pte(current->mm,regs->nip) & PAGE_MASK)
+				| (regs->nip & ~PAGE_MASK);
+			printk("Kernel VA for NIP 0x%p ", __va(pa));
+			print_8xx_pte(current->mm, (unsigned long)__va(pa));
 		}
 		
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/syscalls.c linux-2.4.21-rc3/arch/ppc/kernel/syscalls.c
--- linux-2.4.20/arch/ppc/kernel/syscalls.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/syscalls.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.syscalls.c 1.13 03/13/02 09:12:22 trini
- */
-/*
  * linux/arch/ppc/kernel/sys_ppc.c
  *
  *  PowerPC version 
@@ -54,24 +51,6 @@
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/time.c linux-2.4.21-rc3/arch/ppc/kernel/time.c
--- linux-2.4.20/arch/ppc/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/time.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -186,7 +183,7 @@
 		 * We should have an rtc call that only sets the minutes and
 		 * seconds like on Intel to avoid problems with non UTC clocks.
 		 */
-		if ( (time_status & STA_UNSYNC) == 0 &&
+		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
 		     xtime.tv_sec - last_rtc_update >= 659 &&
 		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
 		     jiffies - wall_jiffies == 1) {
@@ -197,8 +194,6 @@
 				last_rtc_update += 60;
 		}
 		write_unlock(&xtime_lock);
-		
-
 	}
 	if (!disarm_decr[cpu])
 		set_dec(next_dec);
@@ -295,13 +290,11 @@
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
 
-
+/* This function is only called on the boot processor */
 void __init time_init(void)
 {
 	time_t sec, old_sec;
 	unsigned old_stamp, stamp, elapsed;
-	/* This function is only called on the boot processor */
-	unsigned long flags;
 
         if (ppc_md.time_init != NULL)
                 time_offset = ppc_md.time_init();
@@ -318,32 +311,33 @@
 	/* Now that the decrementer is calibrated, it can be used in case the 
 	 * clock is stuck, but the fact that we have to handle the 601
 	 * makes things more complex. Repeatedly read the RTC until the
-	 * next second boundary to try to achieve some precision...
+	 * next second boundary to try to achieve some precision.  If there
+	 * is no RTC, we still need to set tb_last_stamp and
+	 * last_jiffy_stamp(cpu 0) to the current stamp.
 	 */
+	stamp = get_native_tbl();
 	if (ppc_md.get_rtc_time) {
-		stamp = get_native_tbl();
 		sec = ppc_md.get_rtc_time();
 		elapsed = 0;
 		do {
 			old_stamp = stamp; 
 			old_sec = sec;
 			stamp = get_native_tbl();
-			if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000;
+			if (__USE_RTC() && stamp < old_stamp)
+				old_stamp -= 1000000000;
 			elapsed += stamp - old_stamp;
 			sec = ppc_md.get_rtc_time();
 		} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
-		if (sec==old_sec) {
+		if (sec == old_sec)
 			printk("Warning: real time clock seems stuck!\n");
-		}
-		write_lock_irqsave(&xtime_lock, flags);
 		xtime.tv_sec = sec;
-		last_jiffy_stamp(0) = tb_last_stamp = stamp;
 		xtime.tv_usec = 0;
 		/* No update now, we just read the time from the RTC ! */
 		last_rtc_update = xtime.tv_sec;
-		write_unlock_irqrestore(&xtime_lock, flags);
 	}
 
+	last_jiffy_stamp(0) = tb_last_stamp = stamp;
+
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/todc_time.c linux-2.4.21-rc3/arch/ppc/kernel/todc_time.c
--- linux-2.4.20/arch/ppc/kernel/todc_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/todc_time.c	2003-05-22 22:06:25.000000000 +0000
@@ -7,12 +7,10 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 #include <linux/errno.h>
 #include <linux/init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.21-rc3/arch/ppc/kernel/traps.c
--- linux-2.4.20/arch/ppc/kernel/traps.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/kernel/traps.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.traps.c 1.22 10/11/01 10:33:09 paulus
- */
-/*
  *  linux/arch/ppc/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
@@ -38,6 +35,9 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 
 extern int fix_alignment(struct pt_regs *);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int sig);
@@ -66,6 +66,13 @@
 int (*debugger_iabr_match)(struct pt_regs *regs);
 int (*debugger_dabr_match)(struct pt_regs *regs);
 void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#define debugger(regs)			do { } while (0)
+#define debugger_bpt(regs)		0
+#define debugger_sstep(regs)		0
+#define debugger_iabr_match(regs)	0
+#define debugger_dabr_match(regs)	0
+#define debugger_fault_handler		((void (*)(struct pt_regs *))0)
 #endif
 #endif
 
@@ -74,15 +81,19 @@
  */
 
 
-spinlock_t oops_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * fp, long err)
 {
 	console_verbose();
-	spin_lock_irq(&oops_lock);
+	spin_lock_irq(&die_lock);
+#ifdef CONFIG_PMAC_BACKLIGHT
+	set_backlight_enable(1);
+	set_backlight_level(BACKLIGHT_MAX);
+#endif
 	printk("Oops: %s, sig: %ld\n", str, err);
 	show_regs(fp);
-	spin_unlock_irq(&oops_lock);
+	spin_unlock_irq(&die_lock);
 	/* do_exit() should take care of panic'ing from an interrupt
 	 * context so we don't handle it here
 	 */
@@ -90,54 +101,37 @@
 }
 
 void
-_exception(int signr, struct pt_regs *regs)
+_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 {
-	if (!user_mode(regs))
-	{
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	siginfo_t info;
+
+	if (!user_mode(regs)) {
 		debugger(regs);
-#endif
 		die("Exception in kernel mode", regs, signr);
 	}
-	force_sig(signr, current);
+	info.si_signo = signr;
+	info.si_errno = 0;
+	info.si_code = code;
+	info.si_addr = (void *) addr;
+	force_sig_info(signr, &info, current);
 }
 
-void
-MachineCheckException(struct pt_regs *regs)
+/*
+ * I/O accesses can cause machine checks on powermacs.
+ * Check if the NIP corresponds to the address of a sync
+ * instruction for which there is an entry in the exception
+ * table.
+ * Note that the 601 only takes a machine check on TEA
+ * (transfer error ack) signal assertion, and does not
+ * set any of the top 16 bits of SRR1.
+ *  -- paulus.
+ */
+static inline int check_io_access(struct pt_regs *regs)
 {
 #ifdef CONFIG_ALL_PPC
 	unsigned long fixup;
-#endif /* CONFIG_ALL_PPC */
 	unsigned long msr = regs->msr;
 
-	if (user_mode(regs)) {
-		_exception(SIGSEGV, regs);	
-		return;
-	}
-
-#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
-	/* the qspan pci read routines can cause machine checks -- Cort */
-	bad_page_fault(regs, regs->dar, SIGBUS);
-	return;
-#endif
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-	if (debugger_fault_handler) {
-		debugger_fault_handler(regs);
-		return;
-	}
-#endif
-
-#ifdef CONFIG_ALL_PPC
-	/*
-	 * I/O accesses can cause machine checks on powermacs.
-	 * Check if the NIP corresponds to the address of a sync
-	 * instruction for which there is an entry in the exception
-	 * table.
-	 * Note that the 601 only takes a machine check on TEA
-	 * (transfer error ack) signal assertion, and does not
-	 * set of the top 16 bits of SRR1.
-	 *  -- paulus.
-	 */
 	if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000)))
 	    && (fixup = search_exception_table(regs->nip)) != 0) {
 		/*
@@ -163,18 +157,72 @@
 			       (*nip & 0x100)? "OUT to": "IN from",
 			       regs->gpr[rb] - _IO_BASE, nip);
 			regs->nip = fixup;
-			return;
+			return 1;
 		}
 	}
 #endif /* CONFIG_ALL_PPC */
+	return 0;
+}
+
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+/* On 4xx, the reason for the machine check or program exception
+   is in the ESR. */
+#define get_reason(regs)	mfspr(SPRN_ESR);
+#define REASON_FP		0
+#define REASON_ILLEGAL		ESR_PIL
+#define REASON_PRIVILEGED	ESR_PPR
+#define REASON_TRAP		ESR_PTR
+
+#else
+/* On non-4xx, the reason for the machine check or program
+   exception is in the MSR. */
+#define get_reason(regs)	((regs)->msr)
+#define REASON_FP		0x100000
+#define REASON_ILLEGAL		0x80000
+#define REASON_PRIVILEGED	0x40000
+#define REASON_TRAP		0x20000
+#endif
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long reason = get_reason(regs);
+
+	if (user_mode(regs)) {
+		_exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
+		return;
+	}
+
+#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
+	/* the qspan pci read routines can cause machine checks -- Cort */
+	bad_page_fault(regs, regs->dar, SIGBUS);
+	return;
+#endif
+	if (debugger_fault_handler) {
+		debugger_fault_handler(regs);
+		return;
+	}
+	if (check_io_access(regs))
+		return;
+
+#ifdef CONFIG_4xx
+	if (reason & ESR_IMCP) {
+		printk("Instruction");
+		mtspr(SPRN_ESR, reason & ~ESR_IMCP);
+	} else
+		printk("Data");
+	printk(" machine check in kernel mode.\n");
+
+#else /* CONFIG_4xx */
 	printk("Machine check in kernel mode.\n");
-	printk("Caused by (from SRR1=%lx): ", msr);
-	switch (msr & 0xF0000) {
+	printk("Caused by (from SRR1=%lx): ", reason);
+	switch (reason & 0x601F0000) {
 	case 0x80000:
 		printk("Machine check signal\n");
 		break;
 	case 0:		/* for 601 */
 	case 0x40000:
+	case 0x140000:	/* 7450 MSS error and TEA */
 		printk("Transfer error ack signal\n");
 		break;
 	case 0x20000:
@@ -183,26 +231,32 @@
 	case 0x10000:
 		printk("Address parity error signal\n");
 		break;
+	case 0x20000000:
+		printk("L1 Data Cache error\n");
+		break;
+	case 0x40000000:
+		printk("L1 Instruction Cache error\n");
+		break;
+	case 0x00100000:
+		printk("L2 data cache parity error\n");
+		break;
 	default:
 		printk("Unknown values in msr\n");
 	}
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#endif /* CONFIG_4xx */
+
 	debugger(regs);
-#endif
 	die("machine check", regs, SIGBUS);
 }
 
 void
 SMIException(struct pt_regs *regs)
 {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-	{
-		debugger(regs);
-		return;
-	}
-#endif
+	debugger(regs);
+#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB))
 	show_regs(regs);
 	panic("System Management Interrupt");
+#endif
 }
 
 void
@@ -210,23 +264,21 @@
 {
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, 0, 0);
 }
 
 void
 InstructionBreakpoint(struct pt_regs *regs)
 {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_iabr_match(regs))
 		return;
-#endif
-	_exception(SIGTRAP, regs);
+	_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
 }
 
 void
 RunModeException(struct pt_regs *regs)
 {
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, 0, 0);
 }
 
 /* Illegal instruction emulation support.  Originally written to
@@ -245,16 +297,16 @@
 static int
 emulate_instruction(struct pt_regs *regs)
 {
-	uint    instword;
-	uint    rd;
-	uint    retval;
+	u32 instword;
+	u32 rd;
+	int retval;
 
-	retval = EINVAL;
+	retval = -EINVAL;
 
 	if (!user_mode(regs))
 		return retval;
 
-	if (get_user(instword, (uint *)(regs->nip)))
+	if (get_user(instword, (u32 *)(regs->nip)))
 		return -EFAULT;
 
 	/* Emulate the mfspr rD, PVR.
@@ -263,60 +315,71 @@
 		rd = (instword >> 21) & 0x1f;
 		regs->gpr[rd] = mfspr(PVR);
 		retval = 0;
-	}
-	if (retval == 0)
 		regs->nip += 4;
-	return(retval);
+	}
+	return retval;
 }
 
 void
 ProgramCheckException(struct pt_regs *regs)
 {
-#if defined(CONFIG_4xx)
-	unsigned int esr = mfspr(SPRN_ESR);
+	unsigned int reason = get_reason(regs);
+	extern int do_mathemu(struct pt_regs *regs);
 
-	if (esr & ESR_PTR) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-		if (debugger_bpt(regs))
-			return;
-#endif
-		_exception(SIGTRAP, regs);
-	} else {
-		_exception(SIGILL, regs);
-	}
-#else
-	if (regs->msr & 0x100000) {
+#ifdef CONFIG_MATH_EMULATION
+	if ((reason & REASON_ILLEGAL) && do_mathemu(regs) == 0)
+		return;
+#endif /* CONFIG_MATH_EMULATION */
+
+	if (reason & REASON_FP) {
 		/* IEEE FP exception */
-		_exception(SIGFPE, regs);
-	} else if (regs->msr & 0x20000) {
+		int code = 0;
+		u32 fpscr;
+
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
+		fpscr = current->thread.fpscr;
+		fpscr &= fpscr << 22;	/* mask summary bits with enables */
+		if (fpscr & FPSCR_VX)
+			code = FPE_FLTINV;
+		else if (fpscr & FPSCR_OX)
+			code = FPE_FLTOVF;
+		else if (fpscr & FPSCR_UX)
+			code = FPE_FLTUND;
+		else if (fpscr & FPSCR_ZX)
+			code = FPE_FLTDIV;
+		else if (fpscr & FPSCR_XX)
+			code = FPE_FLTRES;
+		_exception(SIGFPE, regs, code, regs->nip);
+		return;
+	}
+
+	if (reason & REASON_TRAP) {
 		/* trap exception */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_bpt(regs))
 			return;
-#endif
-		_exception(SIGTRAP, regs);
-	} else {
+		_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
+		return;
+	}
+
+	if (reason & REASON_PRIVILEGED) {
 		/* Try to emulate it if we should. */
-		int errcode;
-		if ((errcode = emulate_instruction(regs))) {
-			if (errcode == -EFAULT)
-				_exception(SIGBUS, regs);
-			else
-				_exception(SIGILL, regs);
-		}
+		if (emulate_instruction(regs) == 0)
+			return;
+		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+		return;
 	}
-#endif
+
+	_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 }
 
 void
 SingleStepException(struct pt_regs *regs)
 {
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_sstep(regs))
 		return;
-#endif
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, TRAP_TRACE, 0);
 }
 
 void
@@ -332,12 +395,12 @@
 	if (fixed == -EFAULT) {
 		/* fixed == -EFAULT means the operand address was bad */
 		if (user_mode(regs))
-			force_sig(SIGSEGV, current);
+			_exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
 		else
 			bad_page_fault(regs, regs->dar, SIGSEGV);
 		return;
 	}
-	_exception(SIGBUS, regs);	
+	_exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
 }
 
 void
@@ -345,9 +408,7 @@
 {
 	printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
 	       current, regs->gpr[1]);
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	debugger(regs);
-#endif
 	show_regs(regs);
 	panic("kernel stack overflow");
 }
@@ -365,29 +426,29 @@
 SoftwareEmulation(struct pt_regs *regs)
 {
 	extern int do_mathemu(struct pt_regs *);
+	extern int Soft_emulate_8xx(struct pt_regs *);
 	int errcode;
 
 	if (!user_mode(regs)) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		debugger(regs);
-#endif
 		die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
 	}
 
 #ifdef CONFIG_MATH_EMULATION
-	if ((errcode = do_mathemu(regs))) {
+	errcode = do_mathemu(regs);
 #else
-	if ((errcode = Soft_emulate_8xx(regs))) {
+	errcode = Soft_emulate_8xx(regs);
 #endif
+	if (errcode) {
 		if (errcode > 0)
-			_exception(SIGFPE, regs);
+			_exception(SIGFPE, regs, 0, 0);
 		else if (errcode == -EFAULT)
-			_exception(SIGSEGV, regs);
+			_exception(SIGSEGV, regs, 0, 0);
 		else
-			_exception(SIGILL, regs);
+			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 	}
 }
-#endif
+#endif /* CONFIG_8xx */
 
 #if !defined(CONFIG_TAU_INT)
 void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/Makefile linux-2.4.21-rc3/arch/ppc/lib/Makefile
--- linux-2.4.20/arch/ppc/lib/Makefile	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.10 11/08/01 07:57:40 paulus
-#
 #
 # Makefile for ppc-specific library files..
 #
@@ -10,7 +8,7 @@
 
 export-objs		:= dec_and_lock.o
 
-obj-y			:= checksum.o string.o strcase.o dec_and_lock.o
+obj-y			:= checksum.o string.o strcase.o dec_and_lock.o div64.o
 
 obj-$(CONFIG_SMP)	+= locks.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/checksum.S linux-2.4.21-rc3/arch/ppc/lib/checksum.S
--- linux-2.4.20/arch/ppc/lib/checksum.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/checksum.S	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains assembly-language implementations
  * of IP-style 1's complement checksum routines.
  *	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/div64.S linux-2.4.21-rc3/arch/ppc/lib/div64.S
--- linux-2.4.20/arch/ppc/lib/div64.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/div64.S	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+_GLOBAL(__div64_32)
+	lwz	r5,0(r3)	# get the dividend into r5/r6
+	lwz	r6,4(r3)
+	cmplw	r5,r4
+	li	r7,0
+	li	r8,0
+	blt	1f
+	divwu	r7,r5,r4	# if dividend.hi >= divisor,
+	mullw	r0,r7,r4	# quotient.hi = dividend.hi / divisor
+	subf.	r5,r0,r5	# dividend.hi %= divisor
+	beq	3f
+1:	mr	r11,r5		# here dividend.hi != 0
+	andis.	r0,r5,0xc000
+	bne	2f
+	cntlzw	r0,r5		# we are shifting the dividend right
+	li	r10,-1		# to make it < 2^32, and shifting
+	srw	r10,r10,r0	# the divisor right the same amount,
+	add	r9,r4,r10	# rounding up (so the estimate cannot
+	andc	r11,r6,r10	# ever be too large, only too small)
+	andc	r9,r9,r10
+	or	r11,r5,r11
+	rotlw	r9,r9,r0
+	rotlw	r11,r11,r0
+	divwu	r11,r11,r9	# then we divide the shifted quantities
+2:	mullw	r10,r11,r4	# to get an estimate of the quotient,
+	mulhwu	r9,r11,r4	# multiply the estimate by the divisor,
+	subfc	r6,r10,r6	# take the product from the divisor,
+	add	r8,r8,r11	# and add the estimate to the accumulated
+	subfe.	r5,r9,r5	# quotient
+	bne	1b
+3:	cmplw	r6,r4
+	blt	4f
+	divwu	r0,r6,r4	# perform the remaining 32-bit division
+	mullw	r10,r0,r4	# and get the remainder
+	add	r8,r8,r0
+	subf	r6,r10,r6
+4:	stw	r7,0(r3)	# return the quotient in *r3
+	stw	r8,4(r3)
+	mr	r3,r6		# return the remainder in r3
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/locks.c linux-2.4.21-rc3/arch/ppc/lib/locks.c
--- linux-2.4.20/arch/ppc/lib/locks.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/locks.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Locks for smp ppc 
  * 
  * Written by Cort Dougan (cort@cs.nmt.edu)
@@ -35,8 +32,9 @@
 	__asm__ __volatile__ ("\n\
 1:	lwarx	%0,0,%1\n\
 	cmpwi	0,%0,0\n\
-	bne	2f\n\
-	stwcx.	%2,0,%1\n\
+	bne	2f\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%2,0,%1\n\
 	bne-	1b\n\
 	isync\n\
 2:"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/strcase.c linux-2.4.21-rc3/arch/ppc/lib/strcase.c
--- linux-2.4.20/arch/ppc/lib/strcase.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/strcase.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort
- */
 #include <linux/ctype.h>
 
 int strcasecmp(const char *s1, const char *s2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/string.S linux-2.4.21-rc3/arch/ppc/lib/string.S
--- linux-2.4.20/arch/ppc/lib/string.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/lib/string.S	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
@@ -445,23 +442,23 @@
 
 #if !defined(CONFIG_8xx)
 	/* Here we decide how far ahead to prefetch the source */
-#if MAX_L1_COPY_PREFETCH > 1
+#if MAX_COPY_PREFETCH > 1
 	/* Heuristically, for large transfers we prefetch
-	   MAX_L1_COPY_PREFETCH cachelines ahead.  For small transfers
+	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
 	   we prefetch 1 cacheline ahead. */
-	cmpwi	r0,MAX_L1_COPY_PREFETCH
+	cmpwi	r0,MAX_COPY_PREFETCH
 	li	r7,1
 	li	r3,4
 	ble	111f
-	li	r7,MAX_L1_COPY_PREFETCH
+	li	r7,MAX_COPY_PREFETCH
 111:	mtctr	r7
 112:	dcbt	r3,r4
 	addi	r3,r3,CACHELINE_BYTES
 	bdnz	112b
-#else /* MAX_L1_COPY_PREFETCH == 1 */
+#else /* MAX_COPY_PREFETCH == 1 */
 	li	r3,CACHELINE_BYTES + 4
 	dcbt	r11,r4
-#endif /* MAX_L1_COPY_PREFETCH */
+#endif /* MAX_COPY_PREFETCH */
 #endif /* CONFIG_8xx */
 
 	mtctr	r0
@@ -517,18 +514,18 @@
 	blr
 
 /* read fault, initial single-byte copy */
-100:	li	r4,0
+100:	li	r9,0
 	b	90f
 /* write fault, initial single-byte copy */
-101:	li	r4,1
+101:	li	r9,1
 90:	subf	r5,r8,r5
 	li	r3,0
 	b	99f
 /* read fault, initial word copy */
-102:	li	r4,0
+102:	li	r9,0
 	b	91f
 /* write fault, initial word copy */
-103:	li	r4,1
+103:	li	r9,1
 91:	li	r3,2
 	b	99f
 
@@ -552,38 +549,47 @@
 #endif
 
 /* read fault in cacheline loop */
-104:	li	r4,0
+104:	li	r9,0
 	b	92f
 /* fault on dcbz (effectively a write fault) */
 /* or write fault in cacheline loop */
-105:	li	r4,1
+105:	li	r9,1
 92:	li	r3,LG_CACHELINE_BYTES
 	b	99f
 /* read fault in final word loop */
-108:	li	r4,0
+108:	li	r9,0
 	b	93f
 /* write fault in final word loop */
-109:	li	r4,1
+109:	li	r9,1
 93:	andi.	r5,r5,3
 	li	r3,2
 	b	99f
 /* read fault in final byte loop */
-110:	li	r4,0
+110:	li	r9,0
 	b	94f
 /* write fault in final byte loop */
-111:	li	r4,1
+111:	li	r9,1
 94:	li	r5,0
 	li	r3,0
 /*
  * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
  */
 99:	mfctr	r0
 	slw	r3,r0,r3
-	add	r3,r3,r5
-	cmpwi	0,r4,0
+	add.	r3,r3,r5
+	beq	120f			/* shouldn't happen */
+	cmpwi	0,r9,0
 	bne	120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+/* for a read fault, first try to continue the copy one byte at a time */
+	mtctr	r3
+130:	lbz	r0,4(r4)
+131:	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	130b
+/* then clear out the destination: r3 bytes starting at 4(r6) */
+132:	mfctr	r3
 	srwi.	r0,r3,2
 	li	r9,0
 	mtctr	r0
@@ -604,6 +610,8 @@
 	.long	31b,109b
 	.long	40b,110b
 	.long	41b,111b
+	.long	130b,132b
+	.long	131b,120b
 	.long	112b,120b
 	.long	114b,120b
 	.text
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/Makefile linux-2.4.21-rc3/arch/ppc/math-emu/Makefile
--- linux-2.4.20/arch/ppc/math-emu/Makefile	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort
-#
 #
 #
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/double.h linux-2.4.21-rc3/arch/ppc/math-emu/double.h
--- linux-2.4.20/arch/ppc/math-emu/double.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/double.h	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  * Definitions for IEEE Double Precision
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fabs.c linux-2.4.21-rc3/arch/ppc/math-emu/fabs.c
--- linux-2.4.20/arch/ppc/math-emu/fabs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fabs.c	2003-05-22 22:06:28.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fadd.c linux-2.4.21-rc3/arch/ppc/math-emu/fadd.c
--- linux-2.4.20/arch/ppc/math-emu/fadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fadd.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fadds.c linux-2.4.21-rc3/arch/ppc/math-emu/fadds.c
--- linux-2.4.20/arch/ppc/math-emu/fadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fadds.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fcmpo.c linux-2.4.21-rc3/arch/ppc/math-emu/fcmpo.c
--- linux-2.4.20/arch/ppc/math-emu/fcmpo.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fcmpo.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fcmpu.c linux-2.4.21-rc3/arch/ppc/math-emu/fcmpu.c
--- linux-2.4.20/arch/ppc/math-emu/fcmpu.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fcmpu.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fctiw.c linux-2.4.21-rc3/arch/ppc/math-emu/fctiw.c
--- linux-2.4.20/arch/ppc/math-emu/fctiw.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fctiw.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fctiwz.c linux-2.4.21-rc3/arch/ppc/math-emu/fctiwz.c
--- linux-2.4.20/arch/ppc/math-emu/fctiwz.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fctiwz.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fdiv.c linux-2.4.21-rc3/arch/ppc/math-emu/fdiv.c
--- linux-2.4.20/arch/ppc/math-emu/fdiv.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fdiv.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fdivs.c linux-2.4.21-rc3/arch/ppc/math-emu/fdivs.c
--- linux-2.4.20/arch/ppc/math-emu/fdivs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fdivs.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmadd.c linux-2.4.21-rc3/arch/ppc/math-emu/fmadd.c
--- linux-2.4.20/arch/ppc/math-emu/fmadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmadd.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmadds.c linux-2.4.21-rc3/arch/ppc/math-emu/fmadds.c
--- linux-2.4.20/arch/ppc/math-emu/fmadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmadds.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmr.c linux-2.4.21-rc3/arch/ppc/math-emu/fmr.c
--- linux-2.4.20/arch/ppc/math-emu/fmr.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmr.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmsub.c linux-2.4.21-rc3/arch/ppc/math-emu/fmsub.c
--- linux-2.4.20/arch/ppc/math-emu/fmsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmsub.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmsubs.c linux-2.4.21-rc3/arch/ppc/math-emu/fmsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fmsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmsubs.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmul.c linux-2.4.21-rc3/arch/ppc/math-emu/fmul.c
--- linux-2.4.20/arch/ppc/math-emu/fmul.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmul.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmuls.c linux-2.4.21-rc3/arch/ppc/math-emu/fmuls.c
--- linux-2.4.20/arch/ppc/math-emu/fmuls.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fmuls.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnabs.c linux-2.4.21-rc3/arch/ppc/math-emu/fnabs.c
--- linux-2.4.20/arch/ppc/math-emu/fnabs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fnabs.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fneg.c linux-2.4.21-rc3/arch/ppc/math-emu/fneg.c
--- linux-2.4.20/arch/ppc/math-emu/fneg.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fneg.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmadd.c linux-2.4.21-rc3/arch/ppc/math-emu/fnmadd.c
--- linux-2.4.20/arch/ppc/math-emu/fnmadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fnmadd.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmadds.c linux-2.4.21-rc3/arch/ppc/math-emu/fnmadds.c
--- linux-2.4.20/arch/ppc/math-emu/fnmadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fnmadds.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmsub.c linux-2.4.21-rc3/arch/ppc/math-emu/fnmsub.c
--- linux-2.4.20/arch/ppc/math-emu/fnmsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fnmsub.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmsubs.c linux-2.4.21-rc3/arch/ppc/math-emu/fnmsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fnmsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fnmsubs.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fres.c linux-2.4.21-rc3/arch/ppc/math-emu/fres.c
--- linux-2.4.20/arch/ppc/math-emu/fres.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fres.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/frsp.c linux-2.4.21-rc3/arch/ppc/math-emu/frsp.c
--- linux-2.4.20/arch/ppc/math-emu/frsp.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/frsp.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/frsqrte.c linux-2.4.21-rc3/arch/ppc/math-emu/frsqrte.c
--- linux-2.4.20/arch/ppc/math-emu/frsqrte.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/frsqrte.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsel.c linux-2.4.21-rc3/arch/ppc/math-emu/fsel.c
--- linux-2.4.20/arch/ppc/math-emu/fsel.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fsel.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsqrt.c linux-2.4.21-rc3/arch/ppc/math-emu/fsqrt.c
--- linux-2.4.20/arch/ppc/math-emu/fsqrt.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fsqrt.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsqrts.c linux-2.4.21-rc3/arch/ppc/math-emu/fsqrts.c
--- linux-2.4.20/arch/ppc/math-emu/fsqrts.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fsqrts.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsub.c linux-2.4.21-rc3/arch/ppc/math-emu/fsub.c
--- linux-2.4.20/arch/ppc/math-emu/fsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fsub.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsubs.c linux-2.4.21-rc3/arch/ppc/math-emu/fsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/fsubs.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/lfd.c linux-2.4.21-rc3/arch/ppc/math-emu/lfd.c
--- linux-2.4.20/arch/ppc/math-emu/lfd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/lfd.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/lfs.c linux-2.4.21-rc3/arch/ppc/math-emu/lfs.c
--- linux-2.4.20/arch/ppc/math-emu/lfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/lfs.c	2003-05-22 22:06:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/math.c linux-2.4.21-rc3/arch/ppc/math-emu/math.c
--- linux-2.4.20/arch/ppc/math-emu/math.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/math.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort
- */
-/*
  * arch/ppc/math-emu/math.c
  *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mcrfs.c linux-2.4.21-rc3/arch/ppc/math-emu/mcrfs.c
--- linux-2.4.20/arch/ppc/math-emu/mcrfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mcrfs.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mffs.c linux-2.4.21-rc3/arch/ppc/math-emu/mffs.c
--- linux-2.4.20/arch/ppc/math-emu/mffs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mffs.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsb0.c linux-2.4.21-rc3/arch/ppc/math-emu/mtfsb0.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsb0.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mtfsb0.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsb1.c linux-2.4.21-rc3/arch/ppc/math-emu/mtfsb1.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsb1.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mtfsb1.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsf.c linux-2.4.21-rc3/arch/ppc/math-emu/mtfsf.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsf.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mtfsf.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsfi.c linux-2.4.21-rc3/arch/ppc/math-emu/mtfsfi.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsfi.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/mtfsfi.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-1.h linux-2.4.21-rc3/arch/ppc/math-emu/op-1.h
--- linux-2.4.20/arch/ppc/math-emu/op-1.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/op-1.h	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic one-word fraction declaration and manipulation.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-2.h linux-2.4.21-rc3/arch/ppc/math-emu/op-2.h
--- linux-2.4.20/arch/ppc/math-emu/op-2.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/op-2.h	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic two-word fraction declaration and manipulation.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-4.h linux-2.4.21-rc3/arch/ppc/math-emu/op-4.h
--- linux-2.4.20/arch/ppc/math-emu/op-4.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/op-4.h	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic four-word fraction declaration and manipulation.
  *
  * When adding quadword support for 32 bit machines, we need
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-common.h linux-2.4.21-rc3/arch/ppc/math-emu/op-common.h
--- linux-2.4.20/arch/ppc/math-emu/op-common.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/op-common.h	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort
- */
-
 #define _FP_DECL(wc, X)			\
   _FP_I_TYPE X##_c, X##_s, X##_e;	\
   _FP_FRAC_DECL_##wc(X)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/sfp-machine.h linux-2.4.21-rc3/arch/ppc/math-emu/sfp-machine.h
--- linux-2.4.20/arch/ppc/math-emu/sfp-machine.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/sfp-machine.h	2003-05-22 22:06:38.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort
- */
 /* Machine-dependent software floating-point definitions.  PPC version.
    Copyright (C) 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/single.h linux-2.4.21-rc3/arch/ppc/math-emu/single.h
--- linux-2.4.20/arch/ppc/math-emu/single.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/single.h	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Definitions for IEEE Single Precision
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/soft-fp.h linux-2.4.21-rc3/arch/ppc/math-emu/soft-fp.h
--- linux-2.4.20/arch/ppc/math-emu/soft-fp.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/soft-fp.h	2003-05-22 22:06:38.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort
- */
 #ifndef SOFT_FP_H
 #define SOFT_FP_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfd.c linux-2.4.21-rc3/arch/ppc/math-emu/stfd.c
--- linux-2.4.20/arch/ppc/math-emu/stfd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/stfd.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfiwx.c linux-2.4.21-rc3/arch/ppc/math-emu/stfiwx.c
--- linux-2.4.20/arch/ppc/math-emu/stfiwx.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/stfiwx.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfs.c linux-2.4.21-rc3/arch/ppc/math-emu/stfs.c
--- linux-2.4.20/arch/ppc/math-emu/stfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/stfs.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/types.c linux-2.4.21-rc3/arch/ppc/math-emu/types.c
--- linux-2.4.20/arch/ppc/math-emu/types.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/types.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort
- */
-
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/udivmodti4.c linux-2.4.21-rc3/arch/ppc/math-emu/udivmodti4.c
--- linux-2.4.20/arch/ppc/math-emu/udivmodti4.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/math-emu/udivmodti4.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort
- */
 /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
 
 #include "soft-fp.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_mmu.c linux-2.4.21-rc3/arch/ppc/mm/4xx_mmu.c
--- linux-2.4.20/arch/ppc/mm/4xx_mmu.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/4xx_mmu.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for initializing the MMU
  * on the 4xx series of chips.
  *  -- paulus
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_tlb.c linux-2.4.21-rc3/arch/ppc/mm/4xx_tlb.c
--- linux-2.4.20/arch/ppc/mm/4xx_tlb.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/4xx_tlb.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.4xx_tlb.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  *
  *    Copyright (c) 1998-1999 TiVo, Inc.
  *      Original implementation.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_tlb.h linux-2.4.21-rc3/arch/ppc/mm/4xx_tlb.h
--- linux-2.4.20/arch/ppc/mm/4xx_tlb.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/4xx_tlb.h	2003-05-22 22:06:46.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.4xx_tlb.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/Makefile linux-2.4.21-rc3/arch/ppc/mm/Makefile
--- linux-2.4.20/arch/ppc/mm/Makefile	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/Makefile	2003-05-22 22:06:39.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.8 08/16/01 17:25:47 paulus
-#
 #
 # Makefile for the linux ppc-specific parts of the memory manager.
 #
@@ -20,7 +18,6 @@
 					mmu_context.o pgtable.o
 
 obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
-obj-$(CONFIG_PPC_ISERIES)	+= iSeries_hashtable.o iSeries_mmu.o tlb.o
 obj-$(CONFIG_4xx)		+= cachemap.o 4xx_mmu.o
 obj-$(CONFIG_8xx)		+= cachemap.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/cachemap.c linux-2.4.21-rc3/arch/ppc/mm/cachemap.c
--- linux-2.4.20/arch/ppc/mm/cachemap.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/cachemap.c	2003-05-22 22:06:43.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *  PowerPC version derived from arch/arm/mm/consistent.c
  *    Copyright (C) 2001 Dan Malek (dmalek@jlc.net)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/extable.c linux-2.4.21-rc3/arch/ppc/mm/extable.c
--- linux-2.4.20/arch/ppc/mm/extable.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/extable.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * linux/arch/ppc/mm/extable.c
  *
  * from linux/arch/i386/mm/extable.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/fault.c linux-2.4.21-rc3/arch/ppc/mm/fault.c
--- linux-2.4.20/arch/ppc/mm/fault.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/fault.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.fault.c 1.15 09/24/01 16:35:10 paulus
- */
-/*
  *  arch/ppc/mm/fault.c
  *
  *  PowerPC version 
@@ -56,6 +53,41 @@
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 
 /*
+ * Check whether the instruction at regs->nip is a store using
+ * an update addressing form which will update r1.
+ */
+static int store_updates_sp(struct pt_regs *regs)
+{
+	unsigned int inst;
+
+	if (get_user(inst, (unsigned int *)regs->nip))
+		return 0;
+	/* check for 1 in the rA field */
+	if (((inst >> 16) & 0x1f) != 1)
+		return 0;
+	/* check major opcode */
+	switch (inst >> 26) {
+	case 37:	/* stwu */
+	case 39:	/* stbu */
+	case 45:	/* sthu */
+	case 53:	/* stfsu */
+	case 55:	/* stfdu */
+		return 1;
+	case 31:
+		/* check minor opcode */
+		switch ((inst >> 1) & 0x3ff) {
+		case 183:	/* stwux */
+		case 247:	/* stbux */
+		case 439:	/* sthux */
+		case 695:	/* stfsux */
+		case 759:	/* stfdux */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
  * For 600- and 800-family processors, the error_code parameter is DSISR
  * for a data fault, SRR1 for an instruction fault. For 400-family processors
  * the error_code parameter is ESR for a data fault, 0 for an instruction
@@ -111,6 +143,40 @@
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
+	if (!is_write)
+                goto bad_area;
+
+	/*
+	 * N.B. The rs6000/xcoff ABI allows programs to access up to
+	 * a few hundred bytes below the stack pointer.
+	 * The kernel signal delivery code writes up to about 1.5kB
+	 * below the stack pointer (r1) before decrementing it.
+	 * The exec code can write slightly over 640kB to the stack
+	 * before setting the user r1.  Thus we allow the stack to
+	 * expand to 1MB without further checks.
+	 */
+	if (address + 0x100000 < vma->vm_end) {
+		/* get user regs even if this fault is in kernel mode */
+		struct pt_regs *uregs = current->thread.regs;
+		if (uregs == NULL)
+			goto bad_area;
+
+		/*
+		 * A user-mode access to an address a long way below
+		 * the stack pointer is only valid if the instruction
+		 * is one which would update the stack pointer to the
+		 * address accessed if the instruction completed,
+		 * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
+		 * (or the byte, halfword, float or double forms).
+		 *
+		 * If we don't check this then any write to the area
+		 * between the last mapped region and the stack will
+		 * expand the stack rather than segfaulting.
+		 */
+		if (address + 2048 < uregs->gpr[1]
+		    && (!user_mode(regs) || !store_updates_sp(regs)))
+			goto bad_area;
+	}
 	if (expand_stack(vma, address))
 		goto bad_area;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/hashtable.S linux-2.4.21-rc3/arch/ppc/mm/hashtable.S
--- linux-2.4.20/arch/ppc/mm/hashtable.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/hashtable.S	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/hashtable.S
  *
  *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
@@ -27,7 +24,6 @@
  */
 
 #include <linux/config.h>
-#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -335,25 +331,6 @@
 	ori	r8,r8,_PAGE_COHERENT	/* set M (coherence required) */
 #endif
 
-#ifdef CONFIG_POWER4
-	/*
-	 * XXX hack hack hack - translate 32-bit "physical" addresses
-	 * in the linux page tables to 42-bit real addresses in such
-	 * a fashion that we can get at the I/O we need to access.
-	 *	-- paulus
-	 */
-	cmpwi	r8,0
-	rlwinm	r0,r8,16,16,30
-	bge	57f
-	cmplwi	r0,0xfe00
-	li	r0,0x3fd
-	bne	56f
-	li	r0,0x3ff
-56:	sldi	r0,r0,32
-	or	r8,r8,r0
-57:
-#endif
-
 	/* Construct the high word of the PPC-style PTE (r5) */
 #ifndef CONFIG_PPC64BRIDGE
 	rlwinm	r5,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/init.c linux-2.4.21-rc3/arch/ppc/mm/init.c
--- linux-2.4.20/arch/ppc/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/init.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.43 03/12/02 12:13:51 paulus
- */
-/*
- *  PowerPC version 
+ *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
@@ -51,10 +48,12 @@
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
-void *end_of_DRAM;
 unsigned long total_memory;
 unsigned long total_lowmem;
 
+unsigned long ppc_memstart;
+unsigned long ppc_memoffset = PAGE_OFFSET;
+
 int mem_init_done;
 int init_bootmem_done;
 int boot_mapsize;
@@ -181,13 +180,13 @@
 				iscur = 1;
 				printk("current");
 			}
-			
+
 			if ( p == last_task_used_math )
 			{
 				if ( iscur )
 					printk(",");
 				printk("last math");
-			}			
+			}
 #endif /* CONFIG_SMP */
 			printk("\n");
 		}
@@ -312,8 +311,7 @@
 	if (__max_memory && total_memory > __max_memory)
 		total_memory = __max_memory;
 	total_lowmem = total_memory;
-	adjust_total_lowmem();	
-	end_of_DRAM = __va(total_lowmem);
+	adjust_total_lowmem();
 	set_phys_avail(total_lowmem);
 
 	/* Initialize the MMU hardware */
@@ -396,8 +394,11 @@
 	}
 	start = PAGE_ALIGN(start);
 
-	boot_mapsize = init_bootmem(start >> PAGE_SHIFT,
-				    total_lowmem >> PAGE_SHIFT);
+	min_low_pfn = start >> PAGE_SHIFT;
+	max_low_pfn = (PPC_MEMSTART + total_lowmem) >> PAGE_SHIFT;
+	boot_mapsize = init_bootmem_node(&contig_page_data, min_low_pfn,
+					 PPC_MEMSTART >> PAGE_SHIFT,
+					 max_low_pfn);
 
 	/* remove the bootmem bitmap from the available memory */
 	mem_pieces_remove(&phys_avail, start, boot_mapsize, 1);
@@ -450,12 +451,10 @@
 
 	highmem_mapnr = total_lowmem >> PAGE_SHIFT;
 	highmem_start_page = mem_map + highmem_mapnr;
-	max_mapnr = total_memory >> PAGE_SHIFT;
-#else
-	max_mapnr = max_low_pfn;
 #endif /* CONFIG_HIGHMEM */
+	max_mapnr = total_memory >> PAGE_SHIFT;
 
-	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+	high_memory = (void *) __va(PPC_MEMSTART + total_lowmem);
 	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
 
 	totalram_pages += free_all_bootmem();
@@ -485,7 +484,7 @@
 		     addr += PAGE_SIZE)
 			SetPageReserved(virt_to_page(addr));
 
-	for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
+	for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory;
 	     addr += PAGE_SIZE) {
 		if (!PageReserved(virt_to_page(addr)))
 			continue;
@@ -544,7 +543,7 @@
 	 * physical memory.
 	 */
 
-	phys_avail.regions[0].address = 0;
+	phys_avail.regions[0].address = PPC_MEMSTART;
 	phys_avail.regions[0].size = total_memory;
 	phys_avail.n_regions = 1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mem_pieces.c linux-2.4.21-rc3/arch/ppc/mm/mem_pieces.c
--- linux-2.4.20/arch/ppc/mm/mem_pieces.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/mem_pieces.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mem_pieces.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mem_pieces.h linux-2.4.21-rc3/arch/ppc/mm/mem_pieces.h
--- linux-2.4.20/arch/ppc/mm/mem_pieces.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/mem_pieces.h	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mmu_context.c linux-2.4.21-rc3/arch/ppc/mm/mmu_context.c
--- linux-2.4.20/arch/ppc/mm/mmu_context.c	2001-10-02 16:12:44.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/mmu_context.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mmu_decl.h linux-2.4.21-rc3/arch/ppc/mm/mmu_decl.h
--- linux-2.4.20/arch/ppc/mm/mmu_decl.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/mmu_decl.h	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Declarations of procedures and variables shared between files
  * in arch/ppc/mm/.
  * 
@@ -34,19 +31,14 @@
 extern void reserve_phys_mem(unsigned long start, unsigned long size);
 
 extern int __map_without_bats;
-extern void *end_of_DRAM;
 extern unsigned long ioremap_base;
 extern unsigned long ioremap_bot;
 extern unsigned int rtas_data, rtas_size;
 
 extern unsigned long total_memory;
 extern unsigned long total_lowmem;
-extern unsigned long ram_phys_base;
 extern int mem_init_done;
 
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-
 /* ...and now those things that may be slightly different between processor
  * architectures.  -- Dan
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/pgtable.c linux-2.4.21-rc3/arch/ppc/mm/pgtable.c
--- linux-2.4.20/arch/ppc/mm/pgtable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/pgtable.c	2003-05-22 22:06:28.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines setting up the linux page tables.
  *  -- paulus
  * 
@@ -32,11 +29,10 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
 
 #include "mmu_decl.h"
 
-unsigned long ram_phys_base;
-
 unsigned long ioremap_base;
 unsigned long ioremap_bot;
 int io_bat_index;
@@ -71,7 +67,6 @@
 #define p_mapped_by_bats(x)	(0UL)
 #endif /* HAVE_BATS */
 
-#ifndef CONFIG_PPC_ISERIES
 void *
 ioremap(unsigned long addr, unsigned long size)
 {
@@ -171,7 +166,6 @@
 	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
 		vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
-#endif /* CONFIG_PPC_ISERIES */
 
 int
 map_page(unsigned long va, unsigned long pa, int flags)
@@ -203,7 +197,7 @@
 #ifdef HAVE_BATS
 	unsigned long bat_max = 0x10000000;
 	unsigned long align;
-	unsigned long ram = total_lowmem;
+	unsigned long ram;
 	int is601 = 0;
 	
 	/* 601s have smaller BATs */
@@ -212,10 +206,20 @@
 		is601 = 1;
 	}
 
+	/* adjust BAT block size to max_low_mem */
+	if (max_low_mem < bat_max)
+		bat_max = max_low_mem;
+
+	/* adjust lowmem size to max_low_mem */
+	if (max_low_mem < total_lowmem)
+		ram = max_low_mem;
+	else
+		ram = total_lowmem;
+
 	/* Make sure we don't map a block larger than the
 	   smallest alignment of the physical address. */
-	/* alignment of ram_phys_base */
-	align = ~(ram_phys_base-1) & ram_phys_base;
+	/* alignment of PPC_MEMSTART */
+	align = ~(PPC_MEMSTART-1) & PPC_MEMSTART;
 	/* set BAT block size to MIN(max_size, align) */
 	if (align && align < bat_max)
 		bat_max = align;
@@ -232,8 +236,9 @@
 		ram -= __bat3;
 	}
 
-	printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb, residual: %ldMb\n",
-		__bat2 >> 20, __bat3 >> 20, ram >> 20);
+	printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb,"
+			" residual: %ldMb\n", __bat2 >> 20, __bat3 >> 20,
+			(total_lowmem - (__bat2 - __bat3)) >> 20);
 
 	/* On SMP, we limit the lowmem to the area mapped with BATs.
 	 * We also assume nobody will do SMP with 601s
@@ -247,8 +252,9 @@
 	if (total_lowmem > max_low_mem) {
 		total_lowmem = max_low_mem;
 #ifndef CONFIG_HIGHMEM
-		printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM"
-			" to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20);
+		printk(KERN_INFO "Warning, memory limited to %ld Mb, use "
+				"CONFIG_HIGHMEM to reach %ld Mb\n",
+				max_low_mem >> 20, total_memory >> 20);
 		total_memory = total_lowmem;
 #endif /* CONFIG_HIGHMEM */
 	}
@@ -267,7 +273,7 @@
 #endif /* HAVE_BATS */
 
 	v = KERNELBASE;
-	p = ram_phys_base;
+	p = PPC_MEMSTART;
 	for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
 		/* On the MPC8xx, we want the page shared so we
 		 * don't get ASID compares on kernel space.
@@ -290,6 +296,8 @@
 		v += PAGE_SIZE;
 		p += PAGE_SIZE;
 	}
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:mapin_ram done", 0x401);
 }
 
 /* is x a power of 2? */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/ppc_mmu.c linux-2.4.21-rc3/arch/ppc/mm/ppc_mmu.c
--- linux-2.4.20/arch/ppc/mm/ppc_mmu.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/ppc_mmu.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
@@ -91,11 +88,11 @@
 	unsigned long tot, done;
 	
 	tot = total_lowmem;
-	setbat(2, KERNELBASE, ram_phys_base, bat2, _PAGE_KERNEL);
+	setbat(2, KERNELBASE, PPC_MEMSTART, bat2, _PAGE_KERNEL);
 	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
 	if ((done < tot) && !bat_addrs[3].limit && bat3) {
 		tot -= done;
-		setbat(3, KERNELBASE+done, ram_phys_base+done, bat3, 
+		setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bat3, 
 		       _PAGE_KERNEL);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/tlb.c linux-2.4.21-rc3/arch/ppc/mm/tlb.c
--- linux-2.4.20/arch/ppc/mm/tlb.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/mm/tlb.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,10 +1,7 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for TLB flushing.
  * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the the
+ * physical translations, these routines flush entries from the 
  * hash table also.
  *  -- paulus
  * 
@@ -30,7 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-
+#include <asm/mmu.h>
 #include "mmu_decl.h"
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/Makefile linux-2.4.21-rc3/arch/ppc/platforms/Makefile
--- linux-2.4.20/arch/ppc/platforms/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/Makefile	2003-05-22 22:06:54.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.57 09/24/01 07:45:31 trini
-#
 #
 # Makefile for the linux kernel.
 #
@@ -46,6 +44,7 @@
 obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
 obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
+obj-$(CONFIG_LOPEC)		+= lopec_setup.o lopec_pci.o
 obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o cpc700_pic.o
 obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_pci.c linux-2.4.21-rc3/arch/ppc/platforms/apus_pci.c
--- linux-2.4.20/arch/ppc/platforms/apus_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/apus_pci.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
  *
  * APUS PCI routines.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_pci.h linux-2.4.21-rc3/arch/ppc/platforms/apus_pci.h
--- linux-2.4.20/arch/ppc/platforms/apus_pci.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/apus_pci.h	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
  * driver.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_setup.c linux-2.4.21-rc3/arch/ppc/platforms/apus_setup.c
--- linux-2.4.20/arch/ppc/platforms/apus_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/apus_setup.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/apus_setup.c
  *
  *  Copyright (C) 1998, 1999  Jesper Skov
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/bseip.h linux-2.4.21-rc3/arch/ppc/platforms/bseip.h
--- linux-2.4.20/arch/ppc/platforms/bseip.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/bseip.h	2003-05-22 22:06:25.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_pci.c linux-2.4.21-rc3/arch/ppc/platforms/chrp_pci.c
--- linux-2.4.20/arch/ppc/platforms/chrp_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/chrp_pci.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * CHRP pci routines.
  */
 
@@ -26,12 +23,15 @@
 #include <asm/open_pic.h>
 
 /* LongTrail */
-unsigned long gg2_pci_config_base;
+unsigned long gg2_pci_config_base __chrpdata;
 
 #define pci_config_addr(dev, offset) \
-(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
+(gg2_pci_config_base + ((dev->bus->number<<16) | (dev->devfn<<8) | offset))
+
+volatile struct Hydra *Hydra __chrpdata = NULL;
 
-volatile struct Hydra *Hydra = NULL;
+/* BriQ */
+extern int chrp_is_briq;
 
 /*
  * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
@@ -66,7 +66,7 @@
 GG2_PCI_OP(write, word, u16, out_le16)
 GG2_PCI_OP(write, dword, u32, out_le32)
 
-static struct pci_ops gg2_pci_ops =
+static struct pci_ops gg2_pci_ops __chrpdata =
 {
 	gg2_read_config_byte,
 	gg2_read_config_word,
@@ -101,7 +101,7 @@
 PYTHON_PCI_OP(write, word, u16, out_le16, 2)
 PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
 
-static struct pci_ops python_pci_ops =
+static struct pci_ops python_pci_ops __chrpdata =
 {
 	python_read_config_byte,
 	python_read_config_word,
@@ -148,7 +148,7 @@
 RTAS_PCI_WRITE_OP(word, u16, 2)
 RTAS_PCI_WRITE_OP(dword, u32, 4)
 
-static struct pci_ops rtas_pci_ops =
+static struct pci_ops rtas_pci_ops __chrpdata =
 {
 	rtas_read_config_byte,
 	rtas_read_config_word,
@@ -194,6 +194,71 @@
 	}
 }
 
+/* W83C553 IDE Interrupt Routing Control Register */
+#define W83C553_IDEIRCR                0x43
+
+/* SL82C105 IDE Control/Status Register */
+#define SL82C105_IDECSR                0x40
+
+static void __init
+longtrail_pcibios_fixup(void)
+{
+       struct pci_dev *w83c553, *sl82c105;
+       u8 progif;
+
+       chrp_pcibios_fixup();
+
+       /*
+        *  Open Firmware may have left the SL82C105 IDE interface in the
+        *  W83C553 PCI/ISA bridge in legacy mode
+        */
+       if ((w83c553 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                      PCI_DEVICE_ID_WINBOND_83C553, 0)) &&
+           (sl82c105 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                       PCI_DEVICE_ID_WINBOND_82C105,
+                                       w83c553)) &&
+           (sl82c105->class & 5) != 5) {
+               printk("W83C553: Switching SL82C105 IDE to PCI native mode\n");
+               /* Enable W83C553 legacy interrupt internal routing to INTC#, */
+               /* which is connected to HYDRA_INT_EXT5 */
+               pci_write_config_byte(w83c553, W83C553_IDEIRCR, 0x00);
+               /* Enable SL82C105 PCI native IDE mode */
+               pci_read_config_byte(sl82c105, PCI_CLASS_PROG, &progif);
+               pci_write_config_byte(sl82c105, PCI_CLASS_PROG, progif | 0x05);
+               sl82c105->class |= 0x05;
+               /* Enable SL82C105 legacy interrupts & both channels */
+               pci_write_config_word(sl82c105, SL82C105_IDECSR, 0x0833);
+       }
+}
+
+static void __init
+briq_pcibios_fixup(void)
+{
+       struct pci_dev *w83c553, *sl82c105;
+       u8 progif;
+
+       chrp_pcibios_fixup();
+
+       /*
+        *  Open Firmware may have left the SL82C105 IDE interface in the
+        *  W83C553 PCI/ISA bridge in legacy mode
+        */
+       if ((w83c553 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                      PCI_DEVICE_ID_WINBOND_83C553, 0)) &&
+           (sl82c105 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                       PCI_DEVICE_ID_WINBOND_82C105,
+                                       w83c553)) &&
+           (sl82c105->class & 5) != 5) {
+               printk("W83C553: Switching SL82C105 IDE to PCI native mode\n");
+               /* Enable SL82C105 PCI native IDE mode */
+               pci_read_config_byte(sl82c105, PCI_CLASS_PROG, &progif);
+               pci_write_config_byte(sl82c105, PCI_CLASS_PROG, progif | 0x05);
+               sl82c105->class |= 0x05;
+               /* Disable SL82C105 second port */
+               pci_write_config_word(sl82c105, SL82C105_IDECSR, 0x0003);
+       }
+}
+
 #define PRG_CL_RESET_VALID 0x00010000
 
 static void __init
@@ -318,5 +383,10 @@
 		}
 	}
 
-	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+       if (is_longtrail)
+               ppc_md.pcibios_fixup = longtrail_pcibios_fixup;
+       else if (chrp_is_briq)
+               ppc_md.pcibios_fixup = briq_pcibios_fixup;
+       else
+               ppc_md.pcibios_fixup = chrp_pcibios_fixup;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_setup.c linux-2.4.21-rc3/arch/ppc/platforms/chrp_setup.c
--- linux-2.4.20/arch/ppc/platforms/chrp_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/chrp_setup.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -56,6 +53,11 @@
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
 
+#ifdef CONFIG_SERIAL
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#endif
+
 unsigned long chrp_get_rtc_time(void);
 int chrp_set_rtc_time(unsigned long nowtime);
 void chrp_calibrate_decr(void);
@@ -81,13 +83,11 @@
 
 extern kdev_t boot_dev;
 
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
 extern unsigned long loops_per_jiffy;
-static int max_width;
-static int is_briq;
-unsigned int* briq_SPOR; /* To be replaced by RTAS when available */
+
+static int max_width __chrpdata;
+int chrp_is_briq __chrpdata;
+unsigned int* briq_SPOR __chrpdata; /* To be replaced by RTAS when available */
 
 #ifdef CONFIG_SMP
 extern struct smp_ops_t chrp_smp_ops;
@@ -411,8 +411,6 @@
 chrp_init_irq_openpic(unsigned long intack)
 {
 	int i;
-	unsigned char* chrp_int_ack_special = 0;
-	int nmi_irq = -1;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
 
 	chrp_find_openpic();
@@ -421,12 +419,14 @@
 	OpenPIC_InitSenses = init_senses;
 	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
 
-	if (intack)
-		chrp_int_ack_special = (unsigned char *) ioremap(intack, 1);
-	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
+	openpic_init(NUM_8259_INTERRUPTS);
+	/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+			       i8259_irq);
+
 	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0);
+	i8259_init(intack);
 }
 
 static void __init
@@ -492,7 +492,7 @@
 chrp_init2(void)
 {
  
-	if (is_briq)
+	if (chrp_is_briq)
 		briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
 #ifdef CONFIG_NVRAM  
 /* Fix me: currently, a lot of pmac_nvram routines are marked __pmac, and
@@ -500,7 +500,7 @@
  * Among others, it cracks on briQ.
  * Please implement a CHRP specific version. --BenH
  */
-	if (!is_briq)
+	if (!chrp_is_briq)
 		pmac_nvram_init();
 #endif
 	/* This is to be replaced by RTAS when available */
@@ -532,46 +532,6 @@
 #endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
 }
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif
-
 void __init
 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7)
@@ -595,7 +555,15 @@
 
 	/* Check if it's a briq */
 	machine = get_property(root, "model", NULL);
-	is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0;
+	chrp_is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0;
+#ifdef CONFIG_SERIAL
+	if (chrp_is_briq) {
+		/* briQ has a different serial clock */
+		extern struct serial_state rs_table[];
+		rs_table[0].baud_base = (7372800 / 16);
+		rs_table[1].baud_base = (7372800 / 16);
+	}
+#endif /* CONFIG_SERIAL */	
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.show_percpuinfo = of_show_percpuinfo;
@@ -606,7 +574,7 @@
 
 	ppc_md.init           = chrp_init2;
 
-	ppc_md.restart        = is_briq ? briq_restart : chrp_restart;
+	ppc_md.restart        = chrp_is_briq ? briq_restart : chrp_restart;
 	ppc_md.power_off      = chrp_power_off;
 	ppc_md.halt           = chrp_halt;
 
@@ -623,8 +591,10 @@
 	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
 	ppc_md.kbd_translate     = pckbd_translate;
 	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
+	if (!chrp_is_briq) {
+		ppc_md.kbd_leds          = pckbd_leds;
+		ppc_md.kbd_init_hw       = pckbd_init_hw;
+	}
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
@@ -657,10 +627,6 @@
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
-        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 #endif
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_smp.c linux-2.4.21-rc3/arch/ppc/platforms/chrp_smp.c
--- linux-2.4.20/arch/ppc/platforms/chrp_smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/chrp_smp.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Smp support for CHRP machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
@@ -125,37 +122,9 @@
 
 	if (OpenPIC_Addr)
 		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_POWER4
-static void __chrp
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* for now, only do reschedule messages
-	   since we only have one IPI */
-	if (msg != PPC_MSG_RESCHEDULE)
-		return;
-	for (i = 0; i < smp_num_cpus; ++i) {
-		if (target == MSG_ALL || target == i
-		    || (target == MSG_ALL_BUT_SELF
-			&& i != smp_processor_id()))
-			xics_cause_IPI(i);
-	}
-}
 
-static int __chrp
-smp_xics_probe(void)
-{
-	return smp_chrp_cpu_nr;
-}
-
-static void __chrp
-smp_xics_setup_cpu(int cpu_nr)
-{
-	if (cpu_nr > 0)
-		xics_setup_cpu();
+	spread_heartbeat();
 }
-#endif /* CONFIG_POWER4 */
 
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops __chrpdata = {
@@ -164,13 +133,3 @@
 	smp_chrp_kick_cpu,
 	smp_chrp_setup_cpu,
 };
-
-#ifdef CONFIG_POWER4
-/* CHRP with new XICS interrupt controller */
-struct smp_ops_t xics_smp_ops __chrpdata = {
-	smp_xics_message_pass,
-	smp_xics_probe,
-	smp_chrp_kick_cpu,
-	smp_xics_setup_cpu,
-};
-#endif /* CONFIG_POWER4 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_time.c linux-2.4.21-rc3/arch/ppc/platforms/chrp_time.c
--- linux-2.4.20/arch/ppc/platforms/chrp_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/chrp_time.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/chrp_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/cpc700.h linux-2.4.21-rc3/arch/ppc/platforms/cpc700.h
--- linux-2.4.20/arch/ppc/platforms/cpc700.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/cpc700.h	2003-05-22 22:06:38.000000000 +0000
@@ -6,27 +6,10 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2000-2002 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2000-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/cpc700_pic.c linux-2.4.21-rc3/arch/ppc/platforms/cpc700_pic.c
--- linux-2.4.20/arch/ppc/platforms/cpc700_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/cpc700_pic.c	2003-05-22 22:06:38.000000000 +0000
@@ -8,27 +8,10 @@
  *          mporter@mvista.com
  *          jpeters@mvista.com
  *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/stddef.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/error_log.c linux-2.4.21-rc3/arch/ppc/platforms/error_log.c
--- linux-2.4.20/arch/ppc/platforms/error_log.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/error_log.c	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
- */
-/*
  *  arch/ppc/kernel/error_log.c
  *  
  *  Copyright (c) 2000 Tilmann Bitterberg
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/error_log.h linux-2.4.21-rc3/arch/ppc/platforms/error_log.h
--- linux-2.4.20/arch/ppc/platforms/error_log.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/error_log.h	2003-05-22 22:06:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
- */
 #ifndef __ERROR_LOG_H__
 #define __ERROR_LOG_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/est8260.h linux-2.4.21-rc3/arch/ppc/platforms/est8260.h
--- linux-2.4.20/arch/ppc/platforms/est8260.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/est8260.h	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
- */
-
 /* Board information for the EST8260, which should be generic for
  * all 8260 boards.  The IMMR is now given to us so the hard define
  * will soon be removed.  All of the clock values are computed from
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/fads.h linux-2.4.21-rc3/arch/ppc/platforms/fads.h
--- linux-2.4.20/arch/ppc/platforms/fads.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/fads.h	2003-05-22 22:06:25.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola 860T FADS board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini.h linux-2.4.21-rc3/arch/ppc/platforms/gemini.h
--- linux-2.4.20/arch/ppc/platforms/gemini.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/gemini.h	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/gemini.h
  *
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_pci.c linux-2.4.21-rc3/arch/ppc/platforms/gemini_pci.c
--- linux-2.4.20/arch/ppc/platforms/gemini_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/gemini_pci.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_prom.S linux-2.4.21-rc3/arch/ppc/platforms/gemini_prom.S
--- linux-2.4.20/arch/ppc/platforms/gemini_prom.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/gemini_prom.S	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/gemini_prom.S
  *
  *  Not really prom support code (yet), but sort of anti-prom code.  The current
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_serial.h linux-2.4.21-rc3/arch/ppc/platforms/gemini_serial.h
--- linux-2.4.20/arch/ppc/platforms/gemini_serial.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/gemini_serial.h	2003-05-22 22:06:41.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASMPPC_GEMINI_SERIAL_H
 #define __ASMPPC_GEMINI_SERIAL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_setup.c linux-2.4.21-rc3/arch/ppc/platforms/gemini_setup.c
--- linux-2.4.20/arch/ppc/platforms/gemini_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/gemini_setup.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995 Linus Torvalds
@@ -118,13 +115,14 @@
 }
 
 static u_char gemini_openpic_initsenses[] = {
-	1,
-	1,
-	1,
-	1,
-	0,
-	0,
-	1, /* remainder are level-triggered */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 6 */
+	/* remainder are level-triggered */
 };
 
 #define GEMINI_MPIC_ADDR (0xfcfc0000)
@@ -330,7 +328,7 @@
 void __init gemini_init_IRQ(void)
 {
 	/* gemini has no 8259 */
-	openpic_init(1, 0, 0, -1);
+	openpic_init(0);
 }
 
 #define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
@@ -374,7 +372,7 @@
 		year = gemini_rtc_read(M48T35_RTC_YEAR);
 	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
 #ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
 	       sec, min, hour, day, mon, year);
 #endif
 
@@ -390,7 +388,7 @@
 	if ((year += 1900) < 1970)
 		year += 100;
 #ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
 	       sec, min, hour, day, mon, year);
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/ivms8.h linux-2.4.21-rc3/arch/ppc/platforms/ivms8.h
--- linux-2.4.20/arch/ppc/platforms/ivms8.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/ivms8.h	2003-05-22 22:06:44.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
- */
-/*
  * Speech Design Integrated Voicemail board specific definitions
  * - IVMS8  (small,  8 channels)
  * - IVML24 (large, 24 channels)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_pci.c linux-2.4.21-rc3/arch/ppc/platforms/lopec_pci.c
--- linux-2.4.20/arch/ppc/platforms/lopec_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/lopec_pci.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,108 @@
+/*
+ * arch/ppc/platforms/lopec_pci.c
+ * 
+ * PCI setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com (or, alternately, source@mvista.com)
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/machdep.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/mpc10x.h>
+
+static inline int __init
+lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	int irq;
+	static char pci_irq_table[][4] = {
+		{16, 0, 0, 0}, /* ID 11 - Winbond */
+		{22, 0, 0, 0}, /* ID 12 - SCSI */
+		{0, 0, 0, 0}, /* ID 13 - nothing */
+		{17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
+		{27, 0, 0, 0}, /* ID 15 - USB */
+		{23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
+		{24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
+		{25, 0, 0, 0}, /* ID 18 - PCI slot */
+		{0, 0, 0, 0}, /* ID 19 - nothing */
+		{0, 0, 0, 0}, /* ID 20 - nothing */
+		{0, 0, 0, 0}, /* ID 21 - nothing */
+		{0, 0, 0, 0}, /* ID 22 - nothing */
+		{0, 0, 0, 0}, /* ID 23 - nothing */
+		{0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
+		{0, 0, 0, 0}, /* ID 25 - nothing */
+		{0, 0, 0, 0}  /* ID 26 - PMC Slot 2b */
+	};
+	const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
+
+	irq = PCI_IRQ_TABLE_LOOKUP;
+	if (!irq)
+		return 0;
+
+	return irq;
+}
+
+void __init
+lopec_setup_winbond_83553(struct pci_controller *hose)
+{
+	int devfn;
+
+	devfn = PCI_DEVFN(11,0);
+
+	/* IDE interrupt routing (primary 14, secondary 15) */
+	early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
+	/* PCI interrupt routing */
+	early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
+
+	/* ISA-PCI address decoder */
+	early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
+
+	/* RTC, kb, not used in PPC */
+	early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
+	early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
+	devfn = PCI_DEVFN(11, 1);
+	early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
+	early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
+}
+
+void __init
+lopec_find_bridges(void)
+{
+	struct pci_controller *hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	if (mpc10x_bridge_init(hose,
+			       MPC10X_MEM_MAP_B,
+			       MPC10X_MEM_MAP_B,
+			       MPC10X_MAPB_EUMB_BASE) == 0) {
+
+		hose->mem_resources[0].end = 0xffffffff;
+		lopec_setup_winbond_83553(hose);
+		hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+		ppc_md.pci_swizzle = common_swizzle;
+		ppc_md.pci_map_irq = lopec_map_irq;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_serial.h linux-2.4.21-rc3/arch/ppc/platforms/lopec_serial.h
--- linux-2.4.20/arch/ppc/platforms/lopec_serial.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/lopec_serial.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,45 @@
+/*
+ * include/asm-ppc/lopec_serial.h
+ *
+ * Definitions for Motorola LoPEC board.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com (or, alternately, source@mvista.com)
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#ifndef __PLATFORMS_LOPEC_SERIAL_H__
+#define __PLATFORMS_LOPEC_SERIAL_H__
+
+#define RS_TABLE_SIZE	3
+
+#define BASE_BAUD	(1843200 / 16)
+#define UART0_INT	29
+#define UART1_INT	20
+#define UART2_INT	21
+
+#define UART0_PORT	0xFFE10000
+#define UART1_PORT	0xFFE11000
+#define UART2_PORT	0xFFE12000
+#define UART0_IO_BASE	(u8 *) UART0_PORT
+#define UART1_IO_BASE	(u8 *) UART1_PORT
+#define UART2_IO_BASE	(u8 *) UART2_PORT
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, UART##num##_PORT, UART##num##_INT,	\
+		(ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST),		\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS 	\
+		STD_UART_OP(0)	\
+		STD_UART_OP(1)	\
+		STD_UART_OP(2)
+
+#endif /* __PLATFORMS_LOPEC_SERIAL_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_setup.c linux-2.4.21-rc3/arch/ppc/platforms/lopec_setup.c
--- linux-2.4.20/arch/ppc/platforms/lopec_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/lopec_setup.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,449 @@
+/*
+ * arch/ppc/platforms/lopec_setup.c
+ * 
+ * Setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/pci-bridge.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/keyboard.h>
+#include <asm/prep_nvram.h>
+#include <asm/serial.h>
+  
+extern char saved_command_line[];
+extern void lopec_find_bridges(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
+/*
+ * Define all of the IRQ senses and polarities.  Taken from the
+ * LoPEC Programmer's Reference Guide */
+static u_char lopec_openpic_initsenses[17] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 6 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 7 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 8 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 9 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 10 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 11 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 12 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 13 */
+	(IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),	/* IRQ 14 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE)	/* IRQ 15 */
+};
+
+static int
+lopec_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "machine\t\t: Motorola LoPEC\n");
+	return 0;
+}
+
+static u32
+lopec_irq_cannonicalize(u32 irq)
+{
+	if (irq == 2)
+		return 9;
+	else
+		return irq;
+}
+
+static void
+lopec_restart(char *cmd)
+{
+#define LOPEC_SYSSTAT1 0xffe00000
+	/* force a hard reset, if possible */
+	unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1);
+	reg |= 0x80;
+	*((unsigned char *) LOPEC_SYSSTAT1) = reg;
+
+	__cli();
+	while(1);
+#undef LOPEC_SYSSTAT1
+}
+
+static void
+lopec_halt(void)
+{
+	__cli();
+	while(1);
+}
+
+static void
+lopec_power_off(void)
+{
+	lopec_halt();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+int lopec_ide_ports_known = 0;
+static ide_ioreg_t lopec_ide_regbase[MAX_HWIFS];
+static ide_ioreg_t lopec_ide_ctl_regbase[MAX_HWIFS];
+static ide_ioreg_t lopec_idedma_regbase;
+
+static void
+lopec_ide_probe(void)
+{
+	struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+					      PCI_DEVICE_ID_WINBOND_82C105,
+					      NULL);
+	lopec_ide_ports_known = 1;
+
+	if (dev) {
+		lopec_ide_regbase[0] = dev->resource[0].start;
+		lopec_ide_regbase[1] = dev->resource[2].start;
+		lopec_ide_ctl_regbase[0] = dev->resource[1].start;
+		lopec_ide_ctl_regbase[1] = dev->resource[3].start;
+		lopec_idedma_regbase = dev->resource[4].start;
+	}
+}
+
+static int
+lopec_ide_default_irq(ide_ioreg_t base)
+{
+	if (lopec_ide_ports_known == 0)
+		lopec_ide_probe();
+
+	if (base == lopec_ide_regbase[0])
+		return 14;
+	else if (base == lopec_ide_regbase[1])
+		return 15;
+	else
+		return 0;
+}
+
+static ide_ioreg_t
+lopec_ide_default_io_base(int index)
+{
+	if (lopec_ide_ports_known == 0)
+		lopec_ide_probe();
+	return lopec_ide_regbase[index];
+}
+
+static void __init
+lopec_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data,
+			  ide_ioreg_t ctl, int *irq)
+{
+	ide_ioreg_t reg = data;
+	uint alt_status_base;
+	int i;
+
+	for(i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw->io_ports[i] = reg++;
+
+	if (data == lopec_ide_regbase[0]) {
+		alt_status_base = lopec_ide_ctl_regbase[0] + 2;
+		hw->irq = 14;
+	}
+	else if (data == lopec_ide_regbase[1]) {
+		alt_status_base = lopec_ide_ctl_regbase[1] + 2;
+		hw->irq = 15;
+	}
+	else {
+		alt_status_base = 0;
+		hw->irq = 0;
+	}
+
+	if (ctl)
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+	else
+		hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base;
+
+	if (irq != NULL)
+		*irq = hw->irq;
+
+}
+#endif /* BLK_DEV_IDE */
+
+static void __init
+lopec_init_IRQ(void)
+{
+	int i;
+
+	OpenPIC_InitSenses = lopec_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses);
+
+	/*
+	 * We need to tell openpic_set_sources where things actually are.
+	 * mpc10x_common will setup OpenPIC_Addr at ioremap(EUMB phys base +
+	 * EPIC offset (0x40000));  The EPIC IRQ Register Address Map -
+	 * Interrupt Source Configuration Registers gives these numbers
+	 * as offsets starting at 0x50200, we need to adjust occordinly.
+	 */
+	/* Map serial interrupts 0-15 */
+	openpic_set_sources(0, 16, OpenPIC_Addr + 0x10200);
+	/* Skip reserved space and map i2c and DMA Ch[01] */
+	openpic_set_sources(16, 3, OpenPIC_Addr + 0x11020);
+	/* Skip reserved space and map Message Unit Interrupt (I2O) */
+	openpic_set_sources(19, 1, OpenPIC_Addr + 0x110C0);
+
+	openpic_init(NUM_8259_INTERRUPTS);
+	/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+			&i8259_irq);
+
+	/* Map i8259 interrupts */
+	for(i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_init(0);
+}
+
+static void __init
+lopec_init2(void)
+{
+	outb(0x00, 0x4d0);
+	outb(0xc0, 0x4d1);
+
+	request_region(0x00, 0x20, "dma1");
+	request_region(0x20, 0x20, "pic1");
+	request_region(0x40, 0x20, "timer");
+	request_region(0x80, 0x10, "dma page reg");
+	request_region(0xa0, 0x20, "pic2");
+	request_region(0xc0, 0x20, "dma2");
+}
+
+static void __init
+lopec_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO);
+}
+
+static void __init
+lopec_set_bat(void)
+{
+	unsigned long batu, batl;
+
+	__asm__ __volatile__(
+		"lis %0,0xf800\n \
+                 ori %1,%0,0x002a\n \
+                 ori %0,%0,0x0ffe\n \
+                 mtspr 0x21e,%0\n \
+                 mtspr 0x21f,%1\n \
+                 isync\n \
+                 sync "
+		: "=r" (batu), "=r" (batl));
+}
+
+static unsigned long __init
+lopec_find_end_of_memory(void)
+{
+	return boot_mem_size;
+}
+
+TODC_ALLOC();
+
+#ifdef CONFIG_SERIAL
+static void __init
+lopec_early_serial_map(void)
+{
+	struct serial_struct serial_req;
+
+	memset(&serial_req, 0, sizeof(serial_req));
+
+	/* Setup ioremapped serial port access */
+	serial_req.line = 0;
+	serial_req.baud_base = BASE_BAUD;
+	serial_req.irq = UART0_INT;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = ioremap(UART0_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = UART1_INT; 
+	serial_req.iomem_base = ioremap(UART1_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+
+	serial_req.line = 2;
+	serial_req.port = 2;
+	serial_req.irq = UART2_INT; 
+	serial_req.iomem_base = ioremap(UART2_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(2, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 2 failed\n");
+}
+#endif
+
+static void __init
+lopec_setup_arch(void)
+{
+
+	TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+		  ioremap(0xffe80000, 0x8000), 8);
+
+	loops_per_jiffy = 100000000/HZ;
+
+	lopec_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#elif defined(CONFIG_ROOT_NFS)
+        	ROOT_DEV = to_kdev_t(0x00ff);
+#elif defined(CONFIG_BLK_DEV_IDE)
+	        ROOT_DEV = to_kdev_t(0x0301);
+#else
+        	ROOT_DEV = to_kdev_t(0x0801);
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_SERIAL
+	lopec_early_serial_map();
+#endif
+
+#ifdef CONFIG_PPCBUG_NVRAM
+	/* Read in NVRAM data */ 
+	init_prep_nvram();
+
+	/* if no bootargs, look in NVRAM */
+	if ( cmd_line[0] == '\0' ) {
+		char *bootargs;
+		 bootargs = prep_nvram_get_var("bootargs");
+		 if (bootargs != NULL) {
+			 strcpy(cmd_line, bootargs);
+			 /* again.. */
+			 strcpy(saved_command_line, cmd_line);
+		}
+	}
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+	lopec_set_bat();
+
+	isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+	isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+	pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch = lopec_setup_arch;
+	ppc_md.show_cpuinfo = lopec_show_cpuinfo;
+	ppc_md.irq_cannonicalize = lopec_irq_cannonicalize;
+	ppc_md.init_IRQ = lopec_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+	ppc_md.init = lopec_init2;
+
+	ppc_md.restart = lopec_restart;
+	ppc_md.power_off = lopec_power_off;
+	ppc_md.halt = lopec_halt;
+
+	ppc_md.find_end_of_memory = lopec_find_end_of_memory;
+	ppc_md.setup_io_mappings = lopec_map_io;
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_VT */
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = todc_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_ID_MODULE)
+	ppc_ide_md.default_irq = lopec_ide_default_irq;
+	ppc_ide_md.default_io_base = lopec_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
+#endif
+#ifdef CONFIG_SERIAL
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif
+	ppc_md.early_serial_map = lopec_early_serial_map;
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/mbx.h linux-2.4.21-rc3/arch/ppc/platforms/mbx.h
--- linux-2.4.20/arch/ppc/platforms/mbx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/mbx.h	2003-05-22 22:06:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
- */
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola MBX boards.  This was originally created for the
  * MBX860, and probably needs revisions for other boards (like the 821).
@@ -92,7 +89,11 @@
 
 /* The MBX uses the 8259.
 */
+#ifdef CONFIG_PCI
 #define NR_8259_INTS	16
+#else
+#define NR_8259_INTS	0
+#endif
 
 #endif
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak.h linux-2.4.21-rc3/arch/ppc/platforms/oak.h
--- linux-2.4.20/arch/ppc/platforms/oak.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/oak.h	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak_setup.c linux-2.4.21-rc3/arch/ppc/platforms/oak_setup.c
--- linux-2.4.20/arch/ppc/platforms/oak_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/oak_setup.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak_setup.h linux-2.4.21-rc3/arch/ppc/platforms/oak_setup.h
--- linux-2.4.20/arch/ppc/platforms/oak_setup.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/oak_setup.h	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4.h linux-2.4.21-rc3/arch/ppc/platforms/pal4.h
--- linux-2.4.20/arch/ppc/platforms/pal4.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pal4.h	2003-05-22 22:06:51.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * 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.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifndef __PPC_PLATFORMS_PAL4_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_pci.c linux-2.4.21-rc3/arch/ppc/platforms/pal4_pci.c
--- linux-2.4.20/arch/ppc/platforms/pal4_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pal4_pci.c	2003-05-22 22:06:40.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox 
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * 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.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_serial.h linux-2.4.21-rc3/arch/ppc/platforms/pal4_serial.h
--- linux-2.4.20/arch/ppc/platforms/pal4_serial.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pal4_serial.h	2003-05-22 22:06:25.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * 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.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifndef __PPC_PAL4_SERIAL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_setup.c linux-2.4.21-rc3/arch/ppc/platforms/pal4_setup.c
--- linux-2.4.20/arch/ppc/platforms/pal4_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pal4_setup.c	2003-05-22 22:06:28.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * 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.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_backlight.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_backlight.c
--- linux-2.4.20/arch/ppc/platforms/pmac_backlight.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_backlight.c	2003-05-22 22:06:45.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
- */
-/*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  * Contains support for the backlight.
  * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_feature.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_feature.c
--- linux-2.4.20/arch/ppc/platforms/pmac_feature.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_feature.c	2003-05-22 22:06:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platform/pmac_feature.c
  *
  *  Copyright (C) 1996-2002 Paul Mackerras (paulus@cs.anu.edu.au)
@@ -17,6 +14,8 @@
  *   - Replace mdelay with some schedule loop if possible
  *   - Shorten some obfuscated delays on some routines (like modem
  *     power)
+ *   - Refcount some clocks (see darwin)
+ *   - Split split split...
  *
  */
 #include <linux/config.h>
@@ -79,7 +78,8 @@
 	macio_gatwick,
 	macio_paddington,
 	macio_keylargo,
-	macio_pangea
+	macio_pangea,
+	macio_intrepid,
 };
 
 static const char* macio_names[] __pmacdata = 
@@ -92,7 +92,8 @@
 	"Gatwick",
 	"Paddington",
 	"Keylargo",
-	"Pangea"
+	"Pangea",
+	"Intrepid"
 };
 
 static struct macio_chip
@@ -538,7 +539,7 @@
 	return 0;
 }
 
-static u32 save_fcr[5] __pmacdata;
+static u32 save_fcr[6] __pmacdata;
 static u32 save_mbcr __pmacdata;
 static u32 save_gpio_levels[2] __pmacdata;
 static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
@@ -814,8 +815,96 @@
 }
 
 static int __pmac
+pangea_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	/* Hack for internal USB modem */
+	if (node == NULL) {	
+		if (macio_chips[0].type != macio_pangea &&
+		    macio_chips[0].type != macio_intrepid)
+			return -ENODEV;
+		node = macio_chips[0].of_node;
+	}
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE);
+    		UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+	} else {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+    		UNLOCK(flags);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_ata100_enable(struct device_node* node, int value)
+{
+	unsigned long flags;
+	struct pci_dev *pdev = NULL;
+	u8 pbus, pid;
+
+    	if (uninorth_rev < 0x24)
+    		return -ENODEV;
+
+	LOCK(flags);
+	if (value)
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+	else
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	UNLOCK(flags);
+	udelay(20);
+
+	if (value) {
+		if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			return 0;
+		pci_enable_device(pdev);
+		pci_set_master(pdev);
+	}
+    	return 0;
+}
+
+static int __pmac
 core99_ide_enable(struct device_node* node, int param, int value)
 {
+	/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
+	 * based ata-100
+	 */
 	switch(param) {
 	    case 0:
 		return simple_feature_tweak(node, macio_unknown,
@@ -826,6 +915,8 @@
 	    case 2:
 		return simple_feature_tweak(node, macio_unknown,
 			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+	    case 3:
+	    	return core99_ata100_enable(node, value);
 	    default:
 	    	return -ENODEV;
 	}
@@ -873,7 +964,8 @@
 	struct macio_chip* macio;
 	
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 
 	LOCK(flags);
@@ -1010,40 +1102,14 @@
 static int __pmac
 core99_reset_cpu(struct device_node* node, int param, int value)
 {
-	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
-					KL_GPIO_RESET_CPU1,
-					KL_GPIO_RESET_CPU2,
-					KL_GPIO_RESET_CPU3 };
-	int reset_io;
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (param > 3 || param < 0)
-		return -ENODEV;
-
-	reset_io = reset_lines[param];
-	
-	LOCK(flags);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(reset_io);
-	udelay(1);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-	(void)MACIO_IN8(reset_io);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-rackmac_reset_cpu(struct device_node* node, int param, int value)
-{
-	int reset_io;
+	unsigned int reset_io = 0;
 	unsigned long flags;
 	struct macio_chip* macio;
 	struct device_node* np;
+	const int dflt_reset_lines[] = {	KL_GPIO_RESET_CPU0,
+						KL_GPIO_RESET_CPU1,
+						KL_GPIO_RESET_CPU2,
+						KL_GPIO_RESET_CPU3 };
 	
 	macio = &macio_chips[0];
 	if (macio->type != macio_keylargo)
@@ -1062,14 +1128,14 @@
 			break;
 		}
 	}
-	if (np == NULL)
-		return -ENODEV;
+	if (np == NULL || reset_io == 0)
+		reset_io = dflt_reset_lines[param];
 	
 	LOCK(flags);
 	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
 	(void)MACIO_IN8(reset_io);
 	udelay(1);
-	MACIO_OUT8(reset_io, 0);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE);
 	(void)MACIO_IN8(reset_io);
 	UNLOCK(flags);
 
@@ -1087,15 +1153,19 @@
 	u32 reg;
 	
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
-	
+
+	/* XXX Fix handling of 3rd USB controller in Intrepid, move the
+	 * port connect stuff (KL4_*) to the sleep code eventually
+	 */
 	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
 	if (!prop)
 		return -ENODEV;
-	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+	if (strncmp(prop, "usb0u048", 8) == 0)
 		number = 0;
-	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+	else if (strncmp(prop, "usb1u148", 8) == 0)
 		number = 2;
 	else
 		return -ENODEV;
@@ -1166,7 +1236,8 @@
 	struct macio_chip* macio;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
 		return -ENODEV;
@@ -1195,7 +1266,8 @@
 	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
 	    	return -ENODEV;
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
 		return -ENODEV;
@@ -1234,23 +1306,24 @@
 }
 
 static void __pmac
-keylargo_shutdown(struct macio_chip* macio, int restart)
+keylargo_shutdown(struct macio_chip* macio, int sleep_mode)
 {
 	u32 temp;
 
-	mdelay(1);
-	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-	(void)MACIO_IN32(KEYLARGO_FCR0);
-	mdelay(100);
+	if (sleep_mode) {
+		mdelay(1);
+		MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+		(void)MACIO_IN32(KEYLARGO_FCR0);
+		mdelay(1);
+	}
 
 	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
 				KL0_SCC_CELL_ENABLE |
 		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
 		      		KL0_IRDA_CLK19_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	
 	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
 
 	MACIO_BIC(KEYLARGO_FCR1,
 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
@@ -1261,27 +1334,33 @@
 		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
 		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
 		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
 
 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
  	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
- 	udelay(10);
+
 	temp = MACIO_IN32(KEYLARGO_FCR3);
-	if (macio->rev >= 2)
-		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
-		
+	if (macio->rev >= 2) {
+		temp |= KL3_SHUTDOWN_PLL2X;
+		if (sleep_mode)
+			temp |= KL3_SHUTDOWN_PLL_TOTAL;
+	}
+	
 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+		KL3_SHUTDOWN_PLLKW35;
+	if (sleep_mode)
+		temp |= KL3_SHUTDOWN_PLLKW12;
 	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+		| KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
 	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
 static void __pmac
-pangea_shutdown(struct macio_chip* macio, int restart)
+pangea_shutdown(struct macio_chip* macio, int sleep_mode)
 {
 	u32 temp;
 
@@ -1289,10 +1368,6 @@
 				KL0_SCC_CELL_ENABLE |
 				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
 
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
 	MACIO_BIC(KEYLARGO_FCR1,
 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
 		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
@@ -1300,18 +1375,54 @@
 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
 		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
 		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
 
 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
+ 	
 	temp = MACIO_IN32(KEYLARGO_FCR3);
 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
 		KL3_SHUTDOWN_PLLKW35;
-	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
 	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void __pmac
+intrepid_shutdown(struct macio_chip* macio, int sleep_mode)
+{
+	u32 temp;
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_USB2_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
+	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	temp |= KL3_IT_SHUTDOWN_PLL1 | KL3_IT_SHUTDOWN_PLL2 |
+		KL3_IT_SHUTDOWN_PLL3;
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
+		  KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
 static int __pmac
@@ -1321,7 +1432,8 @@
 	int i;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	
 	/* We power off the wireless slot in case it was not done
@@ -1337,7 +1449,11 @@
 	}
 
 	/* We make sure int. modem is off (in case driver lost it) */
-	core99_modem_enable(macio->of_node, 0, 0);
+	if (macio->type == macio_keylargo)
+		core99_modem_enable(macio->of_node, 0, 0);
+	else
+		pangea_modem_enable(macio->of_node, 0, 0);
+
 	/* We make sure the sound is off as well */
 	core99_sound_chip_enable(macio->of_node, 0, 0);
 	 
@@ -1354,12 +1470,15 @@
 		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
 
 	/* Save the FCRs */
-	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+	if (macio->type == macio_keylargo)
+		save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
 	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
 	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
 	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
 	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
 	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+	if (macio->type == macio_pangea || macio->type == macio_intrepid)
+		save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
 
 	/* Save state & config of DBDMA channels */
 	dbdma_save(macio, save_dbdma);
@@ -1368,9 +1487,11 @@
 	 * Turn off as much as we can
 	 */
 	if (macio->type == macio_pangea)
-		pangea_shutdown(macio, 0);
+		pangea_shutdown(macio, 1);
+	else if (macio->type == macio_intrepid)
+		intrepid_shutdown(macio, 1);
 	else if (macio->type == macio_keylargo)
-		keylargo_shutdown(macio, 0);
+		keylargo_shutdown(macio, 1);
 	
 	/* 
 	 * Put the host bridge to sleep
@@ -1400,7 +1521,8 @@
 	int i;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 
 	/*
@@ -1414,9 +1536,11 @@
 	/*
 	 * Restore KeyLargo
 	 */
-	 
-	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	if (macio->type == macio_keylargo) {
+		MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+		(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	}
 	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
 	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
 	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
@@ -1427,6 +1551,10 @@
 	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
 	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
 	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+	if (macio->type == macio_pangea || macio->type == macio_intrepid) {
+		MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
+		(void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
+	}
 
 	dbdma_restore(macio, save_dbdma);
 
@@ -1477,61 +1605,6 @@
 }
 
 static int __pmac
-pangea_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	/* Hack for internal USB modem */
-	if (node == NULL) {	
-		if (macio_chips[0].type != macio_pangea)
-			return -ENODEV;
-		node = macio_chips[0].of_node;
-	}
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE);
-    		UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-	} else {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-    		UNLOCK(flags);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-
-static int __pmac
 generic_get_mb_info(struct device_node* node, int param, int value)
 {
 	switch(param) {
@@ -1547,7 +1620,6 @@
 	return 0;
 }
 
-
 /* 
  * Table definitions
  */
@@ -1657,7 +1729,7 @@
 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
 #ifdef CONFIG_SMP
-	{ PMAC_FTR_RESET_CPU,		rackmac_reset_cpu },
+	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
 #endif /* CONFIG_SMP */
 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
@@ -1683,6 +1755,26 @@
 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
 	{ 0, NULL }
 };
+
+/* Intrepid features
+ */
+static struct feature_table_entry intrepid_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
 	
 static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
 	/* Warning: ordering is important as some models may claim
@@ -1714,11 +1806,11 @@
 	},
 	{	"AAPL,3400/2400",		"PowerBook 3400",
 		PMAC_TYPE_HOOPER,		ohare_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"AAPL,3500",			"PowerBook 3500",
 		PMAC_TYPE_KANGA,		ohare_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
 		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
@@ -1730,11 +1822,11 @@
 	},
 	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
 		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
 		PMAC_TYPE_101_PBOOK,		paddington_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"iMac,1",			"iMac (first generation)",
 		PMAC_TYPE_ORIG_IMAC,		paddington_features,
@@ -1746,15 +1838,15 @@
 	},
 	{	"PowerBook4,3",			"iBook 2 rev. 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook4,2",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook4,1",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerMac4,4",			"eMac",
 		PMAC_TYPE_EMAC,			core99_features,
@@ -1774,7 +1866,7 @@
 	},
 	{	"PowerBook2,1",			"iBook (first generation)",
 		PMAC_TYPE_ORIG_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
 		PMAC_TYPE_SAWTOOTH,		core99_features,
@@ -1798,7 +1890,7 @@
 	},
 	{	"PowerBook2,2",			"iBook FireWire",
 		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerMac5,1",			"PowerMac G4 Cube",
 		PMAC_TYPE_CUBE,			core99_features,
@@ -1814,19 +1906,23 @@
 	},
 	{	"PowerBook3,1",			"PowerBook Pismo",
 		PMAC_TYPE_PISMO,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,2",			"PowerBook Titanium",
 		PMAC_TYPE_TITANIUM,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,3",			"PowerBook Titanium II",
 		PMAC_TYPE_TITANIUM2,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,4",			"PowerBook Titanium III",
 		PMAC_TYPE_TITANIUM3,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+	},
+	{	"PowerBook3,5",			"PowerBook Titanium IV",
+		PMAC_TYPE_TITANIUM4,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"RackMac1,1",			"XServe",
 		PMAC_TYPE_RACKMAC,		rackmac_features,
@@ -1931,6 +2027,11 @@
 		pmac_mb.model_name = "Unknown Pangea-based";
 	    	pmac_mb.features = pangea_features;
 		break;
+	    case macio_intrepid:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+		pmac_mb.model_name = "Unknown Pangea-based";
+	    	pmac_mb.features = intrepid_features;
+	    	break;
 	    default:
 	    	return -ENODEV;
 	}
@@ -1977,6 +2078,12 @@
 	 * NAP mode
 	 */
 	powersave_lowspeed = 1;
+
+	/* Check for "mobile" machine */
+	if (model && (strncmp(model, "PowerBook", 9) == 0
+		   || strncmp(model, "iBook", 5) == 0))
+		pmac_mb.board_flags |= PMAC_MB_MOBILE;
+	
 	
 	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
 	return 0;
@@ -2060,6 +2167,8 @@
 		u32* did = (u32 *)get_property(node, "device-id", NULL);
 		if (*did == 0x00000025)
 			type = macio_pangea;
+		if (*did == 0x0000003e)
+			type = macio_intrepid;
 	}
 	macio_chips[i].of_node	= node;
 	macio_chips[i].type	= type;
@@ -2154,7 +2263,8 @@
 	}
 
 	if (macio_chips[0].type == macio_keylargo ||
-	    macio_chips[0].type == macio_pangea) {
+	    macio_chips[0].type == macio_pangea ||
+	    macio_chips[0].type == macio_intrepid) {
 		/* Enable GMAC for now for PCI probing. It will be disabled
 		 * later on after PCI probe
 		 */
@@ -2185,6 +2295,17 @@
 			np = np->next;
 		}
 		
+		/* Enable ATA-100 before PCI probe. */
+		np = find_devices("ata-6");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && device_is_compatible(np, "kauai-ata")) {
+				core99_ata100_enable(np, 1);
+			}
+			np = np->next;
+		}
+		
 		/* Switch airport off */
 		np = find_devices("radio");
 		while(np) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_nvram.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_nvram.c
--- linux-2.4.20/arch/ppc/platforms/pmac_nvram.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_nvram.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
- */
-/*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pci.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_pci.c
--- linux-2.4.20/arch/ppc/platforms/pmac_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_pci.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for PCI bridges found on Power Macintoshes.
  * At present the "bandit" and "chaos" bridges are supported.
  * Fortunately you access configuration space in the same
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pic.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_pic.c
--- linux-2.4.20/arch/ppc/platforms/pmac_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_pic.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
- */
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -358,26 +355,28 @@
 		printk("PowerMac using OpenPIC irq controller\n");
 		if (irqctrler->n_addrs > 0)
 		{
-			int nmi_irq = -1;
 			unsigned char senses[NR_IRQS];
-#ifdef CONFIG_XMON
-			struct device_node* pswitch;
 
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs)
-				nmi_irq = pswitch->intrs[0].line;
-#endif /* CONFIG_XMON */
 			prom_get_irq_senses(senses, 0, NR_IRQS);
 			OpenPIC_InitSenses = senses;
 			OpenPIC_NumInitSenses = NR_IRQS;
 			ppc_md.get_irq = openpic_get_irq;
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, 0, nmi_irq);
+			openpic_init(0);
 #ifdef CONFIG_XMON
-			if (nmi_irq >= 0)
-				request_irq(nmi_irq, xmon_irq, 0,
-					    "NMI - XMON", 0);
+			{
+				struct device_node* pswitch;
+				int nmi_irq;
+
+				pswitch = find_devices("programmer-switch");
+				if (pswitch && pswitch->n_intrs) {
+					nmi_irq = pswitch->intrs[0].line;
+					openpic_init_nmi_irq(nmi_irq);
+					request_irq(nmi_irq, xmon_irq, 0,
+							"NMI - XMON", 0);
+				}
+			}
 #endif	/* CONFIG_XMON */
 			return;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pic.h linux-2.4.21-rc3/arch/ppc/platforms/pmac_pic.h
--- linux-2.4.20/arch/ppc/platforms/pmac_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_pic.h	2003-05-22 22:06:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __PPC_PLATFORMS_PMAC_PIC_H
 #define __PPC_PLATFORMS_PMAC_PIC_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_setup.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_setup.c
--- linux-2.4.20/arch/ppc/platforms/pmac_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_setup.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  PowerPC version 
@@ -86,7 +83,6 @@
 extern void pmac_calibrate_decr(void);
 extern void pmac_pcibios_fixup(void);
 extern void pmac_find_bridges(void);
-extern int pmac_ide_check_base(ide_ioreg_t base);
 extern ide_ioreg_t pmac_ide_get_base(int index);
 extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
 	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
@@ -709,64 +705,6 @@
 }
 
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
-#ifndef CONFIG_BLK_DEV_IDE_PMAC
-/*
- * This is only used if we have a PCI IDE controller, not
- * for the IDE controller in the ohare/paddington/heathrow/keylargo.
- */
-static void __pmac
-pmac_ide_pci_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
 /*
  * Read in a property describing some pieces of memory.
  */
@@ -926,14 +864,9 @@
 	select_adb_keyboard();
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
         ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
         ppc_ide_md.default_io_base	= pmac_ide_get_base;
-#else /* CONFIG_BLK_DEV_IDE_PMAC */
-        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
 #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_sleep.S linux-2.4.21-rc3/arch/ppc/platforms/pmac_sleep.S
--- linux-2.4.20/arch/ppc/platforms/pmac_sleep.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_sleep.S	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains sleep low-level functions for PowerBook G3.
  *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
  *    and Paul Mackerras (paulus@samba.org).
@@ -18,8 +15,7 @@
 #include <asm/page.h>
 #include <asm/ppc_asm.h>
 #include <asm/cputable.h>
-#include <asm/ppc_asm.h>
-#include "../kernel/ppc_defs.h" // DAMMIT !
+#include <asm/cache.h>
 
 #define MAGIC	0x4c617273	/* 'Lars' */
 
@@ -40,16 +36,9 @@
 #define SL_DBAT3	0x50
 #define SL_IBAT3	0x58
 #define SL_TB		0x60
-#define SL_HID0		0x68
-#define SL_HID1		0x6c
-#define SL_MSSCR0	0x70
-#define SL_MSSSR0	0x74
-#define SL_ICTRL	0x78
-#define SL_LDSTCR	0x7c
-#define SL_LDSTDB	0x80
-#define SL_R2		0x84
-#define SL_CR		0x88
-#define SL_R12		0x8c	/* r12 to r31 */
+#define SL_R2		0x68
+#define SL_CR		0x6c
+#define SL_R12		0x70	/* r12 to r31 */
 #define SL_SIZE		(SL_R12 + 80)
 
 	.text
@@ -130,43 +119,9 @@
 	mfibatl	r4,3
 	stw	r4,SL_IBAT3+4(r1)
 
-	/* Save HID0 */
-	mfspr	r4,HID0
-	stw	r4,SL_HID0(r1)
-
-	/* Save 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000	/* 7450 */
-	cmpli	cr1,r3,0x000c	/* 7400 */
-	cmpli	cr2,r3,0x800c	/* 7410 */
-	cmpli	cr3,r3,0x8001	/* 7455 */
-	cmpli	cr4,r3,0x7000	/* 750FX */
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	mfspr	r4,SPRN_MSSCR0
-	stw	r4,SL_MSSCR0(r1)
-	mfspr	r4,SPRN_MSSSR0
-	stw	r4,SL_MSSSR0(r1)
-	/* Save 7450/7455 specific registers */
-	beq	cr1,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	mfspr	r4,SPRN_ICTRL
-	stw	r4,SL_ICTRL(r1)
-	mfspr	r4,SPRN_LDSTCR
-	stw	r4,SL_LDSTCR(r1)
-	mfspr	r4,SPRN_LDSTDB
-	stw	r4,SL_LDSTDB(r1)
-1:	
-	/* Save 750FX specific registers */
-	bne	cr4,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	
-1:
+	/* Backup various CPU config stuffs */
+	bl	__save_cpu_setup
+
 	/* The ROM can wake us up via 2 different vectors:
 	 *  - On wallstreet & lombard, we must write a magic
 	 *    value 'Lars' at address 4 and a pointer to a
@@ -201,33 +156,22 @@
 	addi r3,r3,sleep_storage@l
 	stw r5,0(r3)
 
-BEGIN_FTR_SECTION
-	DSSALL
+	/* Disable DPM during cache flush */
+	mfspr	r3, SPRN_HID0
+	rlwinm	r3,r3,0,12,10
 	sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-/*
- * Flush the L1 data cache by reading the first 128kB of RAM
- * and then flushing the same area with the dcbf instruction.
- * The L2 cache has already been disabled.
- */
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	lwz	r0,0(r4)
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
+	mtspr	SPRN_HID0,r3
 	sync
 	
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	dcbf	r0,r4
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
+	/* Turn off data relocation. */
+	mfmsr	r3		/* Save MSR in r7 */
+	rlwinm	r3,r3,0,28,26	/* Turn off DR bit */
 	sync
+	mtmsr	r3
+	isync
+
+	/* Flush & disable L1 cache */
+	bl	__flush_disable_L1
 
 /*
  * Set the HID0 and MSR for sleep.
@@ -236,6 +180,7 @@
 	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
 	oris	r2,r2,HID0_SLEEP@h
 	sync
+	isync
 	mtspr	HID0,r2
 	sync
 
@@ -296,16 +241,11 @@
  */
 	
 grackle_wake_up:
-	/* Enable and then Flash inval the instruction & data cache */
-	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
-	sync
-	isync
-	mtspr	HID0,r3
-	xori	r3,r3, HID0_ICFI|HID0_DCI
-	mtspr	HID0,r3
-	sync
-	
+	/* Invalidate & enable L1 cache, we don't care about
+	 * whatever the ROM may have tried to write to memory
+	 */
+	bl	__inval_enable_L1
+
 	/* Restore the kernel's segment registers before
 	 * we do any r1 memory access as we are not sure they
 	 * are in a sane state above the first 256Mb region
@@ -318,79 +258,14 @@
 	addi	r3,r3,0x111	/* increment VSID */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-	
-	/* Restore the remaining bits of the HID0 register. */
-	subi	r1,r1,SL_PC
-	lwz	r3,SL_HID0(r1)
-	sync
-	isync
-	mtspr	HID0,r3
 	sync
 	isync
+	
+	subi	r1,r1,SL_PC
+
+	/* Restore various CPU config stuffs */
+	bl	__restore_cpu_setup
 
-	/* Restore 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000	/* 7450 */
-	cmpli	cr1,r3,0x000c	/* 7400 */
-	cmpli	cr2,r3,0x800c	/* 7410 */
-	cmpli	cr3,r3,0x8001	/* 7455 */
-	cmpli	cr4,r3,0x7000	/* 750FX */
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	lwz	r4,SL_MSSCR0(r1)
-	sync
-	mtspr	SPRN_MSSCR0,r4
-	sync
-	isync
-	lwz	r4,SL_MSSSR0(r1)
-	sync
-	mtspr	SPRN_MSSSR0,r4
-	sync
-	isync
-	bne	cr2,1f
-	li	r4,0
-	mtspr	SPRN_L2CR2,r4
-	/* Restore 7450/7455 specific registers */
-	beq	cr1,1f
-	lwz	r4,SL_HID1(r1)
-	sync
-	mtspr	HID1,r4
-	isync
-	sync
-	lwz	r4,SPRN_ICTRL(r1)
-	sync
-	mtspr	SPRN_ICTRL,r4
-	isync
-	sync
-	lwz	r4,SPRN_LDSTCR(r1)
-	sync
-	mtspr	SPRN_LDSTCR,r4
-	isync
-	sync
-	lwz	r4,SL_LDSTDB(r1)
-	sync
-	mtspr	SPRN_LDSTDB,r4
-	isync
-	sync
-1:	
-	/* Restore 750FX specific registers */
-	bne	cr4,1f
-		/* Read PLL config & switch to PLL 0 */
-	lwz	r4,SL_HID1(r1)
-	rlwinm  r5,r4,0,16,14
-	mtspr	SPRN_HID1,r5
-		/* Wait for PLL to stabilize */
-	mftbl	r5
-2:	mftbl	r6
-	sub	r6,r6,r5
-	cmpli	cr0,r6,10000
-	ble	2b
-		/* Setup final PLL */
-	mtspr	SPRN_HID1,r4
-1:
 	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
 	lwz	r4,SL_SDR1(r1)
 	mtsdr1	r4
@@ -436,6 +311,26 @@
 	lwz	r4,SL_IBAT3+4(r1)
 	mtibatl	3,r4
 
+BEGIN_FTR_SECTION
+	li	r4,0
+	mtspr	SPRN_DBAT4U,r4
+	mtspr	SPRN_DBAT4L,r4
+	mtspr	SPRN_DBAT5U,r4
+	mtspr	SPRN_DBAT5L,r4
+	mtspr	SPRN_DBAT6U,r4
+	mtspr	SPRN_DBAT6L,r4
+	mtspr	SPRN_DBAT7U,r4
+	mtspr	SPRN_DBAT7L,r4
+	mtspr	SPRN_IBAT4U,r4
+	mtspr	SPRN_IBAT4L,r4
+	mtspr	SPRN_IBAT5U,r4
+	mtspr	SPRN_IBAT5L,r4
+	mtspr	SPRN_IBAT6U,r4
+	mtspr	SPRN_IBAT6L,r4
+	mtspr	SPRN_IBAT7U,r4
+	mtspr	SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
 	/* Flush all TLBs */
 	lis	r4,0x1000
 1:	addic.	r4,r4,-0x1000
@@ -480,6 +375,8 @@
 #endif /* defined(CONFIG_PMAC_PBOOK) */
 
 	.data
-	.globl sleep_storage
+	.balign	L1_CACHE_LINE_SIZE
 sleep_storage:
 	.long 0
+	.balign	L1_CACHE_LINE_SIZE, 0
+	.text
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_smp.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_smp.c
--- linux-2.4.20/arch/ppc/platforms/pmac_smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_smp.c	2003-05-22 22:06:47.000000000 +0000
@@ -1,11 +1,14 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * SMP support for power macintosh.
  *
  * We support both the old "powersurge" SMP architecture
  * and the current Core99 (G4 PowerMac) machines.
+ * 
+ * Note that we don't support the very first rev. of
+ * Apple/DayStar 2 CPUs board, the one with the funky
+ * watchdog. Hopefully, none of these should be there except
+ * maybe internally to Apple. I should probably still add some
+ * code to detect this card though and disable SMP. --BenH.
  *
  * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
  * and Ben Herrenschmidt <benh@kernel.crashing.org>.
@@ -96,15 +99,16 @@
 static volatile u8 *psurge_sec_intr;
 static volatile u32 *psurge_start;
 
-/* what sort of powersurge board we have */
-static int psurge_type;
-
 /* values for psurge_type */
+#define PSURGE_NONE		-1
 #define PSURGE_DUAL		0
 #define PSURGE_QUAD_OKEE	1
 #define PSURGE_QUAD_COTTON	2
 #define PSURGE_QUAD_ICEGRASS	3
 
+/* what sort of powersurge board we have */
+static int psurge_type = PSURGE_NONE;
+
 volatile static long int core99_l2_cache;
 volatile static long int core99_l3_cache;
 
@@ -140,113 +144,13 @@
 	}
 }
 
-/* Some CPU registers have to be saved from the first CPU and
- * applied to others. Note that we override what is setup by
- * the cputable intentionally.
- */
-
-#define	reg_hid0	0
-#define	reg_hid1	1
-#define	reg_msscr0	2
-#define	reg_msssr0	3
-#define	reg_ictrl	4
-#define	reg_ldstcr	5
-#define	reg_ldstdb	6
-#define	reg_count	7
-
-#define stringify __stringify
-
-static unsigned long cpu_regs[reg_count];
-
-static void __pmac
-cpu_setup_grab(void)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Read cache setting of CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
-		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
-		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
-		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
-		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
-		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
-	}
-	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
-}
-
-static void __pmac
-cpu_setup_apply(int cpu_nr)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Apply cache setting from CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID0)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
-			"isync;sync\n"
-//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
-//			"sync\n"
-//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
-//			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));			
-	}
-	/* 7410 only */
-	if (pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"li	%0, 0\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp));		
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID1)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));		
-	}
-}
-
 /*
  * Set and clear IPIs for powersurge.
  */
 static inline void psurge_set_ipi(int cpu)
 {
+	if (psurge_type == PSURGE_NONE)
+		return;
 	if (cpu == 0)
 		in_be32(psurge_pri_intr);
 	else if (psurge_type == PSURGE_DUAL)
@@ -258,10 +162,14 @@
 static inline void psurge_clr_ipi(int cpu)
 {
 	if (cpu > 0) {
-		if (psurge_type == PSURGE_DUAL)
+		switch(psurge_type) {
+		case PSURGE_DUAL:
 			out_8(psurge_sec_intr, ~0);
-		else
+		case PSURGE_NONE:
+			break;
+		default:
 			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+		}
 	}
 }
 
@@ -413,6 +321,7 @@
 		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
 			/* not a dual-cpu card */
 			iounmap((void *) hhead_base);
+			psurge_type = PSURGE_NONE;
 			return 1;
 		}
 		ncpus = 2;
@@ -499,15 +408,19 @@
 {
 
 	if (cpu_nr == 0) {
+		/* If we failed to start the second CPU, we should still
+		 * send it an IPI to start the timebase & DEC or we might
+		 * have them stuck.
+		 */
 		if (smp_num_cpus < 2)
-			return;
+			goto sync_tb;
 		/* reset the entry point so if we get another intr we won't
 		 * try to startup again */
 		out_be32(psurge_start, 0x100);
-		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
+		if (request_irq(30, psurge_primary_intr, SA_INTERRUPT, "primary IPI", 0))
 			printk(KERN_ERR "Couldn't get primary IPI interrupt");
 	}
-
+sync_tb:
 	if (psurge_type == PSURGE_DUAL)
 		psurge_dual_sync_tb(cpu_nr);
 }
@@ -529,8 +442,11 @@
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
 			smp_hw_index[i] = i;
+#ifdef CONFIG_6xx	/* XXX */
 		powersave_nap = 0;
-		cpu_setup_grab();
+#endif
+		/* Read cache setting of CPU 0 */
+		core99_init_caches();
 	}
 
 	return ncpus;
@@ -594,9 +510,12 @@
 static void __init
 smp_core99_setup_cpu(int cpu_nr)
 {
-	/* Setup some registers */
+
+	/* Setup some critical registers
+	 * and apply cache setting from CPU 0
+	 */
 	if (cpu_nr != 0)
-		cpu_setup_apply(cpu_nr);
+		core99_init_caches();
 	
 	/* Setup openpic */
 	do_openpic_setup_cpu();
@@ -608,16 +527,16 @@
 
 /* PowerSurge-style Macs */
 struct smp_ops_t psurge_smp_ops __pmacdata = {
-	smp_psurge_message_pass,
-	smp_psurge_probe,
-	smp_psurge_kick_cpu,
-	smp_psurge_setup_cpu,
+	.message_pass	= smp_psurge_message_pass,
+	.probe		= smp_psurge_probe,
+	.kick_cpu	= smp_psurge_kick_cpu,
+	.setup_cpu	= smp_psurge_setup_cpu,
 };
 
 /* Core99 Macs (dual G4s) */
 struct smp_ops_t core99_smp_ops __pmacdata = {
-	smp_openpic_message_pass,
-	smp_core99_probe,
-	smp_core99_kick_cpu,
-	smp_core99_setup_cpu,
+	.message_pass	= smp_openpic_message_pass,
+	.probe		= smp_core99_probe,
+	.kick_cpu	= smp_core99_kick_cpu,
+	.setup_cpu	= smp_core99_setup_cpu,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_time.c linux-2.4.21-rc3/arch/ppc/platforms/pmac_time.c
--- linux-2.4.20/arch/ppc/platforms/pmac_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/pmac_time.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for periodic interrupts (100 per second) and for getting
  * the current time from the RTC on Power Macintoshes.
  *
@@ -206,7 +203,7 @@
 	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
 	       tb_ticks_per_jiffy, dstart - dend);
 
-	iounmap(via);
+	iounmap((void *)via);
 	
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_pci.c linux-2.4.21-rc3/arch/ppc/platforms/prep_pci.c
--- linux-2.4.20/arch/ppc/platforms/prep_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/prep_pci.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
- */
-/*
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -29,6 +26,8 @@
 
 #define MAX_DEVNR 22
 
+extern void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
 static unsigned char *Motherboard_map;
@@ -665,22 +664,22 @@
 #define	MPIC_HAWK_ID		0x48030000
 #define	MOT_PROC2_BIT		0x800
 
-static u_char mvme2600_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
+static u_char prep_openpic_initsenses[] __initdata = {
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+    (IRQ_SENSE_EDGE  | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCN_ECC_ERR */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
 };
 
 #define MOT_RAVEN_PRESENT	0x1
@@ -737,8 +736,8 @@
 	/* Map the Raven MPIC registers to virtual memory. */
 	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
 
-	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
 
 	ppc_md.get_irq = openpic_get_irq;
 	
@@ -806,29 +805,51 @@
 void __init
 ibm_prep_init(void)
 {
-	u32 addr;
 #ifdef CONFIG_PREP_RESIDUAL
+	u32 addr, real_addr, len;
 	PPC_DEVICE *mpic;
-#endif
-
-	if (inb(0x0852) == 0xd5) {
-		/* This is for the 43p-140 */
-		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
-					PCI_BASE_ADDRESS_0, &addr);
-		if (addr != 0xffffffff
-		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
-		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
-			addr += PREP_ISA_MEM_BASE;
-			OpenPIC_Addr = ioremap(addr, 0x40000);
-			ppc_md.get_irq = openpic_get_irq;
-		}
-	}
+	PnP_TAG_PACKET *pkt;
 
-#ifdef CONFIG_PREP_RESIDUAL
+	/* Use the PReP residual data to determine if an OpenPIC is
+	 * present.  If so, get the large vendor packet which will
+	 * tell us the base address and length in memory.
+	 * If we are successful, ioremap the memory area and set
+	 * OpenPIC_Addr (this indicates that the OpenPIC was found).
+	 */
 	mpic = residual_find_device(-1, NULL, SystemPeripheral,
-				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL)
-		printk("mpic = %p\n", mpic);
+			    ProgrammableInterruptController, MPIC, 0);
+	if (!mpic)
+		return;
+
+	pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+			mpic->AllocatedOffset, 9, 0);
+
+	if (!pkt)
+		return;
+
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+	if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32)))
+		return; /* not a 32-bit memory address */
+
+	real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
+	if (real_addr == 0xffffffff)
+		return;
+
+	/* Adjust address to be as seen by CPU */
+	addr = real_addr + PREP_ISA_MEM_BASE;
+
+	len = ld_le32((unsigned int *) (p.PPCData + 12));
+	if (!len)
+		return;
+#undef p
+	OpenPIC_Addr = ioremap(addr, len);
+	ppc_md.get_irq = openpic_get_irq;
+
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+
+	printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
+	       "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
 #endif
 }
 
@@ -849,6 +870,47 @@
 }
 
 void __init
+prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
+	Motherboard_map = ibm6015_pci_IRQ_map;
+	Motherboard_routes = ibm6015_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM Thinkpad 850/860";
+	Motherboard_map = Nobis_pci_IRQ_map;
+	Motherboard_routes = Nobis_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 7248, PowerSeries 830/850 (Carolina)";
+	Motherboard_map = ibm8xx_pci_IRQ_map;
+	Motherboard_routes = ibm8xx_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
+}
+
+void __init
+prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 43P-140 (Tiger1)";
+	Motherboard_map = ibm43p_pci_IRQ_map;
+	Motherboard_routes = ibm43p_pci_IRQ_routes;
+	Motherboard_non0 = ibm43p_pci_map_non0;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
 prep_route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
@@ -917,52 +979,12 @@
 			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
 		}
 	} else if ( _prep_type == _PREP_IBM ) {
-		unsigned char planar_id = inb(0x0852);
 		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
 
-		printk("IBM ID: %08x\n", planar_id);
-		switch(planar_id) {
-		case 0xff:
-			Motherboard_map_name = "IBM Thinkpad 850/860";
-			Motherboard_map = Nobis_pci_IRQ_map;
-			Motherboard_routes = Nobis_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xfc:
-			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
-			Motherboard_map = ibm6015_pci_IRQ_map;
-			Motherboard_routes = ibm6015_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xd5:
-			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
-			Motherboard_map = ibm43p_pci_IRQ_map;
-			Motherboard_routes = ibm43p_pci_IRQ_routes;
-			Motherboard_non0 = ibm43p_pci_map_non0;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		default:
-			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
-		case 0xf0: /* PowerSeries 830/850 */
-		case 0xf1: /* PowerSeries 830/850 */
-		case 0xf2: /* PowerSeries 830/850 */
-		case 0xf4: /* 7248-43P */
-		case 0xf5: /* 7248-43P */
-		case 0xf6: /* 7248-43P */
-		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
-			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
-			Motherboard_map = ibm8xx_pci_IRQ_map;
-			Motherboard_routes = ibm8xx_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
-			break;
-		}
+		setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi);
 
-		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
-		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */
 	} else {
 		printk("No known machine pci routing!\n");
 		return;
@@ -1121,7 +1143,6 @@
         struct pci_dev *dev;
         extern unsigned char *Motherboard_map;
         extern unsigned char *Motherboard_routes;
-        unsigned char i;
 
 	prep_route_pci_interrupts();
 
@@ -1152,7 +1173,7 @@
 		 */
 		unsigned char d = PCI_SLOT(dev->devfn);
 		dev->irq = Motherboard_routes[Motherboard_map[d]];
-
+#if 0
 		for ( i = 0 ; i <= 5 ; i++ ) {
 			/*
 			 * Relocate PCI I/O resources if necessary so the
@@ -1175,6 +1196,7 @@
 					| 0x01000000;
 		        }
 		}
+#endif
 #if 0
 		/*
 		 * If we have residual data and if it knows about this
@@ -1235,13 +1257,14 @@
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
 	hose->io_base_phys = PREP_ISA_IO_BASE;
 	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
-	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
+	prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO);
 	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
 			   IORESOURCE_MEM);
-	
+	hose->ops = &prep_pci_ops;
+
 	printk("PReP architecture\n");
-	{
 #ifdef CONFIG_PREP_RESIDUAL	  
+	{
 		PPC_DEVICE *hostbridge;
 
 		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
@@ -1257,12 +1280,12 @@
 				setup_indirect_pci(hose, 
 					ld_le32((unsigned *) (p.PPCData)),
 					ld_le32((unsigned *) (p.PPCData+8)));
+#undef p
 			} else
 				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-		} else
-#endif /* CONFIG_PREP_RESIDUAL */
-			hose->ops = &prep_pci_ops;
+		}
 	}
+#endif /* CONFIG_PREP_RESIDUAL */
 
 	ppc_md.pcibios_fixup = prep_pcibios_fixup;
 	ppc_md.pcibios_after_init = prep_pcibios_after_init;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_setup.c linux-2.4.21-rc3/arch/ppc/platforms/prep_setup.c
--- linux-2.4.20/arch/ppc/platforms/prep_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/prep_setup.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
+ *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
@@ -59,11 +56,8 @@
 #include <asm/time.h>
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
-
-#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
-#include <../drivers/sound/sound_config.h>
-#include <../drivers/sound/dev_table.h>
-#endif
+#include <asm/pci-bridge.h>
+#include <asm/bootinfo.h>
 
 unsigned char ucSystemType;
 unsigned char ucBoardRev;
@@ -96,60 +90,335 @@
 
 int _prep_type;
 
+extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+
+
 #define cached_21	(((char *)(ppc_cached_irq_mask))[3])
 #define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
 
 /* for the mac fs */
 kdev_t boot_dev;
-/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+
+#ifdef CONFIG_SOUND_CS4232 
 long ppc_cs4232_dma, ppc_cs4232_dma2;
+#endif
 
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
-#ifdef CONFIG_SOUND_MODULE
+#ifdef CONFIG_SOUND_CS4232 
 EXPORT_SYMBOL(ppc_cs4232_dma);
 EXPORT_SYMBOL(ppc_cs4232_dma2);
 #endif
 
-static int __prep
-prep_show_cpuinfo(struct seq_file *m)
+/* useful ISA ports */
+#define PREP_SYSCTL	0x81c
+/* present in the IBM reference design; possibly identical in Mot boxes: */
+#define PREP_IBM_SIMM_ID	0x803 /* SIMM size: 32 or 8 MiB */
+#define PREP_IBM_SIMM_PRESENCE	0x804
+#define PREP_IBM_EQUIPMENT	0x80c
+#define PREP_IBM_L2INFO	0x80d
+#define PREP_IBM_PM1	0x82a /* power management register 1 */
+#define PREP_IBM_PLANAR	0x852 /* planar ID - identifies the motherboard */
+
+/* Equipment Present Register masks: */
+#define PREP_IBM_EQUIPMENT_RESERVED	0x80
+#define PREP_IBM_EQUIPMENT_SCSIFUSE	0x40
+#define PREP_IBM_EQUIPMENT_L2_COPYBACK	0x08
+#define PREP_IBM_EQUIPMENT_L2_256	0x04
+#define PREP_IBM_EQUIPMENT_CPU	0x02
+#define PREP_IBM_EQUIPMENT_L2	0x01
+
+/* planar ID values: */
+/* Sandalfoot/Sandalbow (6015/7020) */
+#define PREP_IBM_SANDALFOOT	0xfc
+/* Woodfield, Thinkpad 850/860 (6042/7249) */
+#define PREP_IBM_THINKPAD	0xff /* planar ID unimplemented */
+/* PowerSeries 830/850 (6050/6070) */
+#define PREP_IBM_CAROLINA_IDE_0	0xf0
+#define PREP_IBM_CAROLINA_IDE_1	0xf1
+#define PREP_IBM_CAROLINA_IDE_2	0xf2
+/* 7248-43P */
+#define PREP_IBM_CAROLINA_SCSI_0	0xf4
+#define PREP_IBM_CAROLINA_SCSI_1	0xf5
+#define PREP_IBM_CAROLINA_SCSI_2	0xf6
+#define PREP_IBM_CAROLINA_SCSI_3	0xf7 /* missing from Carolina Tech Spec */
+/* Tiger1 (7043-140) */
+#define PREP_IBM_TIGER1_133		0xd1
+#define PREP_IBM_TIGER1_166		0xd2
+#define PREP_IBM_TIGER1_180		0xd3
+#define PREP_IBM_TIGER1_xxx		0xd4 /* unknown, but probably exists */
+#define PREP_IBM_TIGER1_333		0xd5 /* missing from Tiger Tech Spec */
+
+/* setup_ibm_pci:
+ * 	set Motherboard_map_name, Motherboard_map, Motherboard_routes.
+ * 	return 8259 edge/level masks.
+ */
+void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
+extern char *Motherboard_map_name; /* for use in *_cpuinfo */
+
+/*
+ * As found in the PReP reference implementation.
+ * Used by Thinkpad, Sandalfoot (6015/7020), and all Motorola PReP.
+ */
+static void __init
+prep_gen_enable_l2(void)
+{
+	outb(inb(PREP_SYSCTL) | 0x3, PREP_SYSCTL);
+}
+
+/* Used by Carolina and Tiger1 */
+static void __init
+prep_carolina_enable_l2(void)
+{
+	outb(inb(PREP_SYSCTL) | 0xc0, PREP_SYSCTL);
+}
+
+/* cpuinfo code common to all IBM PReP */
+static void __prep
+prep_ibm_cpuinfo(struct seq_file *m)
 {
-	extern char *Motherboard_map_name;
-	int cachew;
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	seq_printf(m, "upgrade cpu\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_CPU) {
+		seq_printf(m, "not ");
+	}
+	seq_printf(m, "present\n");
+
+	/* print info about the SCSI fuse */
+	seq_printf(m, "scsi fuse\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_SCSIFUSE) 
+		seq_printf(m, "ok");
+	else
+		seq_printf(m, "bad");
+	seq_printf(m, "\n");
+
 #ifdef CONFIG_PREP_RESIDUAL
-	int i;
+	/* print info about SIMMs */
+	if (res->ResidualLength != 0) {
+		int i;
+		seq_printf(m, "simms\t\t: ");
+		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+			if (res->Memories[i].SIMMSize != 0)
+				seq_printf(m, "%d:%ldMiB ", i,
+					(res->Memories[i].SIMMSize > 1024) ? 
+					res->Memories[i].SIMMSize>>20 : 
+					res->Memories[i].SIMMSize);
+		}
+		seq_printf(m, "\n");
+	}
 #endif
+}
 
-	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+static int __prep
+prep_sandalfoot_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
 
-	switch ( _prep_type ) {
-	case _PREP_IBM:
-		cachew = inw(0x80c);
-		if (cachew & (1<<6))
-			seq_printf(m, "Upgrade CPU\n");
-		seq_printf(m, "L2\t\t: ");
-		if (cachew & (1<<7)) {
-			seq_printf(m, "not present\n");
-			goto no_l2;
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "L2 cache\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_L2) {
+		seq_printf(m, "not present");
+	} else {
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_256)
+			seq_printf(m, "256KiB");
+		else
+			seq_printf(m, "unknown size");
+
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_COPYBACK)
+			seq_printf(m, ", copy-back");
+		else
+			seq_printf(m, ", write-through");
+	}
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+static int __prep
+prep_thinkpad_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+	char *cpubus_speed, *pci_speed;
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		switch ((equip_reg & 0xc) >> 2) {
+			case 0x0:
+				seq_printf(m, "128KiB look-aside 2-way write-through\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB look-aside direct-mapped write-back\n");
+				break;
+			case 0x2:
+				seq_printf(m, "256KiB look-aside 2-way write-through\n");
+				break;
+			case 0x3:
+				seq_printf(m, "256KiB look-aside direct-mapped write-back\n");
+				break;
 		}
-		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
-		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
-		break;
-	case _PREP_Motorola:
-		cachew = *((unsigned char *)CACHECRBA);
-		seq_printf(m, "L2\t\t: ");
-		switch (cachew & L2CACHE_MASK) {
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	/* report bus speeds because we can */
+	if ((equip_reg & 0x80) == 0) {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "50";
+				pci_speed = "25";
+				break;
+			case 0x3:
+				cpubus_speed = "66";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	} else {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "25";
+				pci_speed = "25";
+				break;
+			case 0x2:
+				cpubus_speed = "60";
+				pci_speed = "30";
+				break;
+			case 0x3:
+				cpubus_speed = "33";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	}
+	seq_printf(m, "60x bus\t\t: %sMHz\n", cpubus_speed);
+	seq_printf(m, "pci bus\t\t: %sMHz\n", pci_speed);
+
+	return 0;
+}
+
+static int __prep
+prep_carolina_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+		/* L2 size */
+		switch ((l2_reg & 0x60) >> 5) {
+			case 0:
+				seq_printf(m, "256KiB");
+				break;
+			case 1:
+				seq_printf(m, "512KiB");
+				break;
+			default:
+				seq_printf(m, "unknown size");
+				break;
+		}
+
+		/* L2 type */
+		if ((l2_reg & 0x3) == 0)
+			seq_printf(m, ", async");
+		else if ((l2_reg & 0x3) == 1)
+			seq_printf(m, ", sync");
+		else
+			seq_printf(m, ", unknown type");
+
+		seq_printf(m, "\n");
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	return 0;
+}
+
+static int __prep
+prep_tiger1_cpuinfo(struct seq_file *m)
+{
+	unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((l2_reg & 0xf) == 0xf) {
+		seq_printf(m, "not present\n");
+	} else {
+		if (l2_reg & 0x8)
+			seq_printf(m, "async, ");
+		else
+			seq_printf(m, "sync burst, ");
+		
+		if (l2_reg & 0x4)
+			seq_printf(m, "parity, ");
+		else
+			seq_printf(m, "no parity, ");
+		
+		switch (l2_reg & 0x3) {
+			case 0x0:
+				seq_printf(m, "256KiB\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB\n");
+				break;
+			case 0x2:
+				seq_printf(m, "1MiB\n");
+				break;
+			default:
+				seq_printf(m, "unknown size\n");
+				break;
+		}
+	}
+
+	return 0;
+}
+
+
+/* Used by all Motorola PReP */
+static int __prep
+prep_mot_cpuinfo(struct seq_file *m)
+{
+	unsigned int cachew = *((unsigned char *)CACHECRBA);
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	switch (cachew & L2CACHE_MASK) {
 		case L2CACHE_512KB:
-			seq_printf(m, "512Kb");
+			seq_printf(m, "512KiB");
 			break;
 		case L2CACHE_256KB:
-			seq_printf(m, "256Kb");
+			seq_printf(m, "256KiB");
 			break;
 		case L2CACHE_1MB:
-			seq_printf(m, "1MB");
+			seq_printf(m, "1MiB");
 			break;
 		case L2CACHE_NONE:
 			seq_printf(m, "none\n");
@@ -157,32 +426,29 @@
 			break;
 		default:
 			seq_printf(m, "%x\n", cachew);
-		}
-		
-		seq_printf(m, ", parity %s",
-			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+	}
 
-		seq_printf(m, " SRAM:");
-		
-		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
-		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
-			break;
-		case 2: seq_printf(m, "asynchronous,no parity\n");
-			break;
-		case 3: seq_printf(m, "asynchronous,parity\n");
-			break;
-		default:seq_printf(m, "synchronous,pipelined,no parity\n");
-			break;
-		}
-		break;
-	default:
-		break;
+	seq_printf(m, ", parity %s",
+			(cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+	seq_printf(m, " SRAM:");
+
+	switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+		case 1: seq_printf(m, "synchronous, parity, flow-through\n");
+				break;
+		case 2: seq_printf(m, "asynchronous, no parity\n");
+				break;
+		case 3: seq_printf(m, "asynchronous, parity\n");
+				break;
+		default:seq_printf(m, "synchronous, pipelined, no parity\n");
+				break;
 	}
 
 no_l2:
 #ifdef CONFIG_PREP_RESIDUAL
+	/* print info about SIMMs */
 	if (res->ResidualLength != 0) {
-		/* print info about SIMMs */
+		int i;
 		seq_printf(m, "simms\t\t: ");
 		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
 			if (res->Memories[i].SIMMSize != 0)
@@ -198,6 +464,107 @@
 	return 0;
 }
 
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92	0x92	/* Special Port 92 */
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+	while ( 1 ) ;
+	/* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	while ( 1 ) ;
+	/* not reached */
+}
+
+/* Carrera is the power manager in the Thinkpads. Unfortunately not much is
+ * known about it, so we can't power down.
+ */
+static void __prep
+prep_carrera_poweroff(void)
+{
+	prep_halt();
+}
+
+/*
+ * On most IBM PReP's, power management is handled by a Signetics 87c750
+ * behind the Utah component on the ISA bus. To access the 750 you must write
+ * a series of nibbles to port 0x82a (decoded by the Utah). This is described
+ * somewhat in the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+	/*
+	 * byte1: 0 0 0 1 0  d  a5 a4
+	 * byte2: 0 0 0 1 a3 a2 a1 a0
+	 *
+	 * d = the bit's value, enabled or disabled
+	 * (a5 a4 a3) = the byte number, minus 20
+	 * (a2 a1 a0) = the bit number
+	 *
+	 * example: set the 5th bit of byte 21 (21.5)
+	 *     a5 a4 a3 = 001 (byte 1)
+	 *     a2 a1 a0 = 101 (bit 5)
+	 *
+	 *     byte1 = 0001 0100 (0x14)
+	 *     byte2 = 0001 1101 (0x1d)
+	 */
+	unsigned char byte1=0x10, byte2=0x10;
+
+	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+	bytenum -= 20;
+
+	byte1 |= (!!value) << 2;		/* set d */
+	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
+
+	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
+	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
+
+	outb(byte1, PREP_IBM_PM1);	/* first nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+
+	outb(byte2, PREP_IBM_PM1);	/* second nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+}
+
+static void __prep
+prep_sig750_poweroff(void)
+{
+	/* tweak the power manager found in most IBM PRePs (except Thinkpads) */
+	unsigned long flags;
+	__cli();
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+
+	utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+	while (1) ;
+	/* not reached */
+}
+
 static int __prep
 prep_show_percpuinfo(struct seq_file *m, int i)
 {
@@ -216,14 +583,120 @@
 	return 0;
 }
 
+#ifdef CONFIG_SOUND_CS4232 
+static long __init masktoint(unsigned int i)
+{
+	int t = -1;
+	while (i >> ++t)
+		;
+	return (t-1);
+}
+
+/*
+ * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
+ * to distinguish sound dma-channels from others. This is because 
+ * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
+ * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
+ */
+
+static void __init prep_init_sound(void)
+{
+	PPC_DEVICE *audiodevice = NULL;
+
+	/*
+	 * Get the needed resource informations from residual data.
+	 * 
+	 */
+#ifdef CONFIG_PREP_RESIDUAL
+	audiodevice = residual_find_device(~0, NULL, MultimediaController,
+			AudioController, -1, 0);
+	if (audiodevice != NULL) {
+		PnP_TAG_PACKET *pkt;
+
+		pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+				S5_Packet, 0);
+		if (pkt != NULL)
+			ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
+		pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+				S5_Packet, 1);
+		if (pkt != NULL)
+			ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
+	}
+#endif
+
+	/*
+	 * These are the PReP specs' defaults for the cs4231.  We use these
+	 * as fallback incase we don't have residual data.
+	 * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7 
+	 * will use the other values.
+	 */
+	if (audiodevice == NULL) {
+		switch (_prep_type) {
+		case _PREP_IBM:
+			ppc_cs4232_dma = 1;
+			ppc_cs4232_dma2 = -1;
+			break;
+		default: 
+			ppc_cs4232_dma = 6;
+			ppc_cs4232_dma2 = 7;
+		}
+	}
+
+	/*
+	 * Find a way to push these informations to the cs4232 driver
+	 * Give it out with printk, when not in cmd_line?
+	 * Append it to  cmd_line and saved_command_line?
+	 * Format is cs4232=io,irq,dma,dma2
+	 */
+}
+#endif /* CONFIG_SOUND_CS4232 */
+
+/*
+ * Fill out screen_info according to the residual data. This allows us to use
+ * at least vesafb.
+ */
+static void __init
+prep_init_vesa(void)
+{
+#if defined(CONFIG_PREP_RESIDUAL) && \
+	(defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \
+	 defined(CONFIG_FB_VESA))
+	PPC_DEVICE *vgadev;
+
+	vgadev = residual_find_device(~0, NULL, DisplayController, SVGAController,
+									-1, 0);
+	if (vgadev != NULL) {
+		PnP_TAG_PACKET *pkt;
+
+		pkt = PnP_find_large_vendor_packet(
+				(unsigned char *)&res->DevicePnPHeap[vgadev->AllocatedOffset],
+				0x04, 0); /* 0x04 = Display Tag */
+		if (pkt != NULL) {
+			unsigned char *ptr = (unsigned char *)pkt;
+
+			if (ptr[4]) {
+				/* graphics mode */
+				screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
+
+				screen_info.lfb_depth = ptr[4] * 8;
+
+				screen_info.lfb_width = swab16(*(short *)(ptr+6));
+				screen_info.lfb_height = swab16(*(short *)(ptr+8));
+				screen_info.lfb_linelength = swab16(*(short *)(ptr+10));
+
+				screen_info.lfb_base = swab32(*(long *)(ptr+12));
+				screen_info.lfb_size = swab32(*(long *)(ptr+20)) / 65536;
+			}
+		}
+	}
+#endif /* CONFIG_PREP_RESIDUAL */
+}
+
 static void __init
 prep_setup_arch(void)
 {
 	unsigned char reg;
-#if 0 /* unused?? */
-	unsigned char ucMothMemType;
-	unsigned char ucEquipPres1;
-#endif
+	int is_ide=0;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000;
@@ -238,17 +711,64 @@
 	outb(reg, SIO_CONFIG_RD);
 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
 
-	/* we should determine this according to what we find! -- Cort */
 	switch ( _prep_type )
 	{
 	case _PREP_IBM:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+		reg = inb(PREP_IBM_PLANAR);
+		printk(KERN_INFO "IBM planar ID: %08x", reg);
+		switch (reg) {
+			case PREP_IBM_SANDALFOOT:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_sandalfoot_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_sandalfoot_cpuinfo;
+				break;
+			case PREP_IBM_THINKPAD:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_thinkpad_setup_pci;
+				ppc_md.power_off = prep_carrera_poweroff;
+				ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo;
+				break;
+			default:
+				printk(" -- unknown! Assuming Carolina");
+			case PREP_IBM_CAROLINA_IDE_0:
+			case PREP_IBM_CAROLINA_IDE_1:
+			case PREP_IBM_CAROLINA_IDE_2:
+				is_ide = 1;
+			case PREP_IBM_CAROLINA_SCSI_0:
+			case PREP_IBM_CAROLINA_SCSI_1:
+			case PREP_IBM_CAROLINA_SCSI_2:
+			case PREP_IBM_CAROLINA_SCSI_3:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_carolina_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_carolina_cpuinfo;
+				break;
+			case PREP_IBM_TIGER1_133:
+			case PREP_IBM_TIGER1_166:
+			case PREP_IBM_TIGER1_180:
+			case PREP_IBM_TIGER1_xxx:
+			case PREP_IBM_TIGER1_333:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_tiger1_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_tiger1_cpuinfo;
+				break;
+		}
+		printk("\n");
+
+		/* default root device */
+		if (is_ide)
+			ROOT_DEV = to_kdev_t(0x0303); /* hda3 */
+		else
+			ROOT_DEV = to_kdev_t(0x0803); /* sda3 */
+
 		break;
 	case _PREP_Motorola:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
+		prep_gen_enable_l2();
+		ppc_md.power_off = prep_halt;
+		ppc_md.show_cpuinfo = prep_mot_cpuinfo;
+
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (initrd_start)
 			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
@@ -276,46 +796,11 @@
 		}
 	}
 
-#ifdef CONFIG_SOUND_CS4232
-	/*
-	 * setup proper values for the cs4232 driver so we don't have
-	 * to recompile for the motorola or ibm workstations sound systems.
-	 * This is a really nasty hack, but unless we change the driver
-	 * it's the only way to support both addrs from one binary.
-	 * -- Cort
-	 */
-	if ( _machine == _MACH_prep )
-	{
-		extern struct card_info snd_installed_cards[];
-		struct card_info *snd_ptr;
-
-		for ( snd_ptr = snd_installed_cards; 
-			snd_ptr < &snd_installed_cards[num_sound_cards];
-			snd_ptr++ )
-		{
-			if ( snd_ptr->card_type == SNDCARD_CS4232 )
-			{
-				if ( _prep_type == _PREP_Motorola )
-				{
-					snd_ptr->config.io_base = 0x830;
-					snd_ptr->config.irq = 10;
-					snd_ptr->config.dma = ppc_cs4232_dma = 6;
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-				if ( _prep_type == _PREP_IBM )
-				{
-					snd_ptr->config.io_base = 0x530;
-					snd_ptr->config.irq = 5;
-					snd_ptr->config.dma = ppc_cs4232_dma = 1;
-					/* this is wrong - but leave it for now */
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-			}
-		}
-	}
-#endif /* CONFIG_SOUND_CS4232 */	
+#ifdef CONFIG_SOUND_CS4232 
+	prep_init_sound();
+#endif /* CONFIG_SOUND_CS4232 */
 
-	/*print_residual_device_info();*/
+	prep_init_vesa();
 
 	switch (_prep_type) {
 	case _PREP_Motorola:
@@ -327,9 +812,8 @@
 	}
 
 #ifdef CONFIG_VGA_CONSOLE
-	/* remap the VGA memory */
+	/* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */
 	vgacon_remap_base = 0xf0000000;
-	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
 	conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
@@ -502,108 +986,6 @@
 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
 }
 
-static void __prep
-prep_restart(char *cmd)
-{
-#define PREP_SP92	0x92	/* Special Port 92 */
-	__cli(); /* no interrupts */
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(PREP_SP92) | 1 , PREP_SP92);
-
-	while ( 1 ) ;
-	/* not reached */
-#undef PREP_SP92
-}
-
-static void __prep
-prep_halt(void)
-{
-	__cli(); /* no interrupts */
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	while ( 1 ) ;
-	/* not reached */
-}
-
-/*
- * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
- * Utah component on the ISA bus. To access the 750 you must write a series of
- * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
- * the IBM Carolina Technical Specification.
- * -Hollis
- */
-static void __prep
-utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
-{
-	/*
-	 * byte1: 0 0 0 1 0  d  a5 a4
-	 * byte2: 0 0 0 1 a3 a2 a1 a0
-	 *
-	 * d = the bit's value, enabled or disabled
-	 * (a5 a4 a3) = the byte number, minus 20
-	 * (a2 a1 a0) = the bit number
-	 *
-	 * example: set the 5th bit of byte 21 (21.5)
-	 *     a5 a4 a3 = 001 (byte 1)
-	 *     a2 a1 a0 = 101 (bit 5)
-	 *
-	 *     byte1 = 0001 0100 (0x14)
-	 *     byte2 = 0001 1101 (0x1d)
-	 */
-	unsigned char byte1=0x10, byte2=0x10;
-	const unsigned int pm_reg_1=0x82a; /* ISA address */
-
-	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
-	bytenum -= 20;
-
-	byte1 |= (!!value) << 2;		/* set d */
-	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
-
-	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
-	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
-
-	outb(byte1, pm_reg_1);		/* first nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-
-	outb(byte2, pm_reg_1);		/* second nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-}
-
-static void __prep
-prep_power_off(void)
-{
-	if ( _prep_type == _PREP_IBM) {
-		/* tested on:
-		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
-		 * should work on:
-		 * 		Carolina: 6050 (PowerSeries 830)
-		 * 		7043-140 (Tiger 1)
-		 */
-		unsigned long flags;
-		__cli();
-		/* set exception prefix high - to the prom */
-		save_flags( flags );
-		restore_flags( flags|MSR_IP );
-
-		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
-
-		while ( 1 ) ;
-		/* not reached */
-	} else {
-		prep_halt();
-	}
-}
-
 static unsigned int __prep
 prep_irq_cannonicalize(u_int irq)
 {
@@ -621,12 +1003,28 @@
 prep_init_IRQ(void)
 {
 	int i;
+	unsigned int pci_viddid, pci_did;
 
-	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+	if (OpenPIC_Addr != NULL) {
+		openpic_init(NUM_8259_INTERRUPTS);
+		/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+		openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+				       i8259_irq);
+	}
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+	 /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory
+	  * controller, we poll (as they have a different int-ack address). */
+	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &pci_viddid);
+	pci_did = (pci_viddid & 0xffff0000) >> 16;
+	if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA)
+			&& ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN)
+				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK)))
+		i8259_init(0);
+	else
+		/* PCI interrupt ack address given in section 6.1.8 of the
+		 * PReP specification. */
+		i8259_init(0xbffffff0);
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -659,46 +1057,6 @@
 			return 0;
 	}
 }
-
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
-static void __init
-prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-}
 #endif
 
 #ifdef CONFIG_SMP
@@ -722,7 +1080,7 @@
 {
 	*(unsigned long *)KERNELBASE = nr;
 	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
+	printk("CPU1 released, waiting\n");
 }
 
 static void __init
@@ -741,34 +1099,12 @@
 #endif /* CONFIG_SMP */
 
 /*
- * This finds the amount of physical ram and does necessary
- * setup for prep.  This is pretty architecture specific so
- * this will likely stay separate from the pmac.
- * -- Cort
+ * What ever boots us must pass in the ammount of memory.
  */
 static unsigned long __init
 prep_find_end_of_memory(void)
 {
-	unsigned long total = 0;
-	extern unsigned int boot_mem_size;
-
-#ifdef CONFIG_PREP_RESIDUAL	
-	total = res->TotalMemory;
-#endif	
-
-	if (total == 0 && boot_mem_size != 0)
-		total = boot_mem_size;
-	else if (total == 0) {
-		/*
-		 * I need a way to probe the amount of memory if the residual
-		 * data doesn't contain it. -- Cort
-		 */
-		total = 0x02000000;
-		printk(KERN_INFO "Ramsize from residual data was 0"
-			 " -- defaulting to %ldM\n", total>>20);
-	}
-
-	return (total);
+	return boot_mem_size;
 }
 
 /*
@@ -789,8 +1125,6 @@
 #ifdef CONFIG_NVRAM
 	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
 #endif
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
 	request_region(0x80,0x10,"dma page reg");
@@ -818,14 +1152,12 @@
 
 	/* figure out what kind of prep workstation we are */
 #ifdef CONFIG_PREP_RESIDUAL	
-	if ( res->ResidualLength != 0 )
-	{
+	if ( res->ResidualLength != 0 ) {
 		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
 			_prep_type = _PREP_IBM;
 		else
 			_prep_type = _PREP_Motorola;
-	}
-	else /* assume motorola if no residual (netboot?) */
+	} else /* assume motorola if no residual (netboot?) */
 #endif
 	{
 		_prep_type = _PREP_Motorola;
@@ -833,7 +1165,7 @@
 
 	ppc_md.setup_arch     = prep_setup_arch;
 	ppc_md.show_percpuinfo = prep_show_percpuinfo;
-	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
+	ppc_md.show_cpuinfo   = NULL; /* set in prep_setup_arch() */
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
 	/* this gets changed later on if we have an OpenPIC -- Cort */
@@ -841,7 +1173,7 @@
 	ppc_md.init           = prep_init2;
 
 	ppc_md.restart        = prep_restart;
-	ppc_md.power_off      = prep_power_off;
+	ppc_md.power_off      = NULL; /* set in prep_setup_arch() */
 	ppc_md.halt           = prep_halt;
 
 	ppc_md.nvram_read_val = prep_nvram_read_val;
@@ -865,10 +1197,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = prep_ide_default_irq;
 	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
-	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
 #endif
 
 #ifdef CONFIG_VT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_time.c linux-2.4.21-rc3/arch/ppc/platforms/prep_time.c
--- linux-2.4.20/arch/ppc/platforms/prep_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/prep_time.c	2003-05-22 22:06:46.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/prep_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/proc_rtas.c linux-2.4.21-rc3/arch/ppc/platforms/proc_rtas.c
--- linux-2.4.20/arch/ppc/platforms/proc_rtas.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/proc_rtas.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
- */
-/*
  *   arch/ppc/kernel/proc_rtas.c
  *   Copyright (C) 2000 Tilmann Bitterberg
  *   (tilmann@bitterberg.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/residual.c linux-2.4.21-rc3/arch/ppc/platforms/residual.c
--- linux-2.4.20/arch/ppc/platforms/residual.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/residual.c	2003-05-22 22:06:28.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
- */
-/*
  * Code to deal with the PReP residual data.
  *
  * Written by: Cort Dougan (cort@cs.nmt.edu)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxclassic.h linux-2.4.21-rc3/arch/ppc/platforms/rpxclassic.h
--- linux-2.4.20/arch/ppc/platforms/rpxclassic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/rpxclassic.h	2003-05-22 22:06:27.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxhiox.h linux-2.4.21-rc3/arch/ppc/platforms/rpxhiox.h
--- linux-2.4.20/arch/ppc/platforms/rpxhiox.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/rpxhiox.h	2003-05-22 22:06:51.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
- */
-
-/*
  * The Embedded Planet HIOX expansion card definitions.
  * There were a few different versions of these cards, but only
  * the one that escaped real production is defined here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxlite.h linux-2.4.21-rc3/arch/ppc/platforms/rpxlite.h
--- linux-2.4.20/arch/ppc/platforms/rpxlite.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/rpxlite.h	2003-05-22 22:06:26.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Lite board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spd8xx.h linux-2.4.21-rc3/arch/ppc/platforms/spd8xx.h
--- linux-2.4.20/arch/ppc/platforms/spd8xx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/spd8xx.h	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
- */
-/*
  * Speech Design SPD8xxTS board specific definitions
  * 
  * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce.h linux-2.4.21-rc3/arch/ppc/platforms/spruce.h
--- linux-2.4.20/arch/ppc/platforms/spruce.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/spruce.h	2003-05-22 22:06:48.000000000 +0000
@@ -7,27 +7,10 @@
  *          mporter@mvista.com
  *          jpeters@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce_pci.c linux-2.4.21-rc3/arch/ppc/platforms/spruce_pci.c
--- linux-2.4.20/arch/ppc/platforms/spruce_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/spruce_pci.c	2003-05-22 22:06:26.000000000 +0000
@@ -6,27 +6,10 @@
  * Author: Johnnie Peters
  *         jpeters@mvista.com
  *
- * Copyright 2000 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2000 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce_setup.c linux-2.4.21-rc3/arch/ppc/platforms/spruce_setup.c
--- linux-2.4.20/arch/ppc/platforms/spruce_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/spruce_setup.c	2003-05-22 22:06:51.000000000 +0000
@@ -6,27 +6,10 @@
  * Authors: Johnnie Peters <jpeters@mvista.com>
  *          Matt Porter <mporter@mvista.com>
  *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- * 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.
- *
- * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -73,6 +56,9 @@
 extern unsigned char pckbd_sysrq_xlate[128];
 extern char cmd_line[];
 
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
 /*
  * CPC700 PIC interrupt programming table
  *
@@ -128,14 +114,56 @@
 	return 0;
 }
 
-TODC_ALLOC();
-
+#ifdef CONFIG_SERIAL
 static void __init
-spruce_setup_arch(void)
+spruce_early_serial_map(void)
 {
 	u32 baud_base;
 	struct serial_struct serial_req;
 
+	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))
+		baud_base = SPRUCE_BAUD_33M;
+	else
+		baud_base = SPRUCE_BAUD_30M;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.baud_base = baud_base;
+	serial_req.line = 0;
+	serial_req.port = 0;
+	serial_req.irq = 3;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = (u_char *)UART0_IO_BASE;
+	serial_req.iomem_reg_shift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 4;
+	serial_req.iomem_base = (u_char *)UART1_IO_BASE;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
 	/* Setup TODC access */
 	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
 
@@ -160,35 +188,9 @@
 	conswitchp = &dummy_con;
 #endif
 
-	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))	
-		baud_base = SPRUCE_BAUD_33M;
-	else
-		baud_base = SPRUCE_BAUD_30M;
-
-	/* Setup serial port access */
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.baud_base = baud_base;
-	serial_req.line = 0;
-	serial_req.port = 0;
-	serial_req.irq = 3;
-	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
-	serial_req.io_type = SERIAL_IO_MEM;
-	serial_req.iomem_base = UART0_IO_BASE;
-	serial_req.iomem_reg_shift = 0;
-
-	if (early_serial_setup(&serial_req) != 0) {
-		printk("Early serial init of port 0 failed\n");
-	}
-
-	/* Assume early_serial_setup() doesn't modify serial_req */
-	serial_req.line = 1;
-	serial_req.port = 1;
-	serial_req.irq = 4; 
-	serial_req.iomem_base = UART1_IO_BASE;
-
-	if (early_serial_setup(&serial_req) != 0) {
-		printk("Early serial init of port 1 failed\n");
-	}
+#ifdef CONFIG_SERIAL
+	spruce_early_serial_map();
+#endif
 
 	/* Identify the system */
 	printk("System Identification: IBM Spruce\n");
@@ -202,15 +204,12 @@
 
 	/* SRR0 has system reset vector, SRR1 has default MSR value */
 	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-	__asm__ __volatile__
-	("\n\
-	lis	3,0xfff0
-	ori	3,3,0x0100
-	mtspr	26,3
-	li	3,0
-	mtspr	27,3
-	rfi
-	");
+	asm volatile("	lis	3,0xfff0	\n\
+			ori	3,3,0x0100	\n\
+			mtspr	26,3		\n\
+			li	3,0		\n\
+			mtspr	27,3		\n\
+			rfi");
 	for(;;);
 }
 
@@ -249,10 +248,10 @@
 	__raw_writel(0x03000000, 0xff50000c);
 	eieio();
 
-	asm volatile("	lis	7,0xff88	\n
-			ori	7,7,0x8		\n
-			lswi	6,7,0x8		\n
-			mr	%0,6		\n"
+	asm volatile("	lis	7,0xff88	\n\
+			ori	7,7,0x8		\n\
+			lswi	6,7,0x8		\n\
+			mr	%0,6"
 			: "=r" (kbd_status) :: "6", "7");
 
 	__raw_writel(0x00000000, 0xff50000c);
@@ -271,9 +270,9 @@
 	__raw_writel(0x03000000, 0xff50000c);
 	eieio();
 
-	asm volatile("	lis	7,0xff88	\n
-			lswi	6,7,0x8		\n
-			mr	%0,6		\n"
+	asm volatile("	lis	7,0xff88	\n\
+			lswi	6,7,0x8		\n\
+			mr	%0,6"
 			: "=r" (kbd_data) :: "6", "7");
 
 	__raw_writel(0x00000000, 0xff50000c);
@@ -282,6 +281,26 @@
 	return (unsigned char)(kbd_data >> 24);
 }
 
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+spruce_set_bat(void)
+{
+	unsigned long	bat3u, bat3l;
+
+	asm volatile("  lis	%0,0xf800	\n\
+			ori	%1,%0,0x002a	\n\
+			ori	%0,%0,0x0ffe	\n\
+			mtspr	0x21e,%0	\n\
+			mtspr	0x21f,%1	\n\
+			isync			\n\
+			sync "
+			: "=r" (bat3u), "=r" (bat3l));
+}
+#endif
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
@@ -311,6 +330,17 @@
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
 
+#if defined(CONFIG_SERIAL) && (defined(CONFIG_SERIAL_TEXT_DEBUG) \
+		|| defined(CONFIG_KGDB))
+	spruce_set_bat();
+	spruce_early_serial_map();
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+	ppc_md.early_serial_map = spruce_early_serial_map;
+#endif
+
 #ifdef CONFIG_VT
 	/* Spruce has a PS2 style keyboard */
 	ppc_md.kbd_setkeycode = pckbd_setkeycode;
@@ -320,7 +350,7 @@
 	ppc_md.kbd_leds = pckbd_leds;
 	ppc_md.kbd_init_hw = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/tqm8xx.h linux-2.4.21-rc3/arch/ppc/platforms/tqm8xx.h
--- linux-2.4.20/arch/ppc/platforms/tqm8xx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/tqm8xx.h	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
- */
-/*
  * TQM8xx(L) board specific definitions
  * 
  * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/walnut.c linux-2.4.21-rc3/arch/ppc/platforms/walnut.c
--- linux-2.4.20/arch/ppc/platforms/walnut.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/walnut.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/walnut.h linux-2.4.21-rc3/arch/ppc/platforms/walnut.h
--- linux-2.4.20/arch/ppc/platforms/walnut.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/platforms/walnut.h	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/Makefile linux-2.4.21-rc3/arch/ppc/xmon/Makefile
--- linux-2.4.20/arch/ppc/xmon/Makefile	2001-07-02 21:34:57.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini
 #
 # Makefile for xmon
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/adb.c linux-2.4.21-rc3/arch/ppc/xmon/adb.c
--- linux-2.4.20/arch/ppc/xmon/adb.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/adb.c	2003-05-22 22:06:44.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include "nonstdio.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ansidecl.h linux-2.4.21-rc3/arch/ppc/xmon/ansidecl.h
--- linux-2.4.20/arch/ppc/xmon/ansidecl.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/ansidecl.h	2003-05-22 22:06:43.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort
- */
 /* ANSI and traditional C compatability macros
    Copyright 1991, 1992 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/nonstdio.h linux-2.4.21-rc3/arch/ppc/xmon/nonstdio.h
--- linux-2.4.20/arch/ppc/xmon/nonstdio.h	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/nonstdio.h	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.nonstdio.h 1.8 12/01/01 20:09:07 benh
- */
 typedef int	FILE;
 extern FILE *xmon_stdin, *xmon_stdout;
 #define EOF	(-1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc-dis.c linux-2.4.21-rc3/arch/ppc/xmon/ppc-dis.c
--- linux-2.4.20/arch/ppc/xmon/ppc-dis.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/ppc-dis.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-dis.c -- Disassemble PowerPC instructions
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc-opc.c linux-2.4.21-rc3/arch/ppc/xmon/ppc-opc.c
--- linux-2.4.20/arch/ppc/xmon/ppc-opc.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/ppc-opc.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-opc.c -- PowerPC opcode list
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc.h linux-2.4.21-rc3/arch/ppc/xmon/ppc.h
--- linux-2.4.20/arch/ppc/xmon/ppc.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/ppc.h	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort
- */
 /* ppc.h -- Header file for PowerPC opcode table
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/privinst.h linux-2.4.21-rc3/arch/ppc/xmon/privinst.h
--- linux-2.4.20/arch/ppc/xmon/privinst.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/privinst.h	2003-05-22 22:06:41.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/setjmp.c linux-2.4.21-rc3/arch/ppc/xmon/setjmp.c
--- linux-2.4.20/arch/ppc/xmon/setjmp.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/setjmp.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  *
  * NB this file must be compiled with -O2.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/start.c linux-2.4.21-rc3/arch/ppc/xmon/start.c
--- linux-2.4.20/arch/ppc/xmon/start.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/start.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.20 04/09/02 21:01:58 paulus
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
@@ -14,9 +11,11 @@
 #include <linux/cuda.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/sysrq.h>
 #include <asm/prom.h>
 #include <asm/bootx.h>
 #include <asm/machdep.h>
+#include <asm/errno.h>
 #include <asm/pmac_feature.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
@@ -26,11 +25,10 @@
 #endif
 
 static volatile unsigned char *sccc, *sccd;
-unsigned long TXRDY, RXRDY;
+unsigned int TXRDY, RXRDY, DLAB;
 extern void xmon_printf(const char *fmt, ...);
 static int xmon_expect(const char *str, unsigned int timeout);
 
-static int console;
 static int use_screen;
 static int via_modem;
 static int xmon_use_sccb;
@@ -48,12 +46,65 @@
 
 void buf_access(void)
 {
-	if ( _machine == _MACH_chrp )
-		sccd[3] &= ~0x80;	/* reset DLAB */
+	if (DLAB)
+		sccd[3] &= ~DLAB;	/* reset DLAB */
 }
 
 extern int adb_init(void);
 
+#ifdef CONFIG_ALL_PPC
+/*
+ * This looks in the "ranges" property for the primary PCI host bridge
+ * to find the physical address of the start of PCI/ISA I/O space.
+ * It is basically a cut-down version of pci_process_bridge_OF_ranges.
+ */
+static unsigned long chrp_find_phys_io_base(void)
+{
+	struct device_node *node;
+	unsigned int *ranges;
+	unsigned long base = CHRP_ISA_IO_BASE;
+	int rlen = 0;
+	int np;
+
+	node = find_devices("isa");
+	if (node != NULL) {
+		node = node->parent;
+		if (node == NULL || node->type == NULL
+		    || strcmp(node->type, "pci") != 0)
+			node = NULL;
+	}
+	if (node == NULL)
+		node = find_devices("pci");
+	if (node == NULL)
+		return base;
+
+	ranges = (unsigned int *) get_property(node, "ranges", &rlen);
+	np = prom_n_addr_cells(node) + 5;
+	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+		if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
+			/* I/O space starting at 0, grab the phys base */
+			base = ranges[np - 3];
+			break;
+		}
+		ranges += np;
+	}
+	return base;
+}
+#endif /* CONFIG_ALL_PPC */
+
+static void sysrq_handle_xmon(int key, struct pt_regs *regs,
+			      struct kbd_struct *kbd, struct tty_struct *tty)
+{
+	xmon(regs);
+}
+
+static struct sysrq_key_op sysrq_xmon_op = 
+{
+	handler:	sysrq_handle_xmon,
+	help_msg:	"Xmon",
+	action_msg:	"Entering xmon\n",
+};
+
 void
 xmon_map_scc(void)
 {
@@ -132,18 +183,22 @@
 		base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
 		sccc = base + (addr & ~PAGE_MASK);
 		sccd = sccc + 0x10;
-	}
-	else
-	{
-		/* should already be mapped by the kernel boot */
-		sccc = (volatile unsigned char *) (isa_io_base + 0x3fd);
-		sccd = (volatile unsigned char *) (isa_io_base + 0x3f8);
+
+	} else {
+		base = (volatile unsigned char *) isa_io_base;
+		if (_machine == _MACH_chrp)
+			base = (volatile unsigned char *)
+				ioremap(chrp_find_phys_io_base(), 0x1000);
+
+		sccc = base + 0x3fd;
+		sccd = base + 0x3f8;
 		if (xmon_use_sccb) {
 			sccc -= 0x100;
 			sccd -= 0x100;
 		}
 		TXRDY = 0x20;
 		RXRDY = 1;
+		DLAB = 0x80;
 	}
 #elif defined(CONFIG_GEMINI)
 	/* should already be mapped by the kernel boot */
@@ -151,8 +206,16 @@
 	sccd = (volatile unsigned char *) 0xffeffb08;
 	TXRDY = 0x20;
 	RXRDY = 1;
-	console = 1;
+	DLAB = 0x80;
+#elif defined(CONFIG_405GP) || defined(CONFIG_405LP) || defined(CONFIG_405EP)
+	sccc = (volatile unsigned char *)0xef600305;
+	sccd = (volatile unsigned char *)0xef600300;
+	TXRDY = 0x20;
+	RXRDY = 1;
+	DLAB = 0x80;
 #endif /* platform */
+
+	__sysrq_put_key_op('x', &sysrq_xmon_op);
 }
 
 static int scc_initialized = 0;
@@ -209,8 +272,6 @@
 			ct = 1;
 			--i;
 		} else {
-			if (console)
-				printk("%c", c);
 			ct = 0;
 		}
 		buf_access();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/start_8xx.c linux-2.4.21-rc3/arch/ppc/xmon/start_8xx.c
--- linux-2.4.20/arch/ppc/xmon/start_8xx.c	2001-10-08 18:40:13.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/start_8xx.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start_8xx.c 1.10 09/14/01 18:01:17 trini
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  * Copyright (C) 2000 Dan Malek.
  * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/subr_prf.c linux-2.4.21-rc3/arch/ppc/xmon/subr_prf.c
--- linux-2.4.20/arch/ppc/xmon/subr_prf.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/subr_prf.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.subr_prf.c 1.8 12/01/01 20:09:07 benh
- */
-/*
  * Written by Cort Dougan to replace the version originally used
  * by Paul Mackerras, which came from NetBSD and thus had copyright
  * conflicts with Linux.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/xmon.c linux-2.4.21-rc3/arch/ppc/xmon/xmon.c
--- linux-2.4.20/arch/ppc/xmon/xmon.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc/xmon/xmon.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.xmon.c 1.18 12/01/01 20:09:07 benh
- */
-/*
  * Routines providing a simple monitor for use on the PowerMac.
  *
  * Copyright (C) 1996 Paul Mackerras.
@@ -14,6 +11,12 @@
 #include <asm/string.h>
 #include <asm/prom.h>
 #include <asm/bitops.h>
+#include <asm/bootx.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+#include <asm/mmu.h>
+
 #include "nonstdio.h"
 #include "privinst.h"
 
@@ -24,6 +27,7 @@
 static unsigned long cpus_in_xmon = 0;
 static unsigned long got_xmon = 0;
 static volatile int take_xmon = -1;
+static int xmon_owner = -1;
 #endif /* CONFIG_SMP */
 
 static unsigned adrs;
@@ -189,20 +193,31 @@
 	xmon_enter();
 	excprint(excp);
 #ifdef CONFIG_SMP
-	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
-		for (;;)
-			;
-	while (test_and_set_bit(0, &got_xmon)) {
-		if (take_xmon == smp_processor_id()) {
-			take_xmon = -1;
-			break;
+	set_bit(smp_processor_id(), &cpus_in_xmon);
+	if (smp_processor_id() != xmon_owner) {
+		while (test_and_set_bit(0, &got_xmon)) {
+			if (take_xmon == smp_processor_id()) {
+				take_xmon = -1;
+				break;
+			}
 		}
+		xmon_owner = smp_processor_id();
 	}
 	/*
 	 * XXX: breakpoints are removed while any cpu is in xmon
 	 */
 #endif /* CONFIG_SMP */
 	remove_bpts();
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if( setjmp(bus_error_jmp) == 0 ) {
+		debugger_fault_handler = handle_fault;
+		sync();
+		set_backlight_enable(1);
+		set_backlight_level(BACKLIGHT_MAX);
+		sync();
+	}
+	debugger_fault_handler = 0;
+#endif	/* CONFIG_PMAC_BACKLIGHT */
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
@@ -218,6 +233,7 @@
 	xmon_regs[smp_processor_id()] = 0;
 #ifdef CONFIG_SMP
 	clear_bit(0, &got_xmon);
+	xmon_owner = -1;
 	clear_bit(smp_processor_id(), &cpus_in_xmon);
 #endif /* CONFIG_SMP */
 	set_msr(msr);		/* restore interrupt enable */
@@ -503,11 +519,13 @@
 	}
 	/* try to switch to cpu specified */
 	take_xmon = cpu;
+	xmon_owner = -1;
 	timeout = 10000000;
 	while (take_xmon >= 0) {
 		if (--timeout == 0) {
 			/* yes there's a race here */
 			take_xmon = -1;
+			xmon_owner = smp_processor_id();
 			printf("cpu %u didn't take control\n", cpu);
 			return;
 		}
@@ -516,6 +534,7 @@
 	while (test_and_set_bit(0, &got_xmon)) {
 		if (take_xmon == smp_processor_id()) {
 			take_xmon = -1;
+			xmon_owner = smp_processor_id();
 			break;
 		}
 	}
@@ -921,15 +940,22 @@
 }
 #endif
 
+#ifndef CONFIG_PPC_STD_MMU
+static void
+dump_hash_table()
+{
+	printf("This CPU doesn't have a hash table.\n");
+}
+#else
+
 #ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
 {
-	extern void *Hash;
-	extern unsigned long Hash_size;
-	unsigned *htab = Hash;
-	unsigned hsize = Hash_size;
-	unsigned v, hmask, va, last_va;
+	void *htab = Hash;
+	unsigned long hsize = Hash_size;
+	unsigned long hmask;
+	unsigned v, va, last_va;
 	int found, last_found, i;
 	unsigned *hg, w1, last_w2, last_va0;
 
@@ -984,11 +1010,10 @@
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
 {
-	extern void *Hash;
-	extern unsigned long Hash_size;
-	unsigned *htab = Hash;
-	unsigned hsize = Hash_size;
-	unsigned v, hmask, va, last_va;
+	void *htab = Hash;
+	unsigned long hsize = Hash_size;
+	unsigned long hmask;
+	unsigned v, va, last_va;
 	int found, last_found, i;
 	unsigned *hg, w1, last_w2, last_va0;
 
@@ -1050,6 +1075,8 @@
 	int seg;
 	unsigned seg_start, seg_end;
 
+	if (Hash == NULL)
+		return;
 	hash_ctx = 0;
 	hash_start = 0;
 	hash_end = 0xfffff000;
@@ -1067,6 +1094,7 @@
 		seg_start = seg_end + 0x1000;
 	}
 }
+#endif /* CONFIG_PPC_STD_MMU */
 
 /*
  * Stuff for reading and writing memory safely
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/Makefile linux-2.4.21-rc3/arch/ppc64/boot/Makefile
--- linux-2.4.20/arch/ppc64/boot/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/boot/Makefile	2003-05-22 22:06:47.000000000 +0000
@@ -24,7 +24,7 @@
 #CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux-
 
 BOOTCC = $(CROSS32_COMPILE)gcc
-BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH)
+BOOTCFLAGS = $(HOSTCFLAGS) -fno-builtin -I$(HPATH)
 BOOTLD = $(CROSS32_COMPILE)ld
 BOOTAS = $(CROSS32_COMPILE)as
 BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS) -I$(HPATH)
@@ -40,7 +40,6 @@
 LD_ARGS = -Ttext 0x00400000 -e _start
 
 OBJS = crt0.o string.o prom.o zImage.o zlib.o imagesize.o
-#LIBS = $(TOPDIR)/lib/lib.a
 LIBS =
 
 ifeq ($(CONFIG_SMP),y)
@@ -91,7 +90,9 @@
 
 imagesize.c: $(TOPDIR)/vmlinux
 	ls -l $(TOPDIR)/vmlinux | awk '{printf "/* generated -- do not edit! */\nunsigned long vmlinux_filesize = %d;\n", $$5}' > imagesize.c
-	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' >> imagesize.c
+	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | awk '{i=$$1}END{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr(i,8)}' >> imagesize.c
+
+zImage.o: $(TOPDIR)/vmlinux
 
 vmlinux .config System.map: % : $(TOPDIR)/%
 	gzip -cvf9 $(TOPDIR)/$@ > kernel-$@.gz
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/README linux-2.4.21-rc3/arch/ppc64/boot/README
--- linux-2.4.20/arch/ppc64/boot/README	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/boot/README	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,10 @@
+
+To extract the kernel vmlinux, System.map or .config from the zImage binary:
+
+objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
+objcopy -j .kernel:System.map -O binary zImage System.map.gz
+objcopy -j .kernel:.config -O binary zImage config.gz
+
+
+	Peter
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/addRamDisk.c linux-2.4.21-rc3/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.20/arch/ppc64/boot/addRamDisk.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/boot/addRamDisk.c	2003-05-22 22:06:26.000000000 +0000
@@ -154,9 +154,8 @@
   
 	/* Process the Sysmap file to determine where _end is */
 	sysmapPages = sysmapLen / 4096;
-	for (i=0; i<sysmapPages; ++i) {
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/addSystemMap.c linux-2.4.21-rc3/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.20/arch/ppc64/boot/addSystemMap.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/boot/addSystemMap.c	2003-05-22 22:06:51.000000000 +0000
@@ -146,10 +146,8 @@
   /* Process the Sysmap file to determine the true end of the kernel */
 	sysmapPages = sysmapLen / 4096;
 	printf("System map pages to copy = %ld\n", sysmapPages);
-	for (i=0; i<sysmapPages; ++i)
-	{
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/zImage.c linux-2.4.21-rc3/arch/ppc64/boot/zImage.c
--- linux-2.4.20/arch/ppc64/boot/zImage.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/boot/zImage.c	2003-05-22 22:06:51.000000000 +0000
@@ -12,11 +12,14 @@
 #include "ppc32-types.h"
 #include "zlib.h"
 #include <linux/elf.h>
+#include <linux/version.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/bootinfo.h>
 
 void memmove(void *dst, void *im, int len);
+void *memcpy(void *dest, const void *src, size_t n);
+size_t strlen(const char *s);
 
 extern void *finddevice(const char *);
 extern int getprop(void *, const char *, void *, int);
@@ -88,6 +91,8 @@
 	kernel_entry_t kernel_entry;
 	Elf64_Ehdr *elf64;
 	Elf64_Phdr *elf64ph;
+	/* tell userland tools about uname -r */
+	unsigned char this_uts[] = "Linux version " UTS_RELEASE;
 
 	prom = (int (*)(void *)) promptr;
 	chosen_handle = finddevice("/chosen");
@@ -100,6 +105,7 @@
 		exit();
 
 	printf("zImage starting: loaded at 0x%x\n\r", (unsigned)&_start);
+	printf("%s\n\r", this_uts);
 
 #if 0
 	sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/config.in linux-2.4.21-rc3/arch/ppc64/config.in
--- linux-2.4.20/arch/ppc64/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/config.in	2003-05-22 22:06:38.000000000 +0000
@@ -38,6 +38,7 @@
 else
 bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
 tristate 'Firmware flash interface' CONFIG_RTAS_FLASH
+tristate 'Scanlog Dump interface' CONFIG_SCANLOG
 fi
 
 
@@ -228,6 +229,8 @@
 source drivers/usb/Config.in
 fi
 
+source lib/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/configs/pSeries_defconfig linux-2.4.21-rc3/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.20/arch/ppc64/configs/pSeries_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/configs/pSeries_defconfig	2003-05-22 22:06:40.000000000 +0000
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
-
-CONFIG_CMDLINE_BOOL=n
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -178,15 +167,6 @@
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -200,8 +180,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +190,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -245,6 +228,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -401,12 +389,14 @@
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=y
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
+CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -558,14 +543,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +581,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -607,9 +600,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
@@ -639,6 +633,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +649,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -712,21 +706,29 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-CONFIG_KDB=y
-# CONFIG_KDB_OFF is not set
+CONFIG_XMON=y
+# CONFIG_KDB is not set
+# CONFIG_KDB is not set
 # CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
-
-CONFIG_DUMP=y
-CONFIG_DUMP_COMPRESS_RLE=y
-CONFIG_DUMP_COMPRESS_GZIP=y
+# CONFIG_DUMP is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/defconfig linux-2.4.21-rc3/arch/ppc64/defconfig
--- linux-2.4.20/arch/ppc64/defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/defconfig	2003-05-22 22:06:43.000000000 +0000
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
-
-CONFIG_CMDLINE_BOOL=n
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -178,15 +167,6 @@
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -200,8 +180,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +190,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -245,6 +228,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -403,10 +391,12 @@
 CONFIG_ACENIC=y
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
+CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -558,14 +543,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +581,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -607,9 +600,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
@@ -639,6 +633,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +649,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -712,21 +706,29 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-CONFIG_KDB=y
-# CONFIG_KDB_OFF is not set
+CONFIG_XMON=y
+# CONFIG_KDB is not set
+# CONFIG_KDB is not set
 # CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
-
-CONFIG_DUMP=y
-CONFIG_DUMP_COMPRESS_RLE=y
-CONFIG_DUMP_COMPRESS_GZIP=y
+# CONFIG_DUMP is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ItLpQueue.c linux-2.4.21-rc3/arch/ppc64/kernel/ItLpQueue.c
--- linux-2.4.20/arch/ppc64/kernel/ItLpQueue.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/ItLpQueue.c	2003-05-22 22:06:25.000000000 +0000
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <asm/system.h>
 #include <asm/paca.h>
+#include <linux/random.h>
+#include <asm/time.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
@@ -166,5 +168,12 @@
 
 	get_paca()->lpEvent_count += numIntsProcessed;
 
+	/* Use LPEvents as a source of randomness.  Since there
+	 * Isn't an LPEvent Randomness call, pretend these are
+	 * mouse events (which is fair since we don't have mice
+	 * on the iSeries)
+	 */
+	add_mouse_randomness(get_tb());
+
 	return numIntsProcessed;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/Makefile linux-2.4.21-rc3/arch/ppc64/kernel/Makefile
--- linux-2.4.20/arch/ppc64/kernel/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/Makefile	2003-05-22 22:06:42.000000000 +0000
@@ -42,6 +42,8 @@
 
 obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
 
+obj-$(CONFIG_SCANLOG) += scanlog.o
+
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/bitops.c linux-2.4.21-rc3/arch/ppc64/kernel/bitops.c
--- linux-2.4.20/arch/ppc64/kernel/bitops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/bitops.c	2003-05-22 22:06:47.000000000 +0000
@@ -39,7 +39,7 @@
  * 64 bit long layout as shown above.  Got that?  Good.
  */
 
-unsigned long find_next_zero_bit(void * addr, unsigned long size,
+unsigned long find_next_zero_bit(unsigned long* addr, unsigned long size,
 				 unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
@@ -79,6 +79,99 @@
 	return result + ffz(tmp);
 }
 
+unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+{
+        unsigned long *p = addr + (offset >> 6);
+        unsigned long result = offset & ~63UL;
+        unsigned long tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 63UL;
+        if (offset) {
+                tmp = *(p++);
+                tmp &= (~0UL << offset);
+                if (size < 64)
+                        goto found_first;
+                if (tmp)
+                        goto found_middle;
+                size -= 64;
+                result += 64;
+        }
+        while (size & ~63UL) {
+                if ((tmp = *(p++)))
+                        goto found_middle;
+                result += 64;
+                size -= 64;
+        }
+        if (!size)
+                return result;
+        tmp = *p;
+
+found_first:
+        tmp &= (~0UL >> (64 - size));
+        if (tmp == 0UL)        /* Are any bits set? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + __ffs(tmp);
+}
+
+static __inline__ unsigned int ext2_ilog2(unsigned int x)
+{
+        int lz;
+
+        asm("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+        return 31 - lz;
+}
+
+static __inline__ unsigned int ext2_ffz(unsigned int x)
+{
+        u32  tempRC;
+        if ((x = ~x) == 0)
+                return 32;
+        tempRC = ext2_ilog2(x & -x);
+        return tempRC;
+}
+
+unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long
+ offset)
+{
+        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+        unsigned int result = offset & ~31;
+        unsigned int tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 31;
+        if (offset) {
+                tmp = cpu_to_le32p(p++);
+                tmp |= ~0U >> (32-offset); /* bug or feature ? */
+                if (size < 32)
+                        goto found_first;
+                if (tmp != ~0)
+                        goto found_middle;
+                size -= 32;
+                result += 32;
+        }
+        while (size >= 32) {
+                if ((tmp = cpu_to_le32p(p++)) != ~0)
+                        goto found_middle;
+                result += 32;
+                size -= 32;
+        }
+        if (!size)
+                return result;
+        tmp = cpu_to_le32p(p);
+found_first:
+        tmp |= ~0 << size;
+        if (tmp == ~0)          /* Are any bits zero? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + ext2_ffz(tmp);
+}
+
 void BUG_OUTLINE(char* file, unsigned line) 
 {
 	udbg_printf("BUG - kernel BUG at %s:%d! \n", __FILE__, __LINE__);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/chrp_setup.c linux-2.4.21-rc3/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.20/arch/ppc64/kernel/chrp_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/chrp_setup.c	2003-05-22 22:06:50.000000000 +0000
@@ -161,11 +161,12 @@
 
 	fwnmi_init();
 
+#ifndef CONFIG_PPC_ISERIES
 	/* Find and initialize PCI host bridges */
 	/* iSeries needs to be done much later. */
- 	#ifndef CONFIG_PPC_ISERIES
-		find_and_init_phbs();
- 	#endif
+	eeh_init();
+	find_and_init_phbs();
+#endif
 
 	/* Find the Open PIC if present */
 	root = find_path_device("/");
@@ -256,7 +257,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 #endif
 
-	ppc_md.ppc_machine = naca->platform;
+	ppc_md.ppc_machine = systemcfg->platform;
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.setup_residual = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/eeh.c linux-2.4.21-rc3/arch/ppc64/kernel/eeh.c
--- linux-2.4.20/arch/ppc64/kernel/eeh.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/eeh.c	2003-05-22 22:06:41.000000000 +0000
@@ -43,25 +43,25 @@
 static int ibm_set_slot_reset;
 static int ibm_read_slot_reset_state;
 
-int eeh_implemented;
+static int eeh_implemented;
 #define EEH_MAX_OPTS 4096
 static char *eeh_opts;
 static int eeh_opts_last;
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state);
 
-
-unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
-{
-	if (phb > 0xff)
-		panic("eeh_token: phb 0x%lx is too large\n", phb);
-	if (offset & 0x0fffffff00000000)
-		panic("eeh_token: offset 0x%lx is out of range\n", offset);
-	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
-}
-
-int eeh_get_state(unsigned long ea)
-{
-	return 0;
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state);
+
+unsigned long eeh_token_to_phys(unsigned long token)
+{
+	if (REGION_ID(token) == EEH_REGION_ID) {
+		unsigned long vaddr = IO_TOKEN_TO_ADDR(token);
+		pte_t *ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
+		unsigned long pa = pte_pagenr(*ptep) << PAGE_SHIFT;
+		return pa | (vaddr & (PAGE_SIZE-1));
+	} else
+		return token;
 }
 
 /* Check for an eeh failure at the given token address.
@@ -73,47 +73,152 @@
  */
 unsigned long eeh_check_failure(void *token, unsigned long val)
 {
-	unsigned long config_addr = (unsigned long)token >> 24;	/* PPBBDDRR */
-	unsigned long phbidx = (config_addr >> 24) & 0xff;
-	struct pci_controller *phb;
+	unsigned long addr;
+	struct pci_dev *dev;
+	struct device_node *dn;
 	unsigned long ret, rets[2];
 
-	config_addr &= 0xffff00;  /* 00BBDD00 */
+	/* IO BAR access could get us here...or if we manually force EEH
+	 * operation on even if the hardware won't support it.
+	 */
+	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
+		return val;
 
-	if (phbidx >= global_phb_number) {
-		panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
+	/* Finding the phys addr + pci device is quite expensive.
+	 * However, the RTAS call is MUCH slower.... :(
+	 */
+	addr = eeh_token_to_phys((unsigned long)token);
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev) {
+		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
+		return val;
+	}
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
+		return val;
 	}
-	phb = phbtab[phbidx];
 
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
-	if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
-		struct pci_dev *dev;
-		int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
-		int devfn = (config_addr >> 8) & 0xff;
-
-		dev = pci_find_slot(bus, devfn);
-		if (dev) {
-			udbg_printf("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			printk("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			PPCDBG_ENTER_DEBUGGER();
+	/* Access to IO BARs might get this far and still not want checking. */
+	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
+		return val;
+
+
+	/* Now test for an EEH failure.  This is VERY expensive.
+	 * Note that the eeh_config_addr may be a parent device
+	 * in the case of a device behind a bridge, or it may be
+	 * function zero of a multi-function device.
+	 * In any case they must share a common PHB.
+	 */
+	if (dn->eeh_config_addr) {
+		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+				dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
+		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
 			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
 			      rets[0], dev->slot_name, dev->name);
-		} else {
-			udbg_printf("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			printk("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			PPCDBG_ENTER_DEBUGGER();
-			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
 		}
 	}
 	eeh_false_positives++;
 	return val;	/* good case */
+
 }
 
+struct eeh_early_enable_info {
+	unsigned int buid_hi;
+	unsigned int buid_lo;
+	int adapters_enabled;
+};
+
+/* Enable eeh for the given device node. */
+static void *early_enable_eeh(struct device_node *dn, void *data)
+{
+	struct eeh_early_enable_info *info = data;
+	long ret;
+	char *status = get_property(dn, "status", 0);
+	u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
+	u32 *vendor_id =(u32 *) get_property(dn, "vendor-id", 0);
+	u32 *device_id = (u32 *)get_property(dn, "device-id", 0);
+	u32 *regs;
+	int enable;
+
+	if (status && strcmp(status, "ok") != 0)
+		return NULL;	/* ignore devices with bad status */
+
+	/* Weed out PHBs or other bad nodes. */
+	if (!class_code || !vendor_id || !device_id)
+		return NULL;
+
+	/* Ignore known PHBs and EADs bridges */
+	if (*vendor_id == PCI_VENDOR_ID_IBM &&
+	    (*device_id == 0x0102 || *device_id == 0x008b ||
+	     *device_id == 0x0188 || *device_id == 0x0302))
+		return NULL;
+
+	/* Now decide if we are going to "Disable" EEH checking
+	 * for this device.  We still run with the EEH hardware active,
+	 * but we won't be checking for ff's.  This means a driver
+	 * could return bad data (very bad!), an interrupt handler could
+	 * hang waiting on status bits that won't change, etc.
+	 * But there are a few cases like display devices that make sense.
+	 */
+	enable = 1;	/* i.e. we will do checking */
+	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
+		enable = 0;
+
+	if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, enable)) {
+		if (enable) {
+			printk(KERN_INFO "EEH: %s user requested to run without EEH.\n", dn->full_name);
+			enable = 0;
+		}
+	}
+
+	if (!enable)
+		dn->eeh_mode = EEH_MODE_NOCHECK;
+
+	/* This device may already have an EEH parent. */
+	if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
+		/* Parent supports EEH. */
+		dn->eeh_mode |= EEH_MODE_SUPPORTED;
+		dn->eeh_config_addr = dn->parent->eeh_config_addr;
+		return NULL;
+	}
+
+	/* Ok..see if this device supports EEH. */
+	regs = (u32 *)get_property(dn, "reg", 0);
+	if (regs) {
+		/* First register entry is addr (00BBSS00)  */
+		/* Try to enable eeh */
+		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+				regs[0], info->buid_hi, info->buid_lo,
+				EEH_ENABLE);
+		if (ret == 0) {
+			info->adapters_enabled++;
+			dn->eeh_mode |= EEH_MODE_SUPPORTED;
+			dn->eeh_config_addr = regs[0];
+		}
+	}
+	return NULL; 
+}
+
+/*
+ * Initialize eeh by trying to enable it for all of the adapters in the system.
+ * As a side effect we can determine here if eeh is supported at all.
+ * Note that we leave EEH on so failed config cycles won't cause a machine
+ * check.  If a user turns off EEH for a particular adapter they are really
+ * telling Linux to ignore errors.
+ *
+ * We should probably distinguish between "ignore errors" and "turn EEH off"
+ * but for now disabling EEH for adapters is mostly to work around drivers that
+ * directly access mmio space (without using the macros).
+ *
+ * The eeh-force-off/on option does literally what it says, so if Linux must
+ * avoid enabling EEH this must be done.
+ */
 void eeh_init(void)
 {
+	struct device_node *phb;
+	struct eeh_early_enable_info info;
+
 	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
 	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
 	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
@@ -121,64 +226,51 @@
 	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
 	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE && naca->platform == PLATFORM_PSERIES_LPAR)
+
+	/* Allow user to force eeh mode on or off -- even if the hardware
+	 * doesn't exist.  This allows driver writers to at least test use
+	 * of I/O macros even if we can't actually test for EEH failure.
+	 */
+	if (eeh_force_on > eeh_force_off)
 		eeh_implemented = 1;
+	else if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
+		return;
 
 	if (eeh_force_off > eeh_force_on) {
 		/* User is forcing EEH off.  Be noisy if it is implemented. */
 		if (eeh_implemented)
-			printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
+			printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
 		eeh_implemented = 0;
 		return;
 	}
 
-	if (eeh_force_on > eeh_force_off)
-		eeh_implemented = 1;	/* User is forcing it on. */
 
-	if (eeh_implemented)
-		printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
+	/* Enable EEH for all adapters.  Note that eeh requires buid's */
+	info.adapters_enabled = 0;
+	for (phb = find_devices("pci"); phb; phb = phb->next) {
+		int len;
+		int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
+		if (!buid_vals)
+			continue;
+		if (len == sizeof(int)) {
+			info.buid_lo = buid_vals[0];
+			info.buid_hi = 0;
+		} else if (len == sizeof(int)*2) {
+			info.buid_hi = buid_vals[0];
+			info.buid_lo = buid_vals[1];
+		} else {
+			printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
+			continue;
+		}
+		traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
+	}
+	if (info.adapters_enabled) {
+		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
+		eeh_implemented = 1;
+	}
 }
 
 
-/* Given a PCI device check if eeh should be configured or not.
- * This may look at firmware properties and/or kernel cmdline options.
- */
-int is_eeh_configured(struct pci_dev *dev)
-{
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	unsigned long ret, rets[2];
-	int eeh_capable;
-	int default_state = 1;	/* default enable EEH if we can. */
-
-	if (dn == NULL || phb == NULL || !eeh_implemented)
-		return 0;
-
-	/* Hack: turn off eeh for display class devices by default.
-	 * This fixes matrox accel framebuffer.
-	 */
-	if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		default_state = 0;
-
-	/* Ignore known PHBs and EADs bridges */
-	if (dev->vendor == PCI_VENDOR_ID_IBM &&
-	    (dev->device == 0x0102 || dev->device == 0x008b))
-		default_state = 0;
-
-	if (!eeh_check_opts_config(dev, default_state)) {
-		if (default_state)
-			printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
-		return 0;
-	}
-
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			CONFIG_ADDR(dn->busno, dn->devfn),
-			BUID_HI(phb->buid), BUID_LO(phb->buid));
-	eeh_capable = (ret == 0 && rets[1] == 1);
-	printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
-	return eeh_capable;
-}
-
 int eeh_set_option(struct pci_dev *dev, int option)
 {
 	struct device_node *dn = pci_device_to_OF_node(dev);
@@ -193,6 +285,30 @@
 }
 
 
+/* If EEH is implemented, find the PCI device using given phys addr
+ * and check to see if eeh failure checking is disabled.
+ * Remap the addr (trivially) to the EEH region if not.
+ * For addresses not known to PCI the vaddr is simply returned unchanged.
+ */
+void *eeh_ioremap(unsigned long addr, void *vaddr)
+{
+	struct pci_dev *dev;
+	struct device_node *dn;
+
+	if (!eeh_implemented)
+		return vaddr;
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev)
+		return vaddr;
+	dn = pci_device_to_OF_node(dev);
+	if (!dn)
+		return vaddr;
+	if (dn->eeh_mode & EEH_MODE_NOCHECK)
+		return vaddr;
+
+	return (void *)IO_ADDR_TO_TOKEN(vaddr);
+}
+
 static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
 			 int count, int *eof, void *data)
 {
@@ -223,28 +339,24 @@
  * This lets the user specify stupid combinations of options,
  * but at least the result should be very predictable.
  */
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state)
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	char devname[32], classname[32], phbname[32];
+	char devname[32], classname[32];
 	char *strs[8], *s;
 	int nstrs, i;
 	int ret = default_state;
 
-	if (dn == NULL || phb == NULL)
-		return 0;
 	/* Build list of strings to match */
 	nstrs = 0;
 	s = (char *)get_property(dn, "ibm,loc-code", 0);
 	if (s)
 		strs[nstrs++] = s;
-	sprintf(devname, "dev%04x:%04x", dev->vendor, dev->device);
+	sprintf(devname, "dev%04x:%04x", vendor_id, device_id);
 	strs[nstrs++] = devname;
-	sprintf(classname, "class%04x", dev->class);
+	sprintf(classname, "class%04x", class_code);
 	strs[nstrs++] = classname;
-	sprintf(phbname, "pci@%lx", phb->buid);
-	strs[nstrs++] = phbname;
 	strs[nstrs++] = "";	/* yes, this matches the empty string */
 
 	/* Now see if any string matches the eeh_opts list.
@@ -276,7 +388,6 @@
  *
  *	dev#:#    vendor:device id in hex (e.g. dev1022:2000)
  *	class#    class id in hex (e.g. class0200)
- *	pci@buid  all devices under phb (e.g. pci@fef00000)
  *
  * If no location code is specified all devices are assumed
  * so eeh-off means eeh by default is off.
@@ -284,13 +395,11 @@
 
 /* This is implemented as a null separated list of strings.
  * Each string looks like this:  "+X" or "-X"
- * where X is a loc code, dev, class or pci string (as shown above)
+ * where X is a loc code, vendor:device, class (as shown above)
  * or empty which is used to indicate all.
  *
- * We interpret this option string list during the buswalk
- * so that it will literally behave left-to-right even if
- * some combinations don't make sense.  Give the user exactly
- * what they want! :)
+ * We interpret this option string list so that it will literally
+ * behave left-to-right even if some combinations don't make sense.
  */
 
 static int __init eeh_parm(char *str, int state)
@@ -318,7 +427,7 @@
 		if (*cur) {
 			int curlen = curend-cur;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
-				printk("EEH: sorry...too many eeh cmd line options\n");
+				printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
 				return 1;
 			}
 			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/entry.S linux-2.4.21-rc3/arch/ppc64/kernel/entry.S
--- linux-2.4.20/arch/ppc64/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/entry.S	2003-05-22 22:06:27.000000000 +0000
@@ -52,12 +52,12 @@
 	andc	r11,r11,r10
 	std	r11,_CCR(r1)
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	LOADBASE(r31,show_syscalls_task)
 	ld	r31,show_syscalls_task@l(r31)
 	cmp	0,r13,r31
 	bne	1f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	LOADADDR(r3,7f)
 	ld	r4,GPR0(r1)
 	ld	r5,GPR3(r1)
@@ -115,16 +115,16 @@
 _GLOBAL(ret_from_syscall_1)
 20:	std	r3,RESULT(r1)	/* Save result */
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	cmp	0,r13,r31
 	bne	91f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	mr	r4,r3
 	LOADADDR(r3,79f)
 	bl	.printk
 	ld	r3,RESULT(r1)
 91:
-#endif
+#endif /* SHOW_SYSCALLS */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	30f
@@ -177,7 +177,6 @@
 	blrl			/* Call handler */
 _GLOBAL(ret_from_syscall_2)
 58:	std	r3,RESULT(r1)	/* Save result */	
-	std	r3,GPR0(r1)	/* temporary gross hack to make strace work */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	60f
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/head.S linux-2.4.21-rc3/arch/ppc64/kernel/head.S
--- linux-2.4.20/arch/ppc64/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/head.S	2003-05-22 22:06:24.000000000 +0000
@@ -49,8 +49,9 @@
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
  * 0x3000 - 0x3fff : Interrupt support
  * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : Initial segment table
+ * 0x5000 - 0x5fff : SystemCfg
  * 0x6000          : iSeries and common interrupt prologs
+ * 0x9000 - 0x9fff : Initial segment table
  */
 
 /*
@@ -80,6 +81,12 @@
 _stext:
 _STATIC(__start)
 	b .__start_initialization_pSeries
+	.long  0x0
+
+	. = 0x8
+	.globl	__zero
+__zero:
+	.llong	0
 
 	/* At offset 0x20, there is a pointer to iSeries LPAR data.
 	 * This is required by the hypervisor */
@@ -373,21 +380,14 @@
 	.llong 0x0
 	.llong paca
 
-	/*
-	 * Space for the initial segment table
-	 * For LPAR, the hypervisor must fill in at least one entry
-	 * before we get control (with relocate on)
-	 */
 	. = 0x5000
 	.globl __end_naca
-	.globl __start_stab
+	.globl __start_systemcfg
 __end_naca:
-__start_stab:
-
-
+__start_systemcfg:
 	. = 0x6000
-	.globl __end_stab
-__end_stab:
+	.globl __end_systemcfg
+__end_systemcfg:
 
 	/*
 	 * The iSeries LPAR map is at this fixed address
@@ -400,7 +400,7 @@
 
 	.llong	1		/* # ESIDs to be mapped by hypervisor         */
 	.llong	1		/* # memory ranges to be mapped by hypervisor */
-	.llong	5		/* Page # of segment table within load area   */
+	.llong	STAB0_PAGE	/* Page # of segment table within load area   */
 	.llong	0		/* Reserved */
 	.llong  0		/* Reserved */
 	.llong  0		/* Reserved */
@@ -527,6 +527,20 @@
 MachineCheck_FWNMI:
 	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
 
+	/*
+	 * Space for the initial segment table
+	 * For LPAR, the hypervisor must fill in at least one entry
+	 * before we get control (with relocate on)
+	 */
+	. = STAB0_PHYS_ADDR
+	.globl __start_stab
+__start_stab:
+
+	. = (STAB0_PHYS_ADDR + PAGE_SIZE)
+	.globl __end_stab
+__end_stab:
+
+
 /*** Common interrupt handlers ***/
 
 	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
@@ -801,6 +815,7 @@
 	b	fast_exception_return
 	
 _GLOBAL(PerformanceMonitorException)
+	sync
 	mfspr	r7,SPRG3
 	lbz	r8,PACAPROFMODE(r7)
 	cmpi	0,r8,PMC_STATE_PROFILE_KERN
@@ -809,6 +824,8 @@
 	beq 	6f
 	cmpi	0,r8,PMC_STATE_TRACE_USER
 	beq 	9f
+	cmpi	0,r8,PMC_STATE_TIMESLICE
+	beq 	10f
 	blr
 
 	/* PMC Profile Kernel */
@@ -879,6 +896,13 @@
 	addi	r10,r13,THREAD+THREAD_PMC1
 	addi	r7,r13,THREAD+THREAD_PMCC1
 #endif
+	b	7f
+
+	/* PMC Timeslice */
+10:	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
 	/* Accumulate counter values for kernel traces */
 7:	ld	r9,0(r7)
 	mfspr   r8,PMC1	
@@ -914,27 +938,27 @@
 	std	r9,56(r7)
 
 	/* Reset all counters for kernel traces */
-	lwz	r9,0(r10)
+	ld	r9,0(r10)
 	mtspr	PMC1,r9
-	lwz	r9,4(r10)
+	ld	r9,8(r10)
 	mtspr	PMC2,r9
-	lwz	r9,8(r10)
+	ld	r9,16(r10)
 	mtspr	PMC3,r9
-	lwz	r9,12(r10)
+	ld	r9,24(r10)
 	mtspr	PMC4,r9
-	lwz	r9,16(r10)
+	ld	r9,32(r10)
 	mtspr	PMC5,r9
-	lwz	r9,20(r10)
+	ld	r9,40(r10)
 	mtspr	PMC6,r9
-	lwz	r9,24(r10)
+	ld	r9,48(r10)
 	mtspr	PMC7,r9
-	lwz	r9,28(r10)
+	ld	r9,56(r10)
 	mtspr	PMC8,r9
-	lwz	r9,32(r10)
+	ld	r9,64(r10)
 	mtspr	MMCR0,r9
-	lwz	r9,36(r10)
+	ld	r9,72(r10)
 	mtspr	MMCR1,r9
-	lwz	r9,40(r10)
+	ld	r9,80(r10)
 	mtspr	MMCRA,r9
 	blr
 
@@ -1016,6 +1040,13 @@
 #ifdef CONFIG_XMON
 	bl	.xmon
 #endif
+#ifdef CONFIG_KDB
+	/*	    kdb(KDB_REASON_FAULT,regs->trap,regs); */
+	li      r3,1   /* reason_call, regs considered invalid*/
+	li      r4,0x200  /* trap */
+	li      r5,0      /* pointers to regs.*/
+	bl	.kdb
+#endif
 1:	b	1b
 2:
 	/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
@@ -1363,14 +1394,19 @@
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	std	r4,0(r9)		/* set the systemcfg pointer */
+
 	LOADADDR(r9,naca)
-	SET_REG_TO_CONST(r4, KERNELBASE)
-	addi	r4,r4,0x4000
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	std	r4,0(r9)		/* set the naca pointer */
 
+#if 1 /* DRENG:PPPBBB:TIA This looks like dead code to me -Peter */
 	/* Get the pointer to the segment table */
 	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
+#endif
 
 	bl      .iSeries_fixup_klimit
 
@@ -1398,13 +1434,18 @@
 	/* Relocate the TOC from a virt addr to a real addr */
 	sub	r2,r2,r3
 
+	/* setup the systemcfg pointer which is needed by prom_init       */
+	LOADADDR(r9,systemcfg)
+	sub	r9,r9,r3                /* addr of the variable systemcfg */
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	sub	r4,r4,r3
+	std	r4,0(r9)		/* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by prom_init            */
 	LOADADDR(r9,naca)
 	sub	r9,r9,r3                /* addr of the variable naca      */
-
-	SET_REG_TO_CONST(r4, KERNELBASE)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	sub	r4,r4,r3
-	addi	r4,r4,0x4000
 	std	r4,0(r9)		/* set the value of naca          */
 
 	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
@@ -1526,11 +1567,13 @@
 copy_to_here:
 
 /*
+ * load_up_fpu(unused, unused, tsk)
  * Disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
  */
 _STATIC(load_up_fpu)
 	mfmsr	r5                      /* grab the current MSR */
@@ -1548,26 +1591,30 @@
 	ld	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
-	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
+	/* Save FP state to last_task_used_math's THREAD struct */
+	addi	r4,r4,THREAD
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r4)
+	stfd	fr0,THREAD_FPSCR(r4)
+	/* Disable FP for last_task_used_math */
 	ld	r5,PT_REGS(r4)
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r20		/* disable FP for previous task */
+	andc	r4,r4,r20
 	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
-	addi	r5,r13,THREAD		/* Get THREAD */
-	lfd	fr0,THREAD_FPSCR-4(r5)
+	addi	r5,r13,THREAD
+	ld	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP
+	or	r23,r23,r4
+	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
-	subi	r4,r5,THREAD		/* Back to 'current' */
-	std	r4,last_task_used_math@l(r3)
+	/* Update last_task_used_math to 'current' */
+	std	r13,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	b	fast_exception_return
@@ -1606,7 +1653,12 @@
 	cmpi	0,r5,0
 	SAVE_32FPRS(0, r3)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r3)
+	stfd	fr0,THREAD_FPSCR(r3)
+#if 0 /* PPPBBB: enable code below if we run with FE0/1 = 0,0 as default */
+	clrrdi	r4,r13,60		/* r4 <- 0xC000000000000000 */
+	lfd	fr0,__zero@l(r4)
+	mtfsf	0xff,fr0
+#endif
 	beq	1f
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r3,MSR_FP|MSR_FE0|MSR_FE1
@@ -1677,8 +1729,8 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg  */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1753,6 +1805,12 @@
 	bl	.reloc_offset
 	mr	r26,r3
 
+	/* setup the systemcfg pointer which is needed by *tab_initialize  */
+	LOADADDR(r6,systemcfg)
+	sub	r6,r6,r26                /* addr of the variable systemcfg */
+	li	r27,0x5000
+	std	r27,0(r6)	 	 /* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by *tab_initialize       */
 	LOADADDR(r6,naca)
 	sub	r6,r6,r26                /* addr of the variable naca      */
@@ -1819,8 +1877,8 @@
 	ori	r4,r3,1			/* turn on valid bit                */
 
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1840,8 +1898,8 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi r3,PLATFORM_PSERIES
 	bne    98f
 	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
@@ -1891,11 +1949,14 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 
+	/* setup the systemcfg pointer                                       */
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r8, KERNELBASE+0x5000)
+	std	r8,0(r9)
+
 	/* setup the naca pointer                                         */
 	LOADADDR(r9,naca)
-
-	SET_REG_TO_CONST(r8, KERNELBASE)
-	addi	r8,r8,0x4000
+	SET_REG_TO_CONST(r8, KERNELBASE+0x4000)
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
 	LOADADDR(r4,naca)               /* Get naca ptr address           */
@@ -2046,7 +2107,7 @@
 hardware_int_paca0:
 	.space	8*4096
 
-/* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
+/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
 	.globl	stab_array
 stab_array:
         .space	4096 * (48 - 1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/htab.c linux-2.4.21-rc3/arch/ppc64/kernel/htab.c
--- linux-2.4.20/arch/ppc64/kernel/htab.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/htab.c	2003-05-22 22:06:49.000000000 +0000
@@ -73,10 +73,17 @@
 static long hpte_remove(unsigned long hpte_group);
 static long rpa_lpar_hpte_remove(unsigned long hpte_group);
 static long iSeries_hpte_remove(unsigned long hpte_group);
+inline unsigned long get_lock_slot(unsigned long vpn);
 
 static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+#define LOCK_SPLIT
+#ifdef LOCK_SPLIT
+hash_table_lock_t hash_table_lock[128] __cacheline_aligned_in_smp = { [0 ... 31] = {SPIN_LOCK_UNLOCKED}};
+#else
+hash_table_lock_t hash_table_lock[1] __cacheline_aligned_in_smp = { [0] = {SPIN_LOCK_UNLOCKED}};
+#endif
 
 #define KB (1024)
 #define MB (1024*KB)
@@ -115,7 +122,7 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_rw, mask;
+	unsigned long mode_rw, mask, lock_shift;
 
 #if 0
 	/* Can't really do the call below since it calls the normal RTAS
@@ -141,7 +148,15 @@
 	htab_data.htab_num_ptegs = pteg_count;
 	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if(naca->platform == PLATFORM_PSERIES) {
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : 
+	     "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
+	if(systemcfg->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
@@ -167,16 +182,16 @@
 	mask = pteg_count-1;
 
 	/* XXX we currently map kernel text rw, should fix this */
-	if ((naca->platform & PLATFORM_PSERIES) &&
-	   cpu_has_largepage() && (naca->physicalMemorySize > 256*MB)) {
+	if ((systemcfg->platform & PLATFORM_PSERIES) &&
+	   cpu_has_largepage() && (systemcfg->physicalMemorySize > 256*MB)) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, mask, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (naca->physicalMemorySize), 
+				   KERNELBASE + (systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 1);
 	} else {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE+(naca->physicalMemorySize), 
+				   KERNELBASE+(systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 0);
 	}
 #if 0
@@ -220,7 +235,7 @@
 	}
 	local_hpte.dw0.dw0.v = 1;
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
 
 		for (i = 0; i < 8; ++i, ++hptep) {
@@ -229,7 +244,7 @@
 				return;
 			}
 		}
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		slot = ((hash & hash_mask)*HPTES_PER_GROUP);
 		
 		/* Set CEC cookie to 0                   */
@@ -242,12 +257,8 @@
 		lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
 					   local_hpte.dw1.dword1, 
 					   &dummy1, &dummy2);
-		if (lpar_rc != H_Success) {
-			ppc64_terminate_msg(0x21, "hpte enter");
-			loop_forever();
-		}
 		return;
-	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		slot = HvCallHpt_findValid(&rhpte, vpn);
 		if (slot < 0) {
 			/* Must find space in primary group */
@@ -305,18 +316,19 @@
 {
 	unsigned long va, vpn;
 	unsigned long newpp, prpn;
-	unsigned long hpteflags;
+	unsigned long hpteflags, lock_slot;
 	long slot;
 	pte_t old_pte, new_pte;
 
 	/* Search the Linux page table for a match with va */
 	va = (vsid << 28) | (ea & 0x0fffffff);
 	vpn = va >> PAGE_SHIFT;
+	lock_slot = get_lock_slot(vpn); 
 
 	/* Acquire the hash table lock to guarantee that the linux
 	 * pte we fetch will not change
 	 */
-	spin_lock( &hash_table_lock );
+	spin_lock(&hash_table_lock[lock_slot].lock);
 	
 	/* 
 	 * Check the user's access rights to the page.  If access should be
@@ -324,7 +336,7 @@
 	 */
 	access |= _PAGE_PRESENT;
 	if (unlikely(access & ~(pte_val(*ptep)))) {
-		spin_unlock( &hash_table_lock );
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 		return 1;
 	}
 
@@ -401,7 +413,7 @@
 		*ptep = new_pte;
 	}
 
-	spin_unlock(&hash_table_lock);
+	spin_unlock(&hash_table_lock[lock_slot].lock);
 
 	return 0;
 }
@@ -435,22 +447,21 @@
 		mm = &init_mm;
 		vsid = get_kernel_vsid(ea);
 		break;
-	case IO_UNMAPPED_REGION_ID:
-		udbg_printf("EEH Error ea = 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("EEH Error ea = 0x%lx\n", ea);
-		break;
+	case EEH_REGION_ID:
+		/*
+		 * Should only be hit if there is an access to MMIO space
+		 * which is protected by EEH.
+		 * Send the problem up to do_page_fault 
+		 */
 	case KERNEL_REGION_ID:
 		/*
-		 * As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
+		 * Should never get here - entire 0xC0... region is bolted.
+		 * Send the problem up to do_page_fault 
 		 */
-		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("Little faulted on kernel address 0x%lx\n", ea);
-		break;
 	default:
-		/* Not a valid range, send the problem up to do_page_fault */
+		/* Not a valid range
+		 * Send the problem up to do_page_fault 
+		 */
 		return 1;
 		break;
 	}
@@ -483,7 +494,7 @@
 
 void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags, lock_slot;
 	unsigned long large = 0, local = 0;
 	pte_t pte;
 
@@ -497,9 +508,11 @@
 		vpn = va >> LARGE_PAGE_SHIFT;
 	else
 		vpn = va >> PAGE_SHIFT;
+
+	lock_slot = get_lock_slot(vpn); 
 	hash = hpt_hash(vpn, large);
 
-	spin_lock_irqsave( &hash_table_lock, flags);
+	spin_lock_irqsave(&hash_table_lock[lock_slot].lock, flags);
 
 	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
 	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
@@ -511,7 +524,7 @@
 		ppc_md.hpte_invalidate(slot, secondary, va, large, local);
 	}
 
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+	spin_unlock_irqrestore(&hash_table_lock[lock_slot].lock, flags);
 }
 
 long plpar_pte_enter(unsigned long flags,
@@ -567,6 +580,26 @@
 }
 
 /*
+ * Calculate which hash_table_lock to use, based on the pteg being used.
+ *
+ * Given a VPN, use the high order 8 bits to select one of 2^7 locks.  The
+ * highest order bit is used to indicate primary vs. secondary group.  If the
+ * secondary is selected, complement the lock select bits.  This results in
+ * both the primary and secondary groups being covered under the same lock.
+ */
+inline unsigned long get_lock_slot(unsigned long vpn)
+{
+	unsigned long lock_slot;
+#ifdef LOCK_SPLIT
+	lock_slot = (hpt_hash(vpn,0) >> htab_data.htab_lock_shift) & 0xff;
+	if(lock_slot & 0x80) lock_slot = (~lock_slot) & 0x7f;
+#else
+	lock_slot = 0;
+#endif
+	return(lock_slot);
+}
+
+/*
  * Functions used to retrieve word 0 of a given page table entry.
  *
  * Input : slot : PTE index within the page table of the entry to retrieve 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_VpdInfo.c linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_VpdInfo.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_VpdInfo.c	2003-05-22 22:06:27.000000000 +0000
@@ -164,7 +164,8 @@
 	/* Parse Slot label until we find the one requrested         */
 	/*************************************************************/
 	while (SlotMapLen > 0) {
-		if (SlotMapPtr->AgentId == DevNode->AgentId ) {
+		if ((SlotMapPtr->AgentId == DevNode->AgentId) && 
+		    (SlotMapPtr->SecondaryAgentId == 0x10   ) ) {
 			/*******************************************************/
 			/* If Phb wasn't found, grab the entry first one found.*/ 
 			/*******************************************************/
@@ -300,7 +301,7 @@
 		printk("PCI: Bus VPD Buffer zero length.\n");
 		return;
 	}
-	//printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen);
+	//printk("PCI: DevNode:0x%p BusVpdPtr:0x%p Length:%d\n",DevNode, BusVpdPtr, BusVpdLen);
 	/*************************************************************/
 	/* Make sure this is what I think it is                      */
 	/*************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_pci.c	2003-05-22 22:06:26.000000000 +0000
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Allan Trautman, IBM Corporation
  *
  * iSeries specific routines for PCI.
- * /
+ * 
  * Based on code from pci.c and iSeries_pci.c 32bit
  *
  * This program is free software; you can redistribute it and/or modify
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/iSeries_setup.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
@@ -431,7 +429,7 @@
 	u32 chunkBit;
 	u64 map;
 	struct MemoryBlock mb[32];
-	unsigned long numMemoryBlocks, curBlock;
+	unsigned long numMemoryBlocks, curBlock, lock_shift;
 
 	/* Chunk size on iSeries is 256K bytes */
 	totalChunks = (u32)HvLpConfig_getMsChunks();
@@ -492,7 +490,15 @@
 	num_ptegs = hptSizePages * (PAGE_SIZE/(sizeof(HPTE)*HPTES_PER_GROUP));
 	htab_data.htab_num_ptegs = num_ptegs;
 	htab_data.htab_hash_mask = num_ptegs - 1;
+	naca->pftSize = __ilog2(num_ptegs << 7);
 	
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
 	/* The actual hashed page table is in the hypervisor, we have no direct access */
 	htab_data.htab = NULL;
 
@@ -550,15 +556,15 @@
 	 * which should be equal to 
 	 *   nextPhysChunk
 	 */
-	naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
 
 	/* Bolt kernel mappings for all of memory */
-	iSeries_bolt_kernel( 0, naca->physicalMemorySize );
+	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
 
 	lmb_init();
-	lmb_add( 0, naca->physicalMemorySize );
+	lmb_add(0, systemcfg->physicalMemorySize);
 	lmb_analyze();	/* ?? */
-	lmb_reserve( 0, __pa(klimit));
+	lmb_reserve(0, __pa(klimit));
 
 	/* 
 	 * Hardcode to GP size.  I am not sure where to get this info. DRENG
@@ -576,26 +582,24 @@
 	unsigned i,n;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
-	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
-	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
-	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
-	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
-	i = naca->iCacheL1LineSize;
+	systemcfg->iCacheL1Size = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024;
+	systemcfg->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	systemcfg->dCacheL1Size = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024;
+	systemcfg->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
+	naca->iCacheL1LinesPerPage = PAGE_SIZE / systemcfg->iCacheL1LineSize;
+	naca->dCacheL1LinesPerPage = PAGE_SIZE / systemcfg->dCacheL1LineSize;
+
+	i = systemcfg->iCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->iCacheL1LogLineSize = n;
-	i = naca->dCacheL1LineSize;
+	i = systemcfg->dCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->dCacheL1LogLineSize = n;
 
-	printk( "D-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->dCacheL1LineSize,
-			(unsigned)naca->dCacheL1LogLineSize );
-	printk( "I-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->iCacheL1LineSize,
-			(unsigned)naca->iCacheL1LogLineSize );
-	
+	printk( "D-cache line size = %d\n", (unsigned)systemcfg->dCacheL1LineSize);
+	printk( "I-cache line size = %d\n", (unsigned)systemcfg->iCacheL1LineSize);
 }
 
 /*
@@ -637,6 +641,12 @@
 	void *	eventStack;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
+        /* Add an eye catcher and the systemcfg layout version number */
+        strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
+        systemcfg->version.major = SYSTEMCFG_MAJOR;
+        systemcfg->version.minor = SYSTEMCFG_MINOR;
+
+
 	/* Setup the Lp Event Queue */
 
 	/* Allocate a page for the Event Stack
@@ -685,8 +695,8 @@
 	printk("Time base frequency = %lu.%02lu\n",
 			tbFreqMhz,
 			tbFreqMhzHundreths );
-	printk("Processor version = %x\n",
-			xIoHriProcessorVpd[procIx].xPVR );
+	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
+	printk("Processor version = %x\n", systemcfg->processor);
 
 }
 
@@ -715,9 +725,9 @@
 	seq_printf(m,"time base\t: %lu.%02luMHz\n",
 		tbFreqMhz, tbFreqMhzHundreths );
 	seq_printf(m,"i-cache\t\t: %d\n",
-		naca->iCacheL1LineSize);
+		systemcfg->iCacheL1LineSize);
 	seq_printf(m,"d-cache\t\t: %d\n",
-		naca->dCacheL1LineSize);
+		systemcfg->dCacheL1LineSize);
 
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/idle.c linux-2.4.21-rc3/arch/ppc64/kernel/idle.c
--- linux-2.4.20/arch/ppc64/kernel/idle.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/idle.c	2003-05-22 22:06:40.000000000 +0000
@@ -34,36 +34,28 @@
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/ItLpQueue.h>
 
-unsigned long maxYieldTime = 0;
-unsigned long minYieldTime = 0xffffffffffffffffUL;
-
 #ifdef CONFIG_PPC_ISERIES
 static void yield_shared_processor(void)
 {
 	struct paca_struct *lpaca = get_paca();
 	unsigned long tb;
-	unsigned long yieldTime;
 
 	HvCall_setEnabledInterrupts( HvCall_MaskIPI |
 				     HvCall_MaskLpEvent |
 				     HvCall_MaskLpProd |
 				     HvCall_MaskTimeout );
 
-	tb = get_tb();
-	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
-
-	yieldTime = get_tb() - tb;
-	if ( yieldTime > maxYieldTime )
-		maxYieldTime = yieldTime;
-
-	if ( yieldTime < minYieldTime )
-		minYieldTime = yieldTime;
-	
-	/* The decrementer stops during the yield.  Force a fake decrementer
-	 * here and let the timer_interrupt code sort out the actual time.
-	 */
-	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	if ( ! ItLpQueue_isLpIntPending( paca->lpQueuePtr ) ) {
+	  tb = get_tb();
+	  /* Compute future tb value when yield should expire */
+	  HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+	  
+	  /* The decrementer stops during the yield.  Force a fake decrementer
+	   * here and let the timer_interrupt code sort out the actual time.
+	   */
+	  lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	}
+	  
 	process_iSeries_events();
 }
 #endif /* CONFIG_PPC_ISERIES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ioctl32.c linux-2.4.21-rc3/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.20/arch/ppc64/kernel/ioctl32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/ioctl32.c	2003-05-22 22:06:48.000000000 +0000
@@ -838,6 +838,34 @@
 	return err ? -EFAULT : 0;
 }
 
+struct hd_big_geometry32 {
+	u8 heads;
+	u8 sectors;
+	u32 cylinders;
+	u32 start;
+};
+
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO_BIG, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	else {
+		struct hd_big_geometry32 *user_geo = (struct hd_big_geometry32 *)arg;
+		err = __put_user (geo.heads, &(user_geo->heads));
+		err |= __put_user (geo.sectors, &(user_geo->sectors));
+		err |= __put_user (geo.cylinders, &(user_geo->cylinders));
+		err |= __put_user (geo.start, &(user_geo->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
 
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -3706,6 +3734,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -4417,6 +4478,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval),
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
+HANDLE_IOCTL(HDIO_GETGEO_BIG, hdio_getgeo_big),
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big),
 HANDLE_IOCTL(BLKRAGET, w_long),
 HANDLE_IOCTL(BLKGETSIZE, w_long),
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
@@ -4534,6 +4597,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget),
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset),
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget),
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset),
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/misc.S linux-2.4.21-rc3/arch/ppc64/kernel/misc.S
--- linux-2.4.20/arch/ppc64/kernel/misc.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/misc.S	2003-05-22 22:06:40.000000000 +0000
@@ -165,12 +165,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get cache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get cache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -181,12 +183,12 @@
 
 /* Now invalidate the instruction cache */
 	
-	lhz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
+	lwz	r7,ICACHEL1LINESIZE(r11)	/* Get Icache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5
-	lhz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
+	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -212,12 +214,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get dcache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -244,9 +248,11 @@
 /* Flush the dcache */
 	LOADADDR(r7,naca)
 	ld	r7,0(r7)
+	LOADADDR(r8,systemcfg)			/* Get systemcfg address */
+	ld	r8,0(r8)
 	clrrdi	r3,r3,12           	    /* Page align */
-	lhz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
-	lhz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
+	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
+	lwz	r5,DCACHEL1LINESIZE(r8)		/* Get dcache line size */
 	mr	r6,r3
 	mtctr	r4
 0:	dcbst	0,r6
@@ -256,8 +262,8 @@
 
 /* Now invalidate the icache */	
 
-	lhz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
-	lhz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
+	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
+	lwz	r5,ICACHEL1LINESIZE(r8)		/* Get icache line size */
 	mtctr	r4
 1:	icbi	0,r3
 	add	r3,r3,r5
@@ -266,24 +272,6 @@
 	blr
 	
 /*
- * Copy a whole page.  Assumes a 4096B page size.
- */
-_GLOBAL(copy_page)
-	clrrdi	r3,r3,12           	    /* Page align */
-	clrrdi	r4,r4,12           	    /* Page align */
-	li	r5,256
-	mtctr	r5
-	addi	r3,r3,-8
-	addi	r4,r4,-8
-
-1:      ld 	r6,8(r4)
-        ldu	r7,16(r4)
-	std     r6,8(r3) 
-	stdu    r7,16(r3) 
-	bdnz+	1b
-	blr  
-
-/*
  * I/O string operations
  *
  * insb(port, buf, len)
@@ -474,28 +462,28 @@
 	blr
 
 _GLOBAL(cvt_fd)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfs	0,0(r3)
 	stfd	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 _GLOBAL(cvt_df)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfd	0,0(r3)
 	stfs	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 /*
  * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
+ *   arch_kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(arch_kernel_thread)
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
@@ -535,8 +523,8 @@
 	.llong .sys32_execve
 	.llong .sys_chdir
 	.llong .sys32_time
-	.llong .sys32_mknod
-	.llong .sys32_chmod		/* 15 */
+	.llong .sys_mknod
+	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
 	.llong .sys_ni_syscall			/* old break syscall holder */
 	.llong .sys32_stat
@@ -603,7 +591,7 @@
 	.llong .sys32_settimeofday
 	.llong .sys32_getgroups	        /* 80 */
 	.llong .sys32_setgroups
-	.llong .ppc32_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys32_lstat
 	.llong .sys32_readlink	        /* 85 */
@@ -622,7 +610,7 @@
 	.llong .sys_ni_syscall			/* old profil syscall holder */
 	.llong .sys32_statfs
 	.llong .sys32_fstatfs	/* 100 */
-	.llong .sys32_ioperm
+	.llong .sys_ioperm
 	.llong .sys32_socketcall
 	.llong .sys32_syslog
 	.llong .sys32_setitimer
@@ -631,10 +619,10 @@
 	.llong .sys32_newlstat
 	.llong .sys32_newfstat
 	.llong .sys_uname
-	.llong .sys32_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys32_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys32_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys32_sysinfo
@@ -644,7 +632,7 @@
 	.llong .sys32_clone		/* 120 */
 	.llong .sys32_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys32_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys32_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys32_sigprocmask
@@ -712,8 +700,8 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys32_vfork
 	.llong .sys32_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
-	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.llong .sys32_readahead
+	.llong .ppc32_mmap2
 	.llong .sys32_truncate64	/* 193 - truncate64 */
 	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
 	.llong .sys_stat64      	/* 195 - stat64 */
@@ -729,24 +717,7 @@
 	.llong .sys_madvise		/* 205 */
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
-#if 0 /* Reserved syscalls */
-	.llong .sys_tkill		/* 208 */
-	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
-	.llong .sys_fsetxattr
-	.llong .sys_getxattr
-	.llong .sys_lgetxattr
-	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
-	.llong .sys_llistxattr
-	.llong .sys_flistxattr
-	.llong .sys_removexattr
-	.llong .sys_lremovexattr
-	.llong .sys_fremovexattr	/* 220 */
-	.llong .sys_futex
-#endif
-	.llong .sys_perfmonctl   /* Put this here for now ... */
-	.rept NR_syscalls-222
+	.rept NR_syscalls-208
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -774,7 +745,7 @@
 	.llong .sys_lseek
 	.llong .sys_getpid	/* 20 */
 	.llong .sys_mount
-	.llong .sys_oldumount
+	.llong .sys_ni_syscall		/* old umount syscall */
 	.llong .sys_setuid
 	.llong .sys_getuid
 	.llong .ppc64_sys_stime		/* 25 */
@@ -811,7 +782,7 @@
 	.llong .sys_ni_syscall			/* old mpx syscall holder */
 	.llong .sys_setpgid
 	.llong .sys_ni_syscall			/* old ulimit syscall holder */
-	.llong .sys_olduname
+	.llong .sys_ni_syscall		/* old uname syscall */
 	.llong .sys_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
@@ -828,20 +799,20 @@
 	.llong .sys_sigpending
 	.llong .sys_sethostname
 	.llong .sys_setrlimit	/* 75 */
-	.llong .sys_old_getrlimit
+	.llong .sys_ni_syscall		/* old getrlimit syscall */
 	.llong .sys_getrusage
 	.llong .sys_gettimeofday
 	.llong .sys_settimeofday
 	.llong .sys_getgroups	/* 80 */
 	.llong .sys_setgroups
-	.llong .sys_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys_lstat
 	.llong .sys_readlink	/* 85 */
 	.llong .sys_uselib
 	.llong .sys_swapon
 	.llong .sys_reboot
-	.llong .old_readdir
+	.llong .sys_ni_syscall		/* old readdir syscall */
 	.llong .sys_mmap	/* 90 */
 	.llong .sys_munmap
 	.llong .sys_truncate
@@ -862,10 +833,10 @@
 	.llong .sys_newlstat
 	.llong .sys_newfstat
 	.llong .sys_uname
-	.llong .sys_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys_sysinfo
@@ -875,7 +846,7 @@
 	.llong .sys_clone		/* 120 */
 	.llong .sys_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys_sigprocmask
@@ -943,7 +914,7 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys_vfork
 	.llong .sys_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_readahead
 	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
 	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
 	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
@@ -960,23 +931,6 @@
 	.llong .sys_madvise		/* 205 */
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
-#if 0 /* Reserved syscalls */
-	.llong .sys_tkill		/* 208 */
-	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
-	.llong .sys_fsetxattr
-	.llong .sys_getxattr
-	.llong .sys_lgetxattr
-	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
-	.llong .sys_llistxattr
-	.llong .sys_flistxattr
-	.llong .sys_removexattr
-	.llong .sys_lremovexattr
-	.llong .sys_fremovexattr	/* 220 */
-	.llong .sys_futex
-#endif
-	.llong .sys_perfmonctl   /* Put this here for now ... */
-	.rept NR_syscalls-222
+	.rept NR_syscalls-208
 	.llong .sys_ni_syscall
 	.endr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/mk_defs.c linux-2.4.21-rc3/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.20/arch/ppc64/kernel/mk_defs.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/mk_defs.c	2003-05-22 22:06:53.000000000 +0000
@@ -39,7 +39,7 @@
 #include <asm/rtas.h>
 
 #define DEFINE(sym, val) \
-	        asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
+	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
 
 int
 main(void)
@@ -50,29 +50,28 @@
 	DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
 
-        DEFINE(PACA, offsetof(struct naca_struct, paca));
-        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
-
-        DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
-        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
-        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
-
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
-        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
-        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+	DEFINE(PACA, offsetof(struct naca_struct, paca));
 	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
-	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
-
-        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
-        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
-        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
+	DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
+	DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
+	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
+	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct systemcfg, dCacheL1LineSize));
+	DEFINE(ICACHEL1LINESIZE, offsetof(struct systemcfg, iCacheL1LineSize));
+	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
+
+	DEFINE(PACA_SIZE, sizeof(struct paca_struct));
+	DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
+	DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
+	DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
 	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
-        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
-        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
-        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
+	DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
+	DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
+	DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
 	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
-        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
-        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
+	DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
+	DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
 	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
 	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
 	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
@@ -107,18 +106,18 @@
 	DEFINE(PACAPMCC8, offsetof(struct paca_struct, pmcc[7]));
 
 	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
-        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
-        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
-        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
-        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
+	DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
+	DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
+	DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
+	DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+	DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
 	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
 	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
 	DEFINE(LPPACAPDCINT, offsetof(struct ItLpPaca, xIntDword.xFields.xPdcInt));
-        DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
-        DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
-        DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
+	DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+	DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+	DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
 	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
 
 	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
@@ -131,18 +130,25 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 	DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags));
 	DEFINE(PPC_FLAG_32BIT, PPC_FLAG_32BIT);
-	/* Interrupt register frame */
+	/*
+	 * Interrupt register frame
+	 */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-        /* 288 = # of volatile regs, int & fp, for leaf routines */
-        /* which do not stack a frame.  See the PPC64 ABI.       */
-        DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
-	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
-        DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
-        DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	/*
+	 * 288 = # of volatile regs, int & fp, for leaf routines
+	 * which do not stack a frame.  See the PPC64 ABI.
+	 */
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
+	/*
+	 * Create extra stack space for SRR0 and SRR1 when calling prom/rtas.
+	 */
+	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
 	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
 	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
 	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
@@ -157,7 +163,8 @@
 	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
 	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
 	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
-	/* Note: these symbols include _ because they overlap with special
+	/*
+	 * Note: these symbols include _ because they overlap with special
 	 * register names
 	 */
 	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
@@ -173,7 +180,9 @@
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
 
-	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
+	/*
+	 * These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!!
+	 */
 	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
 	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/nvram.c linux-2.4.21-rc3/arch/ppc64/kernel/nvram.c
--- linux-2.4.20/arch/ppc64/kernel/nvram.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/nvram.c	2003-05-22 22:06:25.000000000 +0000
@@ -99,11 +99,11 @@
 }
 
 struct file_operations nvram_fops = {
-	owner:		THIS_MODULE,
-	llseek:		nvram_llseek,
-	read:		read_nvram,
-	write:		write_nvram,
-	ioctl:		nvram_ioctl,
+	.owner =	THIS_MODULE,
+	.llseek =	nvram_llseek,
+	.read =		read_nvram,
+	.write =	write_nvram,
+	.ioctl =	nvram_ioctl,
 };
 
 static struct miscdevice nvram_dev = {
@@ -126,8 +126,7 @@
 	nvram_store = rtas_token("nvram-store");
 	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size);
 
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c linux-2.4.21-rc3/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pSeries_pci.c	2003-05-22 22:06:39.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * pSeries_pci.c
  *
- * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  *
  * pSeries specific routines for PCI.
  * 
@@ -39,7 +39,6 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
-#include <asm/eeh.h>
 
 #include "xics.h"
 #include "open_pic.h"
@@ -78,6 +77,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
 		buid = dn->phb->buid; \
@@ -109,6 +110,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		buid = dn->phb->buid; \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
@@ -252,8 +255,6 @@
 	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
 	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
 
-	eeh_init();
-
 	if (naca->interrupt_controller == IC_OPEN_PIC) {
 		opprop = (unsigned int *)get_property(find_path_device("/"),
 				"platform-open-pic", NULL);
@@ -352,24 +353,15 @@
 				res = &phb->io_resource;
 				res->name = Pci_Node->full_name;
 				res->flags = IORESOURCE_IO;
-				if (is_eeh_implemented()) {
-					if (!isa_io_base && has_isa) {
-						/* map a page for ISA ports.  Not EEH protected. */
-						isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
-					}
-					res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
-					res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
-				} else {
-					phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
-					if (!pci_io_base) {
-						pci_io_base = (unsigned long)phb->io_base_virt;
-						if (has_isa)
-							isa_io_base = pci_io_base;
-					}
-					res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end =   res->start + range.size - 1;
+				phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE);
+				if (!pci_io_base) {
+					pci_io_base = (unsigned long)phb->io_base_virt;
+					if (has_isa)
+						isa_io_base = pci_io_base;
 				}
+				res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+				res->start += (unsigned long)phb->io_base_virt - pci_io_base;
+				res->end =   res->start + range.size - 1;
 				res->parent = NULL;
 				res->sibling = NULL;
 				res->child = NULL;
@@ -393,13 +385,8 @@
 					++memno;
 					res->name = Pci_Node->full_name;
 					res->flags = IORESOURCE_MEM;
-					if (is_eeh_implemented()) {
-						res->start = eeh_token(index, 0, 0, 0);
-						res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
-					} else {
-						res->start = range.parent_addr;
-						res->end =   range.parent_addr + range.size - 1;
-					}
+					res->start = range.parent_addr;
+					res->end =   range.parent_addr + range.size - 1;
 					res->parent = NULL;
 					res->sibling = NULL;
 					res->child = NULL;
@@ -433,6 +420,7 @@
 	struct pci_controller *phb;
 	unsigned int *ui_ptr = NULL, len;
 	struct reg_property64 reg_struct;
+	struct property *of_prop;
 	int *bus_range;
 	int *buid_vals;
 
@@ -517,7 +505,7 @@
 	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
 		if (phb == NULL) return NULL;
 
-		if (naca->platform == PLATFORM_PSERIES) {
+		if (systemcfg->platform == PLATFORM_PSERIES) {
 			phb->cfg_addr = (volatile unsigned long *) 
 			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
 			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
@@ -545,6 +533,21 @@
 		return NULL;
 	}
 
+	/* Add a linux,phbnum property to the device tree so user code
+	 * can translate bus numbers.
+	 */
+	of_prop = (struct property *) alloc_bootmem(sizeof(struct property) +
+						    sizeof(phb->global_number));
+	if (of_prop) {
+		memset(of_prop, 0, sizeof(struct property));
+		of_prop->name = "linux,phbnum";
+		of_prop->length = sizeof(phb->global_number);
+		of_prop->value = (unsigned char *)&of_prop[1];
+		memcpy(of_prop->value, &phb->global_number,
+		       sizeof(phb->global_number));
+		prom_add_property(dev, of_prop);
+	}
+
 	bus_range = (int *) get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name);
@@ -600,7 +603,6 @@
  	int i;
  	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
 	struct device_node *dn;
-	unsigned long eeh_disable_bit;
 
 	/* Add IBM loc code (slot) as a prefix to the device names for service */
 	dn = pci_device_to_OF_node(dev);
@@ -617,20 +619,6 @@
 		}
 	}
 
-	if (is_eeh_implemented()) {
-		if (is_eeh_configured(dev)) {
-			eeh_disable_bit = 0;
-			if (eeh_set_option(dev, EEH_ENABLE) != 0) {
-				printk("PCI: failed to enable EEH for %s %s\n", dev->slot_name, dev->name);
-				eeh_disable_bit = EEH_TOKEN_DISABLED;
-			}
-		} else {
-			/* Assume device is by default EEH_DISABLE'd */
-			printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
-			eeh_disable_bit = EEH_TOKEN_DISABLED;
-		}
-	}
-
 	PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb                 = 0x%016LX\n", phb); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset  = 0x%016LX\n", phb->pci_io_offset); 
@@ -661,19 +649,9 @@
 
 
 		if (dev->resource[i].flags & IORESOURCE_IO) {
-			if (is_eeh_implemented()) {
-				unsigned int busno = dev->bus ? dev->bus->number : 0;
-				unsigned long size = dev->resource[i].end - dev->resource[i].start;
-				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
-				if (!addr)
-					panic("fixup_resources: io ioremap failed!\n");
-				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-				dev->resource[i].end = dev->resource[i].start + size;
-			} else {
-				unsigned long offset = (unsigned long)phb->io_base_virt;
-				dev->resource[i].start += offset;
-				dev->resource[i].end += offset;
-			}
+			unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+			dev->resource[i].start += offset;
+			dev->resource[i].end += offset;
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
 		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
@@ -681,18 +659,8 @@
 				/* Bogus.  Probably an unused bridge. */
 				dev->resource[i].end = 0;
 			} else {
-				if (is_eeh_implemented()) {
-					unsigned int busno = dev->bus ? dev->bus->number : 0;
-					unsigned long size = dev->resource[i].end - dev->resource[i].start;
-					unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
-					if (!addr)
-						panic("fixup_resources: mem ioremap failed!\n");
-					dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-					dev->resource[i].end = dev->resource[i].start + size;
-				} else {
-					dev->resource[i].start += phb->pci_mem_offset;
-					dev->resource[i].end += phb->pci_mem_offset;
-				}
+				dev->resource[i].start += phb->pci_mem_offset;
+				dev->resource[i].end += phb->pci_mem_offset;
 			}
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pacaData.c linux-2.4.21-rc3/arch/ppc64/kernel/pacaData.c
--- linux-2.4.20/arch/ppc64/kernel/pacaData.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pacaData.c	2003-05-22 22:06:48.000000000 +0000
@@ -12,6 +12,8 @@
 #include <stddef.h>
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 
@@ -20,6 +22,7 @@
 #include <asm/paca.h>
 
 struct naca_struct *naca;
+struct systemcfg *systemcfg;
 
 /* The Paca is an array with one entry per processor.  Each contains an 
  * ItLpPaca, which contains the information shared between the 
@@ -65,9 +68,9 @@
 
 struct paca_struct paca[MAX_PACAS] __page_aligned = {
 #ifdef CONFIG_PPC_ISERIES
-	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
+	PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
 #else
-	PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
+	PACAINITDATA( 0, 1, 0, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
 #endif
 	PACAINITDATA( 1, 0, 0, 0, 0),
 	PACAINITDATA( 2, 0, 0, 0, 0),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci.c linux-2.4.21-rc3/arch/ppc64/kernel/pci.c
--- linux-2.4.20/arch/ppc64/kernel/pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pci.c	2003-05-22 22:06:48.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * 
- *
  * Port for PPC64 David Engebretsen, IBM Corp.
  *   Contains common pci routines for ppc64 platform, pSeries and iSeries brands. 
  * 
@@ -33,7 +31,6 @@
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
 #include <asm/machdep.h>
-#include <asm/eeh.h>
 
 #include "pci.h"
 
@@ -123,12 +120,48 @@
 }
 
 
+/* Given an mmio phys address, find a pci device that implements
+ * this address.  This is of course expensive, but only used
+ * for device initialization or error paths.
+ * For io BARs it is assumed the pci_io_base has already been added
+ * into addr.
+ *
+ * Bridges are ignored although they could be used to optimize the search.
+ */
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
+{
+	struct pci_dev *dev;
+	int i;
+	unsigned long ioaddr;
+
+	ioaddr = (addr > _IO_BASE) ? addr - _IO_BASE : 0;
+
+	pci_for_each_dev(dev) {
+		if ((dev->class >> 8) == PCI_BASE_CLASS_BRIDGE)
+			continue;
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			unsigned long start = pci_resource_start(dev,i);
+			unsigned long end = pci_resource_end(dev,i);
+			unsigned int flags = pci_resource_flags(dev,i);
+			if (start == 0 || ~start == 0 ||
+			    end == 0 || ~end == 0)
+				continue;
+			if ((flags & IORESOURCE_IO) &&
+			    (ioaddr >= start && ioaddr <= end))
+				return dev;
+			else if ((flags & IORESOURCE_MEM) &&
+				 (addr >= start && addr <= end))
+				return dev;
+		}
+	}
+	return NULL;
+}
+
 void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
 				struct pbus_set_ranges_data *pranges)
 {
 }
 
-
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			     struct resource *res, int resource)
@@ -182,6 +215,7 @@
 void
 pcibios_align_resource(void *data, struct resource *res, unsigned long size,
 		       unsigned long align)
+
 {
 	struct pci_dev *dev = data;
 
@@ -200,7 +234,6 @@
 	}
 }
 
-
 /*
  *  Handle resources of PCI devices.  If the world were perfect, we could
  *  just allocate all the resource regions and do nothing more.  It isn't.
@@ -409,8 +442,10 @@
                 return NULL;
         }
         memset(hose, 0, sizeof(struct pci_controller));
-        if(strlen(model) < 8) strcpy(hose->what,model);
-        else                  memcpy(hose->what,model,7);
+        if(strlen(model) < 8)
+		strcpy(hose->what,model);
+        else
+		memcpy(hose->what,model,7);
         hose->type = controller_type;
         hose->global_number = global_phb_number;
 	phbtab[global_phb_number++] = hose;
@@ -469,7 +504,7 @@
 			next_busno = hose->last_busno+1;
 	}
 	pci_bus_count = next_busno;
-		
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup) {
 		ppc_md.pcibios_fixup();
@@ -549,21 +584,15 @@
 				/* Transparent resource -- don't try to "fix" it. */
 				continue;
 			}
-			if (is_eeh_implemented()) {
-				if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
-					res->start = eeh_token(phb->global_number, bus->number, 0, 0);
-					res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
-				}
-			} else {
-				if (res->flags & IORESOURCE_IO) {
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end += (unsigned long)phb->io_base_virt;
-				} else if (phb->pci_mem_offset
-					   && (res->flags & IORESOURCE_MEM)) {
-					if (res->start < phb->pci_mem_offset) {
-						res->start += phb->pci_mem_offset;
-						res->end += phb->pci_mem_offset;
-					}
+			if (res->flags & IORESOURCE_IO) {
+				unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+				res->start += offset;
+				res->end += offset;
+			} else if (phb->pci_mem_offset
+				   && (res->flags & IORESOURCE_MEM)) {
+				if (res->start < phb->pci_mem_offset) {
+					res->start += phb->pci_mem_offset;
+					res->end += phb->pci_mem_offset;
 				}
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci.h linux-2.4.21-rc3/arch/ppc64/kernel/pci.h
--- linux-2.4.20/arch/ppc64/kernel/pci.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pci.h	2003-05-22 22:06:48.000000000 +0000
@@ -56,6 +56,7 @@
 void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
 void *traverse_all_pci_devices(traverse_func pre);
 
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr);
 void pci_devs_phb_init(void);
 void pci_fix_bus_sysdata(void);
 struct device_node *fetch_dev_dn(struct pci_dev *dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci_dma.c linux-2.4.21-rc3/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.20/arch/ppc64/kernel/pci_dma.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pci_dma.c	2003-05-22 22:06:41.000000000 +0000
@@ -146,7 +146,7 @@
 		dev = ppc64_isabridge_dev;
 	if (!dev)
 		return NULL;
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
  		return ISERIES_DEVNODE(dev)->DevTceTable;
 	} else {
 		return PCI_GET_DN(dev)->tce_table;
@@ -735,7 +735,7 @@
 	struct pci_dev *dev;
 	struct device_node *dn, *mydn;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		create_tce_tables_for_busesLP(&pci_root_buses);
 	}
 	else {
@@ -776,7 +776,7 @@
  	/* - Tce Table Share between buses,                              */
  	/* - Tce Table per logical slot.                                 */
 	/*****************************************************************/
-	if(naca->platform == PLATFORM_ISERIES_LPAR) {
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 
 		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
 		getTceTableParmsiSeries(DevNode,newTceTable);
@@ -800,7 +800,7 @@
 
 		dn = (struct device_node *)token;
 		phb = dn->phb;
-		if (naca->platform == PLATFORM_PSERIES)
+		if (systemcfg->platform == PLATFORM_PSERIES)
 			getTceTableParmsPSeries(phb, dn, newTceTable);
 		else
 			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci_dn.c linux-2.4.21-rc3/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.20/arch/ppc64/kernel/pci_dn.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pci_dn.c	2003-05-22 22:06:25.000000000 +0000
@@ -50,6 +50,7 @@
 	struct pci_controller *phb = (struct pci_controller *)data;
 	u32 *regs;
 	char *device_type = get_property(dn, "device_type", 0);
+	char *status = get_property(dn, "status", 0);
 
 	dn->phb = phb;
 	if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
@@ -65,6 +66,11 @@
 			dn->devfn = (regs[0] >> 8) & 0xff;
 		}
 	}
+	if (status && strcmp(status, "ok") != 0) {
+		char *name = get_property(dn, "name", 0);
+		printk(KERN_ERR "PCI: %04x:%02x.%x %s (%s) has bad status from firmware! (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "<no name>", device_type ? device_type : "<unknown type>", status);
+		dn->status = 1;
+	}
 	return NULL;
 }
 
@@ -75,9 +81,11 @@
 static void * __init
 write_OF_bars(struct device_node *dn, void *data)
 {
+#ifdef CONFIG_PPC_PSERIES
 	int i;
 	u32 oldbar, newbar, newbartest;
 	u8  config_offset;
+#endif
 	char *name = get_property(dn, "name", 0);
 	char *device_type = get_property(dn, "device_type", 0);
 	char devname[128];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/perfmon.c linux-2.4.21-rc3/arch/ppc64/kernel/perfmon.c
--- linux-2.4.20/arch/ppc64/kernel/perfmon.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/perfmon.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,5 +1,11 @@
 /*
- * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Code to configure and utilize the ppc64 pmc hardware.  Generally, the
+ * following functions are supported:
+ *    1. Kernel profile based on decrementer ticks
+ *    2. Kernel profile based on PMC execution cycles
+ *    3. Trace based on arbitrary PMC counter
+ *    4. Timeslice data capture of arbitrary collections of PMCs
+ *
  * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
  */
 
@@ -14,24 +20,60 @@
 #include <asm/uaccess.h>
 #include <asm/naca.h>
 #include <asm/perfmon.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/hvcall.h>
 
 extern char _stext[], _etext[], _end[];
-struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
+struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, 0, 0, PMC_STATE_INITIAL};
 
 int alloc_perf_buffer(int size);
 int free_perf_buffer(void);
 int clear_buffers(void);
 void pmc_stop(void *data);
+void pmc_clear(void *data);
 void pmc_start(void *data);
 void pmc_touch_bolted(void *data);
 void dump_pmc_struct(struct perfmon_struct *perfdata);
 void dump_hardware_pmc_struct(void *perfdata);
-int  decr_profile(struct perfmon_struct *perfdata);
+int  decr_profile(void *data);
 int  pmc_profile(struct perfmon_struct *perfdata);
 int  pmc_set_general(struct perfmon_struct *perfdata);
 int  pmc_set_user_general(struct perfmon_struct *perfdata);
 void pmc_configure(void *data);
+int pmc_timeslice_enable(struct perfmon_struct *perfdata);
+int pmc_timeslice_disable(struct perfmon_struct *perfdata);
+int pmc_timeslice_set(struct perfmon_struct *perfdata);
+void pmc_dump_timeslice(struct perfmon_struct *perfdata);
+void pmc_trace_rec_type(unsigned long type);
+void pmc_timeslice_data_collect(void *data);
+int pmc_timeslice_tick(void);
+int perfmon_buffer_ctl(void *data);
+int perfmon_dump_ctl(void *data);
+int perfmon_profile_ctl(void *data);
+int perfmon_trace_ctl(void *data);
+int perfmon_timeslice_ctl(void *data);
+
+#define PMC_MAX_CPUS     48
+#define PMC_MAX_COUNTERS 8
+#define PMC_SLICES_STAR  64
+#define PMC_SLICES_GP    28
+#define PMC_SLICES_MAX   64
+#define PMC_TICK_FACTOR  10
 
+int pmc_timeslice_enabled = 0, pmc_timeslice_top = 0;
+int pmc_tick_count[PMC_MAX_CPUS], pmc_timeslice[PMC_MAX_CPUS];
+
+unsigned long pmc_timeslice_data[PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS];
+
+/*
+ * DRENG: todo:
+ * add api to add config entries (entry, values), and bump pmc_timeslice_top
+ *   value
+ * add api to get data from kernel (entry, values)
+ */
+unsigned long pmc_timeslice_config[PMC_SLICES_MAX * 5];
+
+static spinlock_t pmc_lock = SPIN_LOCK_UNLOCKED;
 asmlinkage int
 sys_perfmonctl (int cmd, void *data) 
 { 
@@ -42,37 +84,35 @@
 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
 	switch(cmd) {
-	case PMC_OP_ALLOC:
-		alloc_perf_buffer(0); 
+	case PMC_CMD_BUFFER:
+		perfmon_buffer_ctl(data); 
 		break;
-	case PMC_OP_FREE:
-		free_perf_buffer(); 
-		break;
-	case PMC_OP_CLEAR:
-		clear_buffers();
+	case PMC_CMD_DUMP:
+		perfmon_dump_ctl(data); 
 		break;
-	case PMC_OP_DUMP:
-		dump_pmc_struct(pdata);
-		copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+	case PMC_CMD_DECR_PROFILE: /* NIA time sampling */
+		decr_profile(data); 
 		break;
-	case PMC_OP_DUMP_HARDWARE:
-		dump_hardware_pmc_struct(pdata);
-		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+	case PMC_CMD_PROFILE:
+		perfmon_profile_ctl(pdata); 
 		break;
-	case PMC_OP_DECR_PROFILE: /* NIA time sampling */
-		decr_profile(pdata); 
+	case PMC_CMD_TRACE:
+		perfmon_trace_ctl(pdata); 
 		break;
-	case PMC_OP_PMC_PROFILE:
-		pmc_profile(pdata); 
+	case PMC_CMD_TIMESLICE:
+		perfmon_timeslice_ctl(pdata); 
 		break;
-	case PMC_OP_SET:
-		pmc_set_general(pdata); 
+#if 0
+	case PMC_OP_TIMESLICE:
+		pmc_enable_timeslice(pdata); 
 		break;
-	case PMC_OP_SET_USER:
-		pmc_set_user_general(pdata); 
+	case PMC_OP_DUMP_TIMESLICE:
+		pmc_dump_timeslice(pdata); 
+		smp_call_function(pmc_dump_timeslice, (void *)pdata, 0, 1);
 		break;
+#endif
 	default:
-		printk("Perfmon: Unknown operation\n");
+		printk("Perfmon: Unknown command\n");
 		break;
 	}
 
@@ -80,6 +120,30 @@
 	return 0;
 }
 
+int perfmon_buffer_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_BUFFER_ALLOC:
+		alloc_perf_buffer(0); 
+		break;
+	case PMC_SUBCMD_BUFFER_FREE:
+		free_perf_buffer(); 
+		break;
+	case PMC_SUBCMD_BUFFER_CLEAR:
+		clear_buffers();
+		break;
+	default:
+		return(-1); 
+	}
+
+	return(0); 
+}
+
 int alloc_perf_buffer(int size) 
 {
 	int i;
@@ -92,6 +156,9 @@
 		perfmon_base.trace_length = 1024*1024*16;
 		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
 
+		perfmon_base.timeslice_length = PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS;
+		perfmon_base.timeslice_buffer = (unsigned long)pmc_timeslice_data;
+
 		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
 			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
 			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",
@@ -145,6 +212,8 @@
 
 int clear_buffers() 
 {
+	int i, j;
+
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 
 		return -1;
@@ -152,17 +221,29 @@
 
 	printk("Perfmon: clear buffer\n");
 	
-	/* Stop counters on all processors -- blocking */
+	/* Stop counters on all [PMC_MAX_CPUS]processors -- blocking */
 	pmc_stop(NULL); 
 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
 	
 	/* Clear the buffers */
 	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
 	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
+	memset((char *)perfmon_base.timeslice_buffer, 0, perfmon_base.timeslice_length);
 	
 	/* Reset the trace buffer point */
 	perfmon_base.trace_end = 0;
 	
+	for (i=0; i<MAX_PACAS; ++i) {
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+	}
+#if 0
+	/* Reset the timeslice data */
+	for(i=0; i<(PMC_MAX_CPUS*PMC_MAX_COUNTERS*PMC_SLICES_MAX); i++) {
+		pmc_timeslice_data[i] = 0;
+	}
+#endif
 	/* Restart counters on all processors -- blocking */
 	pmc_start(NULL); 
 	smp_call_function(pmc_start, (void *)NULL, 0, 1);
@@ -173,13 +254,22 @@
 void pmc_stop(void *data) 
 {
 	/* Freeze all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+	mtspr(MMCR0, mfspr( MMCR0 ) | 0x80000000);
+}
+
+void pmc_clear(void *data) 
+{
+	mtspr(PMC1, 0); mtspr(PMC2, 0);
+	mtspr(PMC3, 0); mtspr(PMC4, 0);
+	mtspr(PMC5, 0); mtspr(PMC6, 0);
+	mtspr(PMC7, 0); mtspr(PMC8, 0);
+	mtspr(MMCR0, 0); mtspr(MMCR1, 0); mtspr(MMCRA, 0);
 }
 
 void pmc_start(void *data) 
 {
 	/* Free all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
+	mtspr(MMCR0, mfspr( MMCR0 ) & 0x7fffffff);
 }
 
 void pmc_touch_bolted(void *data) 
@@ -190,6 +280,27 @@
 	touch = *((int *)(perfmon_base.profile_buffer));
 }
 
+int perfmon_dump_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_DUMP_COUNTERS:
+		dump_pmc_struct(pdata);
+		// copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+		break;
+	case PMC_SUBCMD_DUMP_HARDWARE:
+		dump_hardware_pmc_struct(pdata);
+		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+		break;
+	}
+
+	return(0); 
+}
+
 void dump_pmc_struct(struct perfmon_struct *perfdata) 
 {
 	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
@@ -226,7 +337,7 @@
 	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
 }
 
-int decr_profile(struct perfmon_struct *perfdata) 
+int decr_profile(void *data)
 {
 	int i;
 
@@ -251,12 +362,79 @@
 	return 0;
 }
 
+int perfmon_profile_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_PROFILE_CYCLE:
+		pmc_profile(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+
+int perfmon_trace_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	pmc_set_general(pdata); 
+
+#if 0
+        /* Reimplement at some point ... */
+	pmc_set_user_general(pdata); 
+#endif
+	return(0); 
+}
+
+int perfmon_timeslice_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_TIMESLICE_ENABLE:
+		pmc_timeslice_enable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_DISABLE:
+		pmc_timeslice_disable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_SET:
+		pmc_timeslice_set(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+/*
+ * pmc_profile
+ *
+ * Profile the kernel based on cycle counts.  This is made a special case of the more 
+ * general trace functions because it is high use.  Benefits of special casing this
+ * include a buffer of sufficient size to profile the entire kernel is available, and CPI
+ * can be collected along with the profile.
+ */
 int pmc_profile(struct perfmon_struct *perfdata) 
 {
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
 	int i;
 
-	printk("Perfmon: NIA PMC profile and CPI\n");
+	printk("Perfmon: NIA PMC profile\n");
+
+	pmc_timeslice_disable(NULL); // fixme
 
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: failed - no buffer was allocated.\n"); 
@@ -272,15 +450,33 @@
 	}
 	perfmon_base.state = PMC_STATE_PROFILE_KERN; 
 
-	pdata->pmc[0] = 0x7f000000;
-	for(i = 1; i < 8; i++) 
-		pdata->pmc[i] = 0x0;
-	pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
-	pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
-	pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		for(i = 0; i < 8; i++) 
+			pdata->pmc[i] = 0x0;
+		pdata->pmc[1] = 0x7f000000;
+		/* Freeze in problem state, exception enable, freeze on event, */
+		/*   enable counter negative condition, PMC1, PMC2             */
+		pdata->pmc[8] = 0x2600cd0e;
+		pdata->pmc[9] = 0x4a5675ac;
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00022002;
+	} else {
+		pdata->pmc[0] = 0x7f000000;
+		for(i = 1; i < 8; i++) 
+			pdata->pmc[i] = 0x0;
+		pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
+		pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+	}
+
+	pmc_configure_hardware();
 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -308,6 +504,7 @@
 	perfmon_base.state = PMC_STATE_TRACE_KERN; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -316,8 +513,10 @@
 
 int pmc_set_user_general(struct perfmon_struct *perfdata) 
 {
+#if 0
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
-	int pid = perfdata->header.pid;
+#endif
+	int pid = perfdata->header.vdata.pid;
 	struct task_struct *task;
 	int i;
 
@@ -357,38 +556,49 @@
 	perfmon_base.state = PMC_STATE_TRACE_USER; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
 	return 0;
 }
 
+void pmc_trace_rec_type(unsigned long type)
+{
+	unsigned long cmd_rec;
+
+	cmd_rec = 0xFFUL << 56;
+	cmd_rec |= type;
+	*((unsigned long *)(perfmon_base.trace_buffer + 
+			    perfmon_base.trace_end)) = cmd_rec;
+	perfmon_base.trace_end += 8;
+	if(perfmon_base.trace_end >= perfmon_base.trace_length)
+		perfmon_base.trace_end = 0;
+}
+
 void pmc_configure(void *data)
 {
 	struct paca_struct *lpaca = get_paca();
 	struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
-	unsigned long cmd_rec, i;
+	unsigned long i;
 
 	/* Indicate to hypervisor that we are using the PMCs */
-	if(naca->platform == PLATFORM_ISERIES_LPAR)
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR)
 		lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
 
 	/* Freeze all counters */
-	mtspr( MMCR0, 0x80000000 ); mtspr( MMCR1, 0x00000000 );
-
-	cmd_rec = 0xFFUL << 56;
-	cmd_rec |= perfdata->header.type;
-	*((unsigned long *)(perfmon_base.trace_buffer + perfmon_base.trace_end)) = cmd_rec;
-	perfmon_base.trace_end += 8;
+	mtspr(MMCR0, 0x80000000); mtspr(MMCR1, 0x00000000);
 
 	/* Clear all the PMCs */
-	mtspr( PMC1, 0 ); mtspr( PMC2, 0 ); mtspr( PMC3, 0 );
-	mtspr( PMC4, 0 ); mtspr( PMC5, 0 ); mtspr( PMC6, 0 );
-	mtspr( PMC7, 0 ); mtspr( PMC8, 0 );
+	mtspr(PMC1, 0); mtspr(PMC2, 0); mtspr(PMC3, 0); mtspr(PMC4, 0); 
+	mtspr(PMC5, 0); mtspr(PMC6, 0); mtspr(PMC7, 0); mtspr(PMC8, 0);
 
-	for(i = 0; i < 11; i++)
+	/* Set the PMCs to the new values */
+	for(i = 0; i < 11; i++) {
 		lpaca->pmc[i]  = pdata->pmc[i];
+		printk("pmc_configure: 0x%lx\n", pdata->pmc[i]);
+	}
 
 	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
 	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
@@ -398,7 +608,203 @@
 
 	mb();
 	
-	/* Start all counters */
-	mtspr( MMCR0, lpaca->pmc[8]);
+	/* Start all counters - MMCR0 contains the PMC enable control bit */
+	mtspr(MMCR0, lpaca->pmc[8]);
+}
+
+/* Increment the timeslice counters for the current timeslice */ 
+void pmc_timeslice_data_collect(void *data) {
+	struct paca_struct *lpaca = get_paca();
+	int i, cpu = smp_processor_id(); 
+	int slice_rec = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+		        pmc_timeslice[cpu]*PMC_MAX_COUNTERS;
+
+	/* First get any cumulative data that may have accrued */
+	for(i=0; i<8; i++) {
+		pmc_timeslice_data[slice_rec + i] += lpaca->pmcc[i];
+		lpaca->pmcc[i] = 0;
+		lpaca->pmc[i]  = 0;
+	}
+
+	/* Next get current hardware values */
+	pmc_timeslice_data[slice_rec + 0] += ((u32)mfspr(PMC1));
+	pmc_timeslice_data[slice_rec + 1] += ((u32)mfspr(PMC2));
+	pmc_timeslice_data[slice_rec + 2] += ((u32)mfspr(PMC3));
+	pmc_timeslice_data[slice_rec + 3] += ((u32)mfspr(PMC4));
+	pmc_timeslice_data[slice_rec + 4] += ((u32)mfspr(PMC5));
+	pmc_timeslice_data[slice_rec + 5] += ((u32)mfspr(PMC6));
+	pmc_timeslice_data[slice_rec + 6] += ((u32)mfspr(PMC7));
+	pmc_timeslice_data[slice_rec + 7] += ((u32)mfspr(PMC8));
+}
+
+/* Handle a timeslice tick.  Each processor executes independantly */
+int pmc_timeslice_tick() {
+	int i;
+	struct perfmon_struct perfdata;
+	unsigned int cpu = smp_processor_id();
+
+	/* Switch timeslice every decrementer, reduced by some factor */
+	pmc_tick_count[cpu]++;
+	if(!pmc_timeslice_enabled || pmc_tick_count[cpu] < PMC_TICK_FACTOR) 
+		return 0;
+	pmc_tick_count[cpu] = 0;
+
+	/* Stop counters and collect current state */
+	pmc_stop(NULL); 
+	pmc_timeslice_data_collect(NULL); 
+
+	/* Move on to the next timeslice */
+	pmc_timeslice[cpu]++; 
+	if(pmc_timeslice[cpu] >= pmc_timeslice_top) pmc_timeslice[cpu] = 0;
+
+	/* Set up the counters to reflect the new data to collect */
+	for(i = 0; i < 8; i++) {
+		perfdata.vdata.pmc.pmc[i] = 0;
+	}
+	for(i = 0; i < 3; i++) {
+		perfdata.vdata.pmc.pmc[i+8] = 
+			pmc_timeslice_config[pmc_timeslice[cpu]*5+i];
+	}
+	mb();
+
+	/* Configure the new counters */
+	pmc_configure((void *)&perfdata);
+
+	return 0;
+}
+
+int pmc_timeslice_set(struct perfmon_struct *perfdata) 
+{
+	int slice; 
+
+	printk("Perfmon: Timeslice set\n");
+
+	slice = perfdata->header.vdata.slice;
+	if(slice >= PMC_SLICES_MAX) {
+		printk("Perfmon: invalid timeslice specified %d\n", slice);
+		return(-1); 
+	}
+
+	if(slice > pmc_timeslice_top) pmc_timeslice_top = slice;
+
+	pmc_timeslice_config[slice * 5 + 0] = perfdata->vdata.pmc.pmc[0];
+	pmc_timeslice_config[slice * 5 + 1] = perfdata->vdata.pmc.pmc[1];
+	pmc_timeslice_config[slice * 5 + 2] = perfdata->vdata.pmc.pmc[2];
+	pmc_timeslice_config[slice * 5 + 3] = perfdata->vdata.pmc.pmc[3];
+	pmc_timeslice_config[slice * 5 + 4] = perfdata->vdata.pmc.pmc[4];
 }
 
+int pmc_timeslice_enable(struct perfmon_struct *perfdata) 
+{
+	int i, j;
+
+	printk("Perfmon: Timeslice mode\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	pmc_timeslice_disable(NULL); // fixme
+	mb();
+
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+	}
+	perfmon_base.state = PMC_STATE_TIMESLICE; 
+
+	pmc_configure_hardware(); 
+
+	for(i=0; i<PMC_MAX_CPUS; i++) {
+		pmc_tick_count[i] = 0;
+		pmc_timeslice[i]  = 0;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+
+	/* Clear out the PMC counters, cumulative and current */
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+		for(j=0; j<11; j++) {
+			paca[i].pmc[j] = 0;
+		}
+	}	
+
+	memset((char *)perfmon_base.timeslice_buffer, 
+	       0, perfmon_base.timeslice_length);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE);
+
+	/* Clear counters on all processors -- blocking */
+	pmc_clear(NULL); 
+	smp_call_function(pmc_clear, (void *)NULL, 0, 1);
+
+	mb();
+
+	pmc_timeslice_enabled  = 1;
+
+	/* 
+	 * We do not actually setup the PMC hardware here.  That occurs
+	 * after the first timeslice tick occurs. Close enough.
+	 */
+	return 0;
+}
+
+int pmc_timeslice_disable(struct perfmon_struct *perfdata) 
+{
+	pmc_timeslice_enabled = 0;
+}
+
+void pmc_dump_timeslice(struct perfmon_struct *perfdata) 
+{
+	unsigned long rec, i, j, idx;
+	int cpu = smp_processor_id(); 
+
+	spin_lock(&pmc_lock);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE_DUMP); /* DRENG put cpu num in */
+	for(i=0; i<pmc_timeslice_top; i++) {
+		for(j=0; j<8; j++) {
+			idx = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+				i*PMC_MAX_COUNTERS + j;
+			rec = pmc_timeslice_data[idx];
+			*((unsigned long *)(perfmon_base.trace_buffer + 
+					    perfmon_base.trace_end)) = rec;
+			perfmon_base.trace_end += 8;
+			if(perfmon_base.trace_end >= perfmon_base.trace_length)
+				perfmon_base.trace_end = 0;
+		}
+	}
+	spin_unlock(&pmc_lock);
+}
+
+long plpar_perfmon(int mode)
+{
+        return plpar_hcall_norets(H_PERFMON, mode, 0); 
+}
+
+void pmc_configure_hardware() {
+	/* 
+	 * Debug bus enabled is required on GP for timeslice mode.
+	 * Flood enabled is required on GP for PMC cycle profile mode
+	 *   iSeries SP sets this by default.  pSeries requires the OS to enable.
+	 */
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		/* Set up the debug bus to pmc mode - a feature of GP */
+		switch(systemcfg->platform) {
+		case PLATFORM_ISERIES_LPAR:
+			HvCall_setDebugBus(1);
+			break;
+		case PLATFORM_PSERIES_LPAR:
+			plpar_perfmon(1);
+			break;
+		case PLATFORM_PSERIES:
+			mtspr(HID0, mfspr(HID0) | 0x0000080000000000);
+		} 
+	} 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pmc.c linux-2.4.21-rc3/arch/ppc64/kernel/pmc.c
--- linux-2.4.20/arch/ppc64/kernel/pmc.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/pmc.c	2003-05-22 22:06:24.000000000 +0000
@@ -73,7 +73,8 @@
 struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
-extern spinlock_t hash_table_lock;
+extern spinlock_t hash_table_lock[];
+extern inline unsigned long get_lock_slot(unsigned long vpn);
 
 char *
 ppc64_pmc_stab(int file)
@@ -211,15 +212,14 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep, pte;
-	unsigned long ea_base, ea, hpteflags;
+	unsigned long ea_base, ea, hpteflags, lock_slot;
 	struct vm_struct *area;
-	unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
+	unsigned long pa, pg_count, page, vsid, slot, va, rpn, vpn;
   
 	size = PAGE_ALIGN(size);
 	if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL;
 
 	spin_lock(&btmalloc_mm.page_table_lock);
-	spin_lock(&hash_table_lock);
 
 	/* Get a virtual address region in the bolted space */
 	area = get_btm_area(size, 0);
@@ -236,10 +236,12 @@
 		pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
 		ea = ea_base + (page * PAGE_SIZE);
 		vsid = get_kernel_vsid(ea);
-		va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		va = ( vsid << 28 ) | ( ea & 0xfffffff );
 		vpn = va >> PAGE_SHIFT;
-		arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
+		lock_slot = get_lock_slot(vpn); 
+		rpn = pa >> PAGE_SHIFT;
 
+		spin_lock(&hash_table_lock[lock_slot].lock);
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
 		 * that the pmd & pte pages are not themselfs bolted.
@@ -257,13 +259,16 @@
 		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
 		pte_val(pte) |= _PAGE_HASHPTE;
 
-		slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
+		slot = ppc_md.hpte_insert(vpn, rpn, hpteflags, 1, 0);  
 
 		pte_val(pte) |= ((slot<<12) & 
 				 (_PAGE_GROUP_IX | _PAGE_SECONDARY));
+
+		*ptep = pte;
+
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 	}
 
-	spin_unlock(&hash_table_lock);
 	spin_unlock(&btmalloc_mm.page_table_lock);
 	return (void*)ea_base;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.21-rc3/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/ppc_ksyms.c	2003-05-22 22:06:53.000000000 +0000
@@ -106,6 +106,7 @@
 EXPORT_SYMBOL(pci_dram_offset);
 
 EXPORT_SYMBOL(find_next_zero_bit);
+EXPORT_SYMBOL(find_next_zero_le_bit);
 
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -124,6 +125,7 @@
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(naca);
+EXPORT_SYMBOL(systemcfg);
 EXPORT_SYMBOL(__down);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
@@ -252,6 +254,8 @@
 EXPORT_SYMBOL(rtas_firmware_flash_list);
 EXPORT_SYMBOL(rtas_token);
 EXPORT_SYMBOL(rtas_call);
+EXPORT_SYMBOL(rtas_data_buf);
+EXPORT_SYMBOL(rtas_data_buf_lock);
 #endif
 
 #ifndef CONFIG_PPC_ISERIES
@@ -269,10 +273,6 @@
 
 EXPORT_SYMBOL(abs);
 
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(irq_desc);
 void ppc_irq_dispatch_handler(struct pt_regs *, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/proc_pmc.c linux-2.4.21-rc3/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.20/arch/ppc64/kernel/proc_pmc.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/proc_pmc.c	2003-05-22 22:06:52.000000000 +0000
@@ -110,6 +110,9 @@
 static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos);
 static ssize_t write_trace(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos);
+static ssize_t read_timeslice(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
 
 static struct file_operations proc_profile_operations = {
 	read:		read_profile,
@@ -121,6 +124,11 @@
 	write:		write_trace,
 };
 
+static struct file_operations proc_timeslice_operations = {
+	read:		read_timeslice,
+	write:		write_timeslice,
+};
+
 extern struct perfmon_base_struct perfmon_base;
 
 void proc_ppc64_init(void)
@@ -144,7 +152,15 @@
 	ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
 	if ( ent ) {
 		ent->nlink = 1;
-		ent->data = 0;
+		ent->data = naca;
+		ent->size = 4096;
+		ent->proc_fops = &nacamap_fops;
+	}
+	
+	ent = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64_root);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = systemcfg;
 		ent->size = 4096;
 		ent->proc_fops = &nacamap_fops;
 	}
@@ -152,7 +168,7 @@
 	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 	ent = proc_mkdir("paca", proc_ppc64_root);
 	if (ent) {
-		for (i = 0; i < naca->processorCount; i++)
+		for (i = 0; i < systemcfg->processorCount; i++)
 			proc_ppc64_create_paca(i, ent);
 	}
 
@@ -165,14 +181,14 @@
 	proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root);
 
 	proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		sprintf(buf, "cpu%ld", i); 
 		proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root);
 	}
 
 
 	/* Create directories for the software counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -224,8 +240,14 @@
 		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
 	}
 
+	ent = create_proc_entry("timeslice", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_timeslice_operations;
+	}
+
 	/* Create directories for the hardware counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -299,7 +321,7 @@
 	   (unsigned long) proc_ppc64_pmc_system_root) {
 		return(-1); 
 	} else {
-		for (i = 0; i < naca->processorCount; i++) {
+		for (i = 0; i < systemcfg->processorCount; i++) {
 			if ((unsigned long)data ==
 			   (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
 				return(i); 
@@ -417,20 +439,24 @@
 	return read;
 }
 
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
 static ssize_t read_trace(struct file *file, char *buf,
 			    size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
 	ssize_t read;
 	char * pnt;
-	unsigned int sample_step = 4;
 
 	if (p >= (perfmon_base.trace_length)) return 0;
 	if (count > (perfmon_base.trace_length) - p)
 		count = (perfmon_base.trace_length) - p;
 	read = 0;
 
-	pnt = (char *)(perfmon_base.trace_buffer) + p; //  - sizeof(unsigned int);
+	pnt = (char *)(perfmon_base.trace_buffer) + p;
 	copy_to_user(buf,(void *)pnt,count);
 	read += count;
 	*ppos += read;
@@ -442,8 +468,28 @@
 {
 }
 
-static ssize_t write_profile(struct file * file, const char * buf,
-			     size_t count, loff_t *ppos)
+static ssize_t read_timeslice(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.timeslice_length)) return 0;
+	if (count > (perfmon_base.timeslice_length) - p)
+		count = (perfmon_base.timeslice_length) - p;
+	read = 0;
+
+	pnt = (char *)(perfmon_base.timeslice_buffer) + p;
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
 {
 }
 
@@ -545,7 +591,7 @@
 			(unsigned long)xItLpQueue.xLpIntCountByType[i] );
 	}
 	len += sprintf( page+len, "\n  events processed by processor:\n" );
-	for (i=0; i<naca->processorCount; ++i) {
+	for (i=0; i<systemcfg->processorCount; ++i) {
 		len += sprintf( page+len, "    CPU%02d  %10u\n",
 			i, paca[i].lpEvent_count );
 	}
@@ -978,45 +1024,33 @@
 static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
 	unsigned pos = *ppos;
-	unsigned size;
-	char * fromaddr;
 	struct proc_dir_entry *dp;
 
 	dp = file->f_dentry->d_inode->u.generic_ip;
 
-	size = dp->size;
-	if ( pos >= size )
+	if ( pos >= dp->size )
 		return 0;
-	if ( nbytes >= size )
-		nbytes = size;
-	if ( pos + nbytes > size )
-		nbytes = size - pos;
-	fromaddr = (char *)(KERNELBASE + 0x4000 + pos);
+	if ( nbytes >= dp->size )
+		nbytes = dp->size;
+	if ( pos + nbytes > dp->size )
+		nbytes = dp->size - pos;
 
-	copy_to_user( buf, fromaddr, nbytes );
+	copy_to_user( buf, (char *)dp->data + pos, nbytes );
 	*ppos = pos + nbytes;
 	return nbytes;
 }
 
 static int nacamap_mmap( struct file *file, struct vm_area_struct *vma )
 {
-	unsigned long pa;
-	long size;
-	long fsize;
 	struct proc_dir_entry *dp;
 
 	dp = file->f_dentry->d_inode->u.generic_ip;
 
-	pa = 0x4000;
-	fsize = 4096;
-
 	vma->vm_flags |= VM_SHM | VM_LOCKED;
 
-	size = vma->vm_end - vma->vm_start;
-	if ( size != 4096 )
+	if ((vma->vm_end - vma->vm_start) > dp->size)
 		return -EINVAL;
 
-	remap_page_range( vma->vm_start, pa, 4096, vma->vm_page_prot );
+	remap_page_range( vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
 	return 0;
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/process.c linux-2.4.21-rc3/arch/ppc64/kernel/process.c
--- linux-2.4.20/arch/ppc64/kernel/process.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/process.c	2003-05-22 22:06:28.000000000 +0000
@@ -241,6 +241,7 @@
 	}
 	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
 	p->thread.fpscr = current->thread.fpscr;
+	p->thread.fpexc_mode = current->thread.fpexc_mode;
 
 	return 0;
 }
@@ -278,6 +279,32 @@
 	current->thread.fpscr = 0;
 }
 
+# define PR_FP_EXC_DISABLED     0       /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV     1       /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC        2       /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE      3       /* precise exception mode */
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
@@ -337,13 +364,13 @@
 
 void initialize_paca_hardware_interrupt_stack(void)
 {
-	extern struct naca_struct *naca;
+	extern struct systemcfg *systemcfg;
 
 	int i;
 	unsigned long stack;
 	unsigned long end_of_stack =0;
 
-	for (i=1; i < naca->processorCount; i++) {
+	for (i=1; i < systemcfg->processorCount; i++) {
 		/* Carve out storage for the hardware interrupt stack */
 		stack = __get_free_pages(GFP_KERNEL, get_order(8*PAGE_SIZE));
 
@@ -366,7 +393,7 @@
 	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		return;
 
-	for (i=0; i < naca->processorCount; i++) {
+	for (i=0; i < systemcfg->processorCount; i++) {
 		/* set page at the top of stack to be protected - prevent overflow */
 		end_of_stack = paca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
 		ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack);
@@ -461,6 +488,10 @@
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
+			/*
+			 * XXX we mask the upper 32 bits until procps
+			 * gets fixed.
+			 */
 			if (ip < first_sched || ip >= last_sched)
 				return (ip & 0xFFFFFFFF);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/prom.c linux-2.4.21-rc3/arch/ppc64/kernel/prom.c
--- linux-2.4.20/arch/ppc64/kernel/prom.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/prom.c	2003-05-22 22:06:52.000000000 +0000
@@ -342,6 +342,7 @@
         unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 
 	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
@@ -362,7 +363,7 @@
 			 * d-cache and i-cache sizes... -Peter
 			 */
 			if ( num_cpus == 1 ) {
-				u32 size, lsize, sets;
+				u32 size, lsize;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("d-cache-size"),
@@ -372,35 +373,25 @@
 					  RELOC("d-cache-line-size"),
 					  &lsize, sizeof(lsize));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-sets"),
-					  &sets, sizeof(sets));
-
-				_naca->dCacheL1Size         = size;
-				_naca->dCacheL1LineSize     = lsize;
-				_naca->dCacheL1LogLineSize  = __ilog2(lsize);
+				_systemcfg->dCacheL1Size = size;
+				_systemcfg->dCacheL1LineSize = lsize;
+				_naca->dCacheL1LogLineSize = __ilog2(lsize);
 				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
-				_naca->dCacheL1Assoc = size / lsize / sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-line-size"),
+					  RELOC("i-cache-size"),
 					  &size, sizeof(size));
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("i-cache-line-size"),
 					  &lsize, sizeof(lsize));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-sets"),
-					  &sets, sizeof(sets));
-
-				_naca->iCacheL1Size         = size;
-				_naca->iCacheL1LineSize     = lsize;
-				_naca->iCacheL1LogLineSize  = __ilog2(lsize);
+				_systemcfg->iCacheL1Size = size;
+				_systemcfg->iCacheL1LineSize = lsize;
+				_naca->iCacheL1LogLineSize = __ilog2(lsize);
 				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
-				_naca->iCacheL1Assoc = size / lsize / sets;
 
-				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
+				if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
 					call_prom(RELOC("getprop"), 4, 1, node, 
 						  RELOC("ibm,pft-size"),
@@ -470,17 +461,17 @@
 	}
 
 	/* We gotta have at least 1 cpu... */
-        if ( (_naca->processorCount = num_cpus) < 1 )
+        if ( (_systemcfg->processorCount = num_cpus) < 1 )
                 PROM_BUG();
 
-	_naca->physicalMemorySize = lmb_phys_mem_size();
+	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
-	if (_naca->platform == PLATFORM_PSERIES) {
+	if (_systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
-		rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
-		if (rnd_mem_size < _naca->physicalMemorySize)
+		rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
+		if (rnd_mem_size < _systemcfg->physicalMemorySize)
 			rnd_mem_size <<= 1;
 
 		/* # pages / 2 */
@@ -501,58 +492,43 @@
 	 */
 	_naca->slb_size = 64;
 
-	/* Add an eye catcher and the naca layout version number */
-	strcpy(_naca->eye_catcher, RELOC("PPC64"));
-	_naca->version     = 1;
-	_naca->processor   = _get_PVR() >> 16;
+	/* Add an eye catcher and the systemcfg layout version number */
+	strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
+	_systemcfg->version.major = SYSTEMCFG_MAJOR;
+	_systemcfg->version.minor = SYSTEMCFG_MINOR;
+	_systemcfg->processor = _get_PVR();
 
 #ifdef DEBUG_PROM
-        prom_print(RELOC("naca->processorCount       = 0x"));
-        prom_print_hex(_naca->processorCount);
+        prom_print(RELOC("systemcfg->processorCount       = 0x"));
+        prom_print_hex(_systemcfg->processorCount);
         prom_print_nl();
 
-        prom_print(RELOC("naca->physicalMemorySize   = 0x"));
-        prom_print_hex(_naca->physicalMemorySize);
+        prom_print(RELOC("systemcfg->physicalMemorySize   = 0x"));
+        prom_print_hex(_systemcfg->physicalMemorySize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->pftSize              = 0x"));
+        prom_print(RELOC("naca->pftSize                   = 0x"));
         prom_print_hex(_naca->pftSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->dCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->dCacheL1LineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->dCacheL1LogLineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->dCacheL1LinesPerPage);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->iCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->iCacheL1LineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->iCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->iCacheL1LogLineSize);
+        prom_print(RELOC("systemcfg->dCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->dCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->iCacheL1LinesPerPage);
+        prom_print(RELOC("systemcfg->iCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->iCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->serialPortAddr       = 0x"));
+        prom_print(RELOC("naca->serialPortAddr            = 0x"));
         prom_print_hex(_naca->serialPortAddr);
         prom_print_nl();
 
-        prom_print(RELOC("naca->interrupt_controller = 0x"));
+        prom_print(RELOC("naca->interrupt_controller      = 0x"));
         prom_print_hex(_naca->interrupt_controller);
         prom_print_nl();
 
-        prom_print(RELOC("naca->platform             = 0x"));
-        prom_print_hex(_naca->platform);
+        prom_print(RELOC("systemcfg->platform             = 0x"));
+        prom_print_hex(_systemcfg->platform);
         prom_print_nl();
 
 	prom_print(RELOC("prom_initialize_naca: end...\n"));
@@ -655,7 +631,7 @@
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
 	struct rtas_t *_rtas = PTRRELOC(&rtas);
-	struct naca_struct *_naca = RELOC(naca);
+	struct systemcfg *_systemcfg = RELOC(systemcfg);
 	ihandle prom_rtas;
         u32 getprop_rval;
 
@@ -672,7 +648,7 @@
 				  RELOC("ibm,hypertas-functions"), 
 				  hypertas_funcs, 
 				  sizeof(hypertas_funcs))) > 0) {
-			_naca->platform = PLATFORM_PSERIES_LPAR;
+			_systemcfg->platform = PLATFORM_PSERIES_LPAR;
 		}
 
 		call_prom(RELOC("getprop"), 
@@ -689,7 +665,7 @@
 			 * of physical memory (or within the RMO region) because RTAS
 			 * runs in 32-bit mode and relocate off.
 			 */
-			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+			if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
 				struct lmb *_lmb  = PTRRELOC(&lmb);
 				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
 			}
@@ -1083,12 +1059,12 @@
         unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
         unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
         unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
-        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Initially, we must have one active CPU. */
-	_naca->processorCount = 1;
+	_systemcfg->processorCount = 1;
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_hold_cpus: start...\n"));
@@ -1206,7 +1182,7 @@
 		if (*acknowledge == cpuid) {
 			prom_print(RELOC("ok\n"));
 			/* Set the number of active processors. */
-			_naca->processorCount++;
+			_systemcfg->processorCount++;
 		} else {
 			prom_print(RELOC("failed: "));
 			prom_print_hex(*acknowledge);
@@ -1220,8 +1196,8 @@
 	    __is_processor(PV_SSTAR)) {
 		prom_print(RELOC("    starting secondary threads\n"));
 
-		for (i=0; i < _naca->processorCount ;i++) {
-			unsigned long threadid = _naca->processorCount*2-1-i;
+		for (i=0; i < _systemcfg->processorCount ;i++) {
+			unsigned long threadid = _systemcfg->processorCount*2-1-i;
 			
 			if (i == 0) {
 				unsigned long pir = _get_PIR();
@@ -1247,7 +1223,7 @@
 #endif
 			_xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1;
 		}
-		_naca->processorCount *= 2;
+		_systemcfg->processorCount *= 2;
 	} else {
 		prom_print(RELOC("Processor is not HMT capable\n"));
 	}
@@ -1381,13 +1357,14 @@
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
-        struct naca_struct   *_naca = RELOC(naca);
+        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 	char *_cmd_line = PTRRELOC(&cmd_line[0]);
 
 	/* Default machine type. */
-	_naca->platform = PLATFORM_PSERIES;
+	_systemcfg->platform = PLATFORM_PSERIES;
 	/* Reset klimit to take into account the embedded system map */
 	if (RELOC(embedded_sysmap_end))
 		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
@@ -1475,6 +1452,8 @@
 			    sizeof(cmd_line)-1);
 	if (sz > 0)
 		_cmd_line[sz] = '\0';
+        if (sz <=1 )
+                strcpy(_cmd_line,RELOC(CONFIG_CMDLINE));
 
 	prom_parse_cmd_line(_cmd_line);
 
@@ -1544,6 +1523,8 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
+	mem = check_display(mem);
+
 	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
@@ -1553,11 +1534,9 @@
          * following, regardless of whether we have an SMP
          * kernel or not.
          */
-        if ( _naca->processorCount > 1 )
+        if (_systemcfg->processorCount > 1)
 	        prom_hold_cpus(mem);
 
-	mem = check_display(mem);
-
 #ifdef DEBUG_PROM
 	prom_print(RELOC("copying OF device tree...\n"));
 #endif
@@ -1567,7 +1546,7 @@
 
 	lmb_reserve(0, __pa(RELOC(klimit)));
 
-	if (_naca->platform == PLATFORM_PSERIES)
+	if (_systemcfg->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
  	if ((long) call_prom(RELOC("getprop"), 4, 1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ptrace.c linux-2.4.21-rc3/arch/ppc64/kernel/ptrace.c
--- linux-2.4.20/arch/ppc64/kernel/ptrace.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/ptrace.c	2003-05-22 22:06:48.000000000 +0000
@@ -252,50 +252,68 @@
 		break;
 
 	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
-
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.regs)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-		u64 cntr;
-
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-			ret = put_reg(child, cntr, *(u64*)(data+cntr));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
 	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.fpr)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
-		for (cntr=0; cntr<32; ++cntr)
-			((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
-		ret = 0; 
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ptrace32.c linux-2.4.21-rc3/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.20/arch/ppc64/kernel/ptrace32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/ptrace32.c	2003-05-22 22:06:49.000000000 +0000
@@ -228,9 +228,9 @@
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		        if (numReg == PT_FPSCR) 
-			        tmp_reg_value = ((unsigned int *)child->thread.fpscr);
+			        tmp_reg_value = ((unsigned long *)child->thread.fpscr);
 		        else 
-			        tmp_reg_value = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
+			        tmp_reg_value = ((unsigned long *)child->thread.fpr)[numReg - PT_FPR0];
 		} else { /* register within PT_REGS struct */
 		    tmp_reg_value = get_reg(child, numReg);
 		} 
@@ -395,6 +395,74 @@
 		ret = ptrace_detach(child, data);
 		break;
 
+	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+
+
 	default:
 		ret = -EIO;
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtas-proc.c linux-2.4.21-rc3/arch/ppc64/kernel/rtas-proc.c
--- linux-2.4.20/arch/ppc64/kernel/rtas-proc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/rtas-proc.c	2003-05-22 22:06:41.000000000 +0000
@@ -162,26 +162,26 @@
 		size_t count, loff_t *ppos);
 
 struct file_operations ppc_rtas_poweron_operations = {
-	read:		ppc_rtas_poweron_read,
-	write:		ppc_rtas_poweron_write
+	.read =		ppc_rtas_poweron_read,
+	.write =	ppc_rtas_poweron_write
 };
 struct file_operations ppc_rtas_progress_operations = {
-	read:		ppc_rtas_progress_read,
-	write:		ppc_rtas_progress_write
+	.read =		ppc_rtas_progress_read,
+	.write =	ppc_rtas_progress_write
 };
 
 struct file_operations ppc_rtas_clock_operations = {
-	read:		ppc_rtas_clock_read,
-	write:		ppc_rtas_clock_write
+	.read =		ppc_rtas_clock_read,
+	.write =	ppc_rtas_clock_write
 };
 
 struct file_operations ppc_rtas_tone_freq_operations = {
-	read:		ppc_rtas_tone_freq_read,
-	write:		ppc_rtas_tone_freq_write
+	.read =		ppc_rtas_tone_freq_read,
+	.write =	ppc_rtas_tone_freq_write
 };
 struct file_operations ppc_rtas_tone_volume_operations = {
-	read:		ppc_rtas_tone_volume_read,
-	write:		ppc_rtas_tone_volume_write
+	.read =		ppc_rtas_tone_volume_read,
+	.write =	ppc_rtas_tone_volume_write
 };
 
 int ppc_rtas_find_all_sensors (void);
@@ -200,7 +200,7 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == 0) || (naca->platform == PLATFORM_ISERIES_LPAR)) {
+	if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtas.c linux-2.4.21-rc3/arch/ppc64/kernel/rtas.c
--- linux-2.4.20/arch/ppc64/kernel/rtas.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/rtas.c	2003-05-22 22:06:47.000000000 +0000
@@ -53,11 +53,14 @@
  */
 
 struct rtas_t rtas = { 
-	lock: SPIN_LOCK_UNLOCKED
+	.lock = SPIN_LOCK_UNLOCKED
 };
 
 extern unsigned long reloc_offset(void);
 
+spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED;
+char rtas_data_buf[RTAS_DATA_BUF_SIZE];
+
 void
 phys_call_rtas(int token, int nargs, int nret, ...)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtasd.c linux-2.4.21-rc3/arch/ppc64/kernel/rtasd.c
--- linux-2.4.20/arch/ppc64/kernel/rtasd.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/rtasd.c	2003-05-22 22:06:26.000000000 +0000
@@ -113,10 +113,10 @@
 }
 
 struct file_operations proc_rtas_log_operations = {
-	read:		rtas_log_read,
-	poll:		rtas_log_poll,
-	open:		rtas_log_open,
-	release:	rtas_log_release,
+	.read =		rtas_log_read,
+	.poll =		rtas_log_poll,
+	.open =		rtas_log_open,
+	.release =	rtas_log_release,
 };
 
 
@@ -623,25 +623,27 @@
 }
 
 #define MAX_LOG_DEBUG 10
+#define MAX_LOG_DEBUG_LEN 900
 /* Print log debug data.  This appears after the location code.
  * We limit the number of debug logs in case the data is somehow corrupt.
  */
 static void printk_log_debug(char *buf)
 {
-	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 8);
+	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 4);
 	int len, n, logged;
 
 	logged = 0;
-	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) != 2) {
-		/* len includes 2-byte length thus len == 2 is the end */
-		printk("RTAS: Log Debug: ");
-		if (len >= 4)	/* next 2 bytes are an ascii code */
-			printk("%c%c ", p[2], p[3]);
+	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) >= 4) {
+		if (len > MAX_LOG_DEBUG_LEN)
+			len = MAX_LOG_DEBUG_LEN;	/* bound it */
+		printk("RTAS: Log Debug: %c%c ", p[2], p[3]);
 		for (n=4; n < len; n++)
 			printk("%02x", p[n]);
 		printk("\n");
-		p += len;
+		p = (unsigned char *)_ALIGN((unsigned long)p+len, 4);
 		logged++;
+		if (len == MAX_LOG_DEBUG_LEN)
+			return;	/* no point continuing */
 	}
 	if (logged == 0)
 		printk("RTAS: no log debug data present\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtc.c linux-2.4.21-rc3/arch/ppc64/kernel/rtc.c
--- linux-2.4.20/arch/ppc64/kernel/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/rtc.c	2003-05-22 22:06:47.000000000 +0000
@@ -178,12 +178,12 @@
  *	The various file operations we support.
  */
 static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	llseek:		rtc_llseek,
-	read:		rtc_read,
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release,
+	.owner =	THIS_MODULE,
+	.llseek =	rtc_llseek,
+	.read =		rtc_read,
+	.ioctl =	rtc_ioctl,
+	.open =		rtc_open,
+	.release =	rtc_release,
 };
 
 static struct miscdevice rtc_dev=
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/scanlog.c linux-2.4.21-rc3/arch/ppc64/kernel/scanlog.c
--- linux-2.4.20/arch/ppc64/kernel/scanlog.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/scanlog.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,234 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      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.
+ *
+ * scan-log-data driver for PPC64  Todd Inglett <tinglett@vnet.ibm.com>
+ *
+ * When ppc64 hardware fails the service processor dumps internal state
+ * of the system.  After a reboot the operating system can access a dump
+ * of this data using this driver.  A dump exists if the device-tree
+ * /chosen/ibm,scan-log-data property exists.
+ *
+ * This driver exports /proc/ppc64/scan-log-dump which can be read.
+ * The driver supports only sequential reads.
+ *
+ * The driver looks at a write to the driver for the single word "reset".
+ * If given, the driver will reset the scanlog so the platform can free it.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "scanlog"
+
+/* Status returns from ibm,scan-log-dump */
+#define SCANLOG_COMPLETE 0
+#define SCANLOG_HWERROR -1
+#define SCANLOG_CONTINUE 1
+
+#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0)
+
+static int scanlog_debug;
+static unsigned int ibm_scan_log_dump;			/* RTAS token */
+static struct proc_dir_entry *proc_ppc64_scan_log_dump;	/* The proc file */
+
+
+static ssize_t scanlog_read(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+	unsigned long status;
+	unsigned long len, off;
+	unsigned int wait_time;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: read failed no data\n");
+		return -EIO;
+	}
+
+	if (count > RTAS_DATA_BUF_SIZE)
+		count = RTAS_DATA_BUF_SIZE;
+
+	if (count < 1024) {
+		/* This is the min supported by this RTAS call.  Rather
+		 * than do all the buffering we insist the user code handle
+		 * larger reads.  As long as cp works... :)
+		 */
+		printk(KERN_ERR "scanlog: cannot perform a small read (%ld)\n", count);
+		return -EINVAL;
+	}
+
+	if (verify_area(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	for (;;) {
+		wait_time = HZ/2;	/* default wait if no data */
+		spin_lock(&rtas_data_buf_lock);
+		memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
+		status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
+				   __pa(rtas_data_buf), count);
+		memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+		spin_unlock(&rtas_data_buf_lock);
+
+		DEBUG("status=%ld, data[0]=%x, data[1]=%x, data[2]=%x\n",
+		      status, data[0], data[1], data[2]);
+		switch (status) {
+		    case SCANLOG_COMPLETE:
+			DEBUG("hit eof\n");
+			return 0;
+		    case SCANLOG_HWERROR:
+			DEBUG("hardware error reading scan log data\n");
+			return -EIO;
+		    case SCANLOG_CONTINUE:
+			/* We may or may not have data yet */
+			len = data[1];
+			off = data[2];
+			if (len > 0) {
+				if (copy_to_user(buf, ((char *)data)+off, len))
+					return -EFAULT;
+				return len;
+			}
+			/* Break to sleep default time */
+			break;
+		    default:
+			if (status > 9900 && status <= 9905) {
+				/* No data.  RTAS is hinting at a delay required
+				 * between 1-100000 milliseconds
+				 */
+				int ms = 1;
+				for (; status > 9900; status--)
+					ms = ms * 10;
+				/* Use microseconds for reasonable accuracy */
+				ms *= 1000;
+				wait_time = ms / (1000000/HZ); /* round down is fine */
+				/* Fall through to sleep */
+			} else {
+				printk(KERN_ERR "scanlog: unknown error from rtas: %ld\n", status);
+				return -EIO;
+			}
+		}
+		/* Apparently no data yet.  Wait and try again. */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(wait_time);
+	}
+	/*NOTREACHED*/
+}
+
+static ssize_t scanlog_write(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+	unsigned long status;
+
+	if (buf) {
+		if (strncmp(buf, "reset", 5) == 0) {
+			DEBUG("reset scanlog\n");
+			status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0);
+			DEBUG("rtas returns %ld\n", status);
+		} else if (strncmp(buf, "debugon", 7) == 0) {
+			printk(KERN_ERR "scanlog: debug on\n");
+			scanlog_debug = 1;
+		} else if (strncmp(buf, "debugoff", 8) == 0) {
+			printk(KERN_ERR "scanlog: debug off\n");
+			scanlog_debug = 0;
+		}
+	}
+	return count;
+}
+
+static int scanlog_open(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: open failed no data\n");
+		return -EIO;
+	}
+	if (data[0] != 0) {
+		/* This imperfect test stops a second copy of the
+		 * data (or a reset while data is being copied)
+		 */
+		return -EBUSY;
+	}
+
+	data[0] = 0;	/* re-init so we restart the scan */
+
+	return 0;
+}
+
+static int scanlog_release(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: release failed no data\n");
+		return -EIO;
+	}
+	data[0] = 0;
+
+	return 0;
+}
+
+struct file_operations scanlog_fops = {
+	owner:		THIS_MODULE,
+	read:		scanlog_read,
+	write:		scanlog_write,
+	open:		scanlog_open,
+	release:	scanlog_release,
+};
+
+int __init scanlog_init(void)
+{
+	struct proc_dir_entry *ent;
+
+	ibm_scan_log_dump = rtas_token("ibm,scan-log-dump");
+	if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ERR "scan-log-dump not implemented on this system\n");
+		return -EIO;
+	}
+
+	ent = create_proc_entry("ppc64/scan-log-dump", S_IRUSR, NULL);
+	if (ent) {
+		ent->proc_fops = &scanlog_fops;
+		/* Ideally we could allocate a buffer < 4G */
+		ent->data = kmalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+		if (!ent->data) {
+			printk(KERN_ERR "Failed to allocate a buffer\n");
+			remove_proc_entry("scan-log-dump", ent->parent);
+			return -ENOMEM;
+		}
+		((unsigned int *)ent->data)[0] = 0;
+	} else {
+		printk(KERN_ERR "Failed to create ppc64/scan-log-dump proc entry\n");
+		return -EIO;
+	}
+	proc_ppc64_scan_log_dump = ent;
+
+	return 0;
+}
+
+void __exit scanlog_cleanup(void)
+{
+	if (proc_ppc64_scan_log_dump) {
+		if (proc_ppc64_scan_log_dump->data)
+		    kfree(proc_ppc64_scan_log_dump->data);
+		remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent);
+	}
+}
+
+module_init(scanlog_init);
+module_exit(scanlog_cleanup);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/setup.c linux-2.4.21-rc3/arch/ppc64/kernel/setup.c
--- linux-2.4.20/arch/ppc64/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/setup.c	2003-05-22 22:06:39.000000000 +0000
@@ -37,12 +37,15 @@
 #include <asm/paca.h>
 #include <asm/ppcdebug.h>
 #include <asm/time.h>
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
 
 extern unsigned long klimit;
 /* extern void *stab; */
 extern HTAB htab_data;
 extern unsigned long loops_per_jiffy;
-extern int preferred_console;	/* from kernel/printk.c */
+extern int blk_nohighio;
 
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
@@ -89,26 +92,6 @@
 struct machdep_calls ppc_md;
 
 /*
- * Perhaps we can put the pmac screen_info[] here
- * on pmac as well so we don't need the ifdef's.
- * Until we get multiple-console support in here
- * that is.  -- Cort
- * Maybe tie it to serial consoles, since this is really what
- * these processors use on existing boards.  -- Dan
- */ 
-struct screen_info screen_info = {
-	0, 25,			/* orig-x, orig-y */
-	0,			/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-	80,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-	25,			/* orig-video-lines */
-	1,			/* orig-video-isVGA */
-	16			/* orig-video-points */
-};
-
-/*
  * These are used in binfmt_elf.c to put aux entries on the stack
  * for each elf executable being started.
  */
@@ -116,7 +99,7 @@
 int icache_bsize;
 int ucache_bsize;
 
-static struct console udbg_console = {
+struct console udbg_console = {
 	name:	"udbg",
 	write:	udbg_console_write,
 	flags:	CON_PRINTBUFFER,
@@ -135,9 +118,9 @@
 
 	/* pSeries systems are identified in prom.c via OF. */
 	if ( itLpNaca.xLparInstalled == 1 )
-		naca->platform = PLATFORM_ISERIES_LPAR;
+		systemcfg->platform = PLATFORM_ISERIES_LPAR;
 	
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 	case PLATFORM_ISERIES_LPAR:
 		iSeries_init_early();
 		break;
@@ -161,38 +144,36 @@
 #endif
 	}
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		register_console(&udbg_console);
-		preferred_console = -1;
+		udbg_printf("---- start early boot console ----\n");
 	}
 
 	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
 
 	printk("-----------------------------------------------------\n");
-	printk("naca                       = 0x%p\n", naca);
-	printk("naca->processorCount       = 0x%x\n", naca->processorCount);
-	printk("naca->physicalMemorySize   = 0x%lx\n", naca->physicalMemorySize);
-	printk("naca->dCacheL1LineSize     = 0x%x\n", naca->dCacheL1LineSize);
-	printk("naca->dCacheL1LogLineSize  = 0x%x\n", naca->dCacheL1LogLineSize);
-	printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage);
-	printk("naca->iCacheL1LineSize     = 0x%x\n", naca->iCacheL1LineSize);
-	printk("naca->iCacheL1LogLineSize  = 0x%x\n", naca->iCacheL1LogLineSize);
-	printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage);
-	printk("naca->pftSize              = 0x%lx\n", naca->pftSize);
-	printk("naca->debug_switch         = 0x%lx\n", naca->debug_switch);
-	printk("naca->interrupt_controller = 0x%lx\n", naca->interrupt_controller);
-	printk("htab_data.htab             = 0x%p\n", htab_data.htab);
-	printk("htab_data.num_ptegs        = 0x%lx\n", htab_data.htab_num_ptegs);
+	printk("naca                          = 0x%p\n", naca);
+	printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
+	printk("naca->paca                    = 0x%lx\n\n", naca->paca);
+	printk("systemcfg                     = 0x%p\n", systemcfg);
+	printk("systemcfg->platform           = 0x%x\n", systemcfg->platform);
+	printk("systemcfg->processor          = 0x%x\n", systemcfg->processor);
+	printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
+	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
+	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
+	printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
+	printk("htab_data.htab                = 0x%p\n", htab_data.htab);
+	printk("htab_data.num_ptegs           = 0x%lx\n", htab_data.htab_num_ptegs);
 	printk("-----------------------------------------------------\n");
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
 		chrp_init(r3, r4, r5, r6, r7);
 	}
 
 	mm_init_ppc64();
 
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 	    case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
 		break;
@@ -206,14 +187,13 @@
 
 /* This is called just before console_init().
  * It will be obsolete when Linux gets real early console support (2.5?)
- * We need to hack preferred_console to retain the correct behavior
  */
 void setup_before_console_init(void)
 {
-	if (naca->platform & PLATFORM_PSERIES) {
-		int save = preferred_console;
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		unregister_console(&udbg_console);
-		preferred_console = save;
+		udbg_console.next = NULL;
+		udbg_printf("---- end early boot console ----\n");
 	}
 }
 
@@ -298,7 +278,7 @@
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
 		struct device_node *cpu_node;
 		int *fp;
 
@@ -333,18 +313,18 @@
 {
 }
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start =c_start,
+	.next =	c_next,
+	.stop =	c_stop,
+	.show =	show_cpuinfo,
 };
 
 /*
- * Fetch the cmd_line from open firmware. */
+ * Fetch the cmd_line from open firmware. 
+ */
 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
 		  unsigned long r6, unsigned long r7)
 {
-	struct device_node *chosen;
 	char *p;
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -356,6 +336,40 @@
 	}
 #endif
 
+	/* Hack -- add console=ttySn,9600 if necessary */
+	if(strstr(cmd_line, "console=") == NULL) {
+		struct device_node *prom_stdout = find_path_device(of_stdout_device);
+		u32 *reg;
+		int i;
+		char *name, *val = NULL;
+		printk("of_stdout_device %s\n", of_stdout_device);
+		if (prom_stdout) {
+			name = (char *)get_property(prom_stdout, "name", NULL);
+			if (name) {
+				if (strcmp(name, "serial") == 0) {
+					reg = (u32 *)get_property(prom_stdout, "reg", &i);
+					if (i > 8) {
+						switch (reg[1]) {
+						    case 0x3f8: val = "ttyS0,9600"; break; 
+						    case 0x2f8: val = "ttyS1,9600"; break; 
+						    case 0x898: val = "ttyS2,9600"; break; 
+						    case 0x890: val = "ttyS3,9600"; break; 
+						}
+					}
+				} else if (strcmp(name, "vty") == 0) {
+					/* pSeries LPAR virtual console */
+					val = "hvc0";
+				}
+				if (val) {
+					i = strlen(cmd_line);
+					sprintf(cmd_line + i, " AUTOCONSOLE console=%s", val);
+					printk("console= not found, add console=%s\ncmd_line is now %s\n",
+					       val, cmd_line);
+				}
+			}
+		}
+	}	
+
 	/* Look for mem= option on command line */
 	if (strstr(cmd_line, "mem=")) {
 		char *q;
@@ -457,6 +471,7 @@
 }	
 
 extern void (*calibrate_delay)(void);
+extern void sort_exception_table(void);
 
 /*
  * Called into from start_kernel, after lock_kernel has been called.
@@ -469,6 +484,8 @@
 	extern char _etext[], _edata[];
 	extern void do_init_bootmem(void);
 
+	blk_nohighio = 1;
+
 	calibrate_delay = ppc64_calibrate_delay;
 
 	ppc64_boot_msg(0x12, "Setup Arch");
@@ -494,8 +511,8 @@
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	dcache_bsize = naca->dCacheL1LineSize; 
-	icache_bsize = naca->iCacheL1LineSize; 
+	dcache_bsize = systemcfg->dCacheL1LineSize; 
+	icache_bsize = systemcfg->iCacheL1LineSize; 
 
 	/* reboot on panic */
 	panic_timeout = 180;
@@ -515,106 +532,10 @@
 	ppc_md.setup_arch();
 
 	paging_init();
+	sort_exception_table();
 	ppc64_boot_msg(0x15, "Setup Done");
 }
 
-#ifdef CONFIG_IDE
-
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc64_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	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 < 21; 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);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power=__le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 15; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 29; 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);
-}
-#endif
 
 /* ToDo: do something useful if ppc_md is not yet setup. */
 #define PPC64_LINUX_FUNCTION 0x0f000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/signal.c linux-2.4.21-rc3/arch/ppc64/kernel/signal.c
--- linux-2.4.20/arch/ppc64/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/signal.c	2003-05-22 22:06:52.000000000 +0000
@@ -43,24 +43,44 @@
 #endif
 
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define FP_REGS_SIZE	sizeof(elf_fpregset_t)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
+#define TRAMP_TRACEBACK	3
+#define TRAMP_SIZE	6
+
+/*
+ * When we have signals to deliver, we set up on the user stack,
+ * going down from the original stack pointer:
+ *	1) a sigframe/rt_sigframe struct which contains the sigcontext/ucontext	
+ *	2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller
+ *	   frame for the signal handler.
  */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
+struct sigframe {
+	/* sys_sigreturn requires the sigcontext be the first field */
+	struct sigcontext sc;
+	unsigned int tramp[TRAMP_SIZE];
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
+struct rt_sigframe {
+	/* sys_rt_sigreturn requires the ucontext be the first field */
+	struct ucontext uc;
+	unsigned long _unused[2];
+	unsigned int tramp[TRAMP_SIZE];
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
 extern long sys_wait4(pid_t pid, unsigned int *stat_addr,
 		     int options, /*unsigned long*/ struct rusage *ru);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+int
+copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
@@ -95,18 +115,16 @@
 	}
 }
 
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+asmlinkage long
+sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
 	       struct pt_regs *regs)
 {
 	sigset_t saveset;
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
-
 
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sigmask_lock);
@@ -115,7 +133,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -132,16 +152,13 @@
 	}
 }
 
-long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
+asmlinkage long
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
 		  int p7, struct pt_regs *regs)
 {
 	sigset_t saveset, newset;
 
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-	
-  /* XXX: Don't preclude handling different sized sigset_t's.  */
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset_t))
 		return -EINVAL;
 
@@ -155,7 +172,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -164,31 +183,24 @@
 	}
 }
 
-
-
-asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+asmlinkage long
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r5,
+		unsigned long r6, unsigned long r7, unsigned long r8,
+		struct pt_regs *regs)
 {
-  struct pt_regs *regs = (struct pt_regs *) &uss;
-  
-  PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n",
-          current->pid, current, current->comm);
-
-  return do_sigaltstack(uss, uoss, regs->gpr[1]);
+        return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
-long sys_sigaction(int sig, const struct old_sigaction *act,
+asmlinkage long
+sys_sigaction(int sig, const struct old_sigaction *act,
 	      struct old_sigaction *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
 
-        PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
- 
-
 	if (act) {
 		old_sigset_t mask;
+
 		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
@@ -199,7 +211,6 @@
 	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
 	if (!ret && oact) {
 		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
@@ -209,193 +220,212 @@
 		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
-
- 
-
 	return ret;
 }
 
 /*
- * When we have signals to deliver, we set up on the
- * user stack, going down from the original stack pointer:
- *	a sigregs struct
- *	one or more sigcontext structs
- *	a gap of __SIGNAL_FRAMESIZE bytes
- *
- * Each of these things must be a multiple of 16 bytes in size.
- *
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
+ * Set up the sigcontext for the signal frame.
  */
-struct sigregs {
-	elf_gregset_t	gp_regs;
-	double		fp_regs[ELF_NFPREG];
-	unsigned int	tramp[2];
-	/* 64 bit API allows for 288 bytes below sp before 
-	   decrementing it. */
-	int		abigap[72];
-};
 
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+		 int signr, sigset_t *set, unsigned long handler)
+{
+	int err = 0;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->msr = current->thread.saved_msr | current->thread.fpexc_mode;
+	current->thread.saved_softe = regs->softe;
+
+	err |= __put_user(&sc->gp_regs, &sc->regs);
+	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
+	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
+	err |= __put_user(signr, &sc->signal);
+	err |= __put_user(handler, &sc->handler);
+	if (set != NULL)
+		err |=  __put_user(set->sig[0], &sc->oldmask);
 
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	current->thread.fpscr = 0;
 
-struct rt_sigframe
+	return err;
+}
+
+/*
+ * Restore the sigcontext from the signal frame.
+ */
+
+static int
+restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
-	unsigned long	_unused[2];
-	struct siginfo *pinfo;
-	void *puc;
-	struct siginfo info;
-	struct ucontext uc;
-};
+	unsigned int err = 0;
 
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
+	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+	if (set != NULL)
+		err |=  __get_user(set->sig[0], &sc->oldmask);
+
+	/* Don't allow the signal handler to change these modulo FE{0,1} */
+	regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->softe = current->thread.saved_softe;
+
+	return err;
+}
 
 /*
- *  When we have rt signals to deliver, we set up on the
- *  user stack, going down from the original stack pointer:
- *	   a sigregs struct
- *	   one rt_sigframe struct (siginfo + ucontext)
- *	   a gap of __SIGNAL_FRAMESIZE bytes
- *
- *  Each of these things must be a multiple of 16 bytes in size.
- *
+ * Allocate space for the signal frame
  */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+        unsigned long newsp;
 
-int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		     unsigned long r6, unsigned long r7, unsigned long r8,
-		     struct pt_regs *regs)
-{
-	struct rt_sigframe *rt_sf;
-	struct sigcontext_struct sigctx;
-	struct sigregs *sr;
-	int ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+        /* Default to using normal stack */
+        newsp = regs->gpr[1];
+
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(regs->gpr[1]))
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
+	}
+
+        return (void *)((newsp - frame_size) & -8ul);
+}
+
+static int
+setup_trampoline(unsigned int syscall, unsigned int *tramp)
+{
+	int i, err = 0;
+
+	/* addi r1, r1, __SIGNAL_FRAMESIZE  # Pop the dummy stackframe */
+	err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]);
+	/* li r0, __NR_[rt_]sigreturn| */
+	err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]);
+	/* sc */
+	err |= __put_user(0x44000002UL, &tramp[2]);
+
+	/* Minimal traceback info */
+	for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++)
+		err |= __put_user(0, &tramp[i]);
+
+	if (!err)
+		flush_icache_range((unsigned long) &tramp[0],
+			   (unsigned long) &tramp[TRAMP_SIZE]);
+
+	return err;
+}
+
+
+asmlinkage int
+sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		 unsigned long r6, unsigned long r7, unsigned long r8,
+		 struct pt_regs *regs)
+{
+	struct ucontext *uc = (struct ucontext *)regs->gpr[1];
 	sigset_t set;
 	stack_t st;
-	unsigned long prevsp;
 
-	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
-	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
-	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+	if (verify_area(VERIFY_READ, uc, sizeof(*uc)))
 		goto badframe;
+
+	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	rt_sf++;			/* Look at next rt_sigframe */
-	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers -
-		 * sigctx is initialized to point to the 
-		 * preamble frame (where registers are stored) 
-		 * see handle_signal()
-		 */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-		/* This function sets back the stack flags into
-		   the current task structure.  */
-		sys_sigaltstack(&st, NULL);
-
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		/* Set up registers for next signal handler */
-		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		/* Get the siginfo   */
-		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
-		/* Get the ucontext */
-		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
-		regs->gpr[6] = (unsigned long) rt_sf;
-
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	if (restore_sigcontext(regs, NULL, &uc->uc_mcontext))
+		goto badframe;
+
+	if (__copy_from_user(&st, &uc->uc_stack, sizeof(st)))
+		goto badframe;
+
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
+
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }
 
 static void
-setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
-	       signed long newsp)
+setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-        struct funct_descr_entry {
-                     unsigned long entry;
-                     unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct rt_sigframe *frame;
+	unsigned long newsp;
+	int err = 0;
 
-	/* Set up preamble frame */
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])	/* li r0, __NR_rt_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
-	*/
-	newsp -= __SIGNAL_FRAMESIZE;
-
-        if ( get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) {
-		goto badframe;
-	}
-
-        funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
-        
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &funct_desc_ptr->entry)
-            || get_user(regs->gpr[2], &funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
-	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
-		goto badframe;
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
 
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->gpr[1]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
+				(unsigned long)ka->sa.sa_handler);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace. */
+	err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
+	if (err)
+		goto give_sigsegv;
+
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
+
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
 	regs->gpr[1] = newsp;
-	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->link = (unsigned long) frame->tramp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo);
+	err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc);
+	regs->gpr[6] = (unsigned long) frame;
+	if (err)
+		goto give_sigsegv;
 
-	
 	return;
 
-badframe:
+give_sigsegv:
 #if DEBUG_SIG
-	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
-	       regs, frame, newsp);
+	printk("badframe in setup_rt_frame, regs=%p frame=%p, newsp=0x%lx\n",
+		regs, frame, newsp);
 #endif
 	do_exit(SIGSEGV);
 }
@@ -403,131 +433,79 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7, unsigned long r8,
-		   struct pt_regs *regs)
-{
-	struct sigcontext_struct *sc, sigctx;
-	struct sigregs *sr;
-	long ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+asmlinkage long
+sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7, unsigned long r8,
+	      struct pt_regs *regs)
+{
+	struct sigcontext *sc = (struct sigcontext *)regs->gpr[1];
 	sigset_t set;
-	unsigned long prevsp;
 
-        sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
+		goto badframe;
+
+	if (restore_sigcontext(regs, &set, sc))
 		goto badframe;
 
-	set.sig[0] = sigctx.oldmask;
-#if _NSIG_WORDS > 1
-	set.sig[1] = sigctx._unused[3];
-#endif
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	sc++;			/* Look at next sigcontext */
-	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-
-		ret = regs->result;
-
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }	
 
-/*
- * Set up a signal frame.
- */
+
 static void
-setup_frame(struct pt_regs *regs, struct sigregs *frame,
-            unsigned long newsp)
+setup_frame(int signr, struct k_sigaction *ka, sigset_t *set,
+	    struct pt_regs *regs)
 {
-
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-	struct funct_descr_entry {
-		unsigned long entry;
-		unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct sigframe *frame;
+	unsigned long newsp;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
-  
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
 
-	newsp -= __SIGNAL_FRAMESIZE;
-	if ( get_user(temp_ptr, &sc->handler))
-		goto badframe;
-  
-	funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
+	err |= setup_sigcontext(&frame->sc, regs, signr, set,
+				(unsigned long)ka->sa.sa_handler);
 
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, & funct_desc_ptr ->entry)
-	    || get_user(regs->gpr[2],& funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &sc->signal))
+	/* Set up to return from userspace. */
+	err |= setup_trampoline(__NR_sigreturn, &frame->tramp[0]);
+	if (err)
 		goto badframe;
-	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long) sc;
-	regs->link = (unsigned long) frame->tramp;
 
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
 
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n",
-	       regs->gpr[1], regs->gpr[4], regs->link);
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
+	regs->gpr[1] = newsp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	regs->gpr[4] = (unsigned long) &frame->sc;
+	if (err)
+		goto badframe;
 
 	return;
 
- badframe:
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+badframe:
 #if DEBUG_SIG
 	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
@@ -540,61 +518,13 @@
  */
 static void
 handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc;
-        struct rt_sigframe *rt_sf;
-
-	if (regs->trap == 0x0C00 /* System Call! */
-	    && ((int)regs->result == -ERESTARTNOHAND ||
-		((int)regs->result == -ERESTARTSYS &&
-		 !(ka->sa.sa_flags & SA_RESTART))))
-		regs->result = -EINTR;
-        /* Set up Signal Frame */
-     
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		/* Put a Real Time Context onto stack */
-		*newspp -= sizeof(*rt_sf);
-		rt_sf = (struct rt_sigframe *) *newspp;
-		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
-			goto badframe;
-                
-
-		if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
-		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
-		    || __put_user(&rt_sf->uc, &rt_sf->puc)
-		    /* Put the siginfo */
-		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
-		    /* Create the ucontext */
-		    || __put_user(0, &rt_sf->uc.uc_flags)
-		    || __put_user(0, &rt_sf->uc.uc_link)
-		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
-		    || __put_user(sas_ss_flags(regs->gpr[1]), 
-				  &rt_sf->uc.uc_stack.ss_flags)
-		    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
-		    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
-		    /* mcontext.regs points to preamble register frame */
-		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
-		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
-			goto badframe;
-               
-	} else {
-	        /* Put another sigcontext on the stack */
-                *newspp -= sizeof(*sc);
-        	sc = (struct sigcontext_struct *) *newspp;
-        	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-	        	goto badframe;
-
-        	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-	           || __put_user(oldset->sig[0], &sc->oldmask)
-#if _NSIG_WORDS > 1
-	           || __put_user(oldset->sig[1], &sc->_unused[3])
-#endif
-	           || __put_user((struct pt_regs *)frame, &sc->regs)
-	           || __put_user(sig, &sc->signal))
-	        	goto badframe;
-	}
+	/* Set up Signal Frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -606,49 +536,47 @@
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 	}
-	return;
-
-badframe:
-#if DEBUG_SIG
-	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
-	       regs, frame, *newspp);
-	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
-#endif
-	do_exit(SIGSEGV);
 }
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+static inline void
+syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
-	siginfo_t info;
-	struct k_sigaction *ka;
-	unsigned long frame, newsp;
-
-	/*
-	 * If the current thread is 32 bit - invoke the
-	 * 32 bit signal handling code
-	 */
-	if (current->thread.flags & PPC_FLAG_32BIT)
-		return do_signal32(oldset, regs);
-
-        if (!oldset)
-		oldset = &current->blocked;
+	switch ((int)regs->result) {
+		case -ERESTARTNOHAND:
+			/* ERESTARTNOHAND means that the syscall should only
+			   be restarted if there was no handler for the signal,
+			   and since we only get here if there is a handler,
+			   we dont restart */
+			regs->result = -EINTR;
+			break;
 
-	newsp = frame = 0;
+		case -ERESTARTSYS:
+			/* ERESTARTSYS means to restart the syscall if there is
+			   no handler or the handler was registered with SA_RESTART */
+			if (!(ka->sa.sa_flags & SA_RESTART)) {
+				regs->result = -EINTR;
+				break;
+			}
+		/* fallthrough */
+		case -ERESTARTNOINTR:
+			/* ERESTARTNOINTR means that the syscall should be
+			   called again after the signal handler returns */
+			regs->gpr[3] = regs->orig_gpr3;
+			regs->nip -= 4;
+			regs->result = 0;
+	}
+}
 
+static int
+get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
+{
 	for (;;) {
 		unsigned long signr;
+		struct k_sigaction *ka;
 
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
+		signr = dequeue_signal(&current->blocked, info);
 		spin_unlock_irq(&current->sigmask_lock);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm);
 
 		if (!signr)
 			break;
@@ -661,7 +589,8 @@
 			schedule();
 
 			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
+			signr = current->exit_code;
+			if (signr == 0)
 				continue;
 			current->exit_code = 0;
 
@@ -670,28 +599,24 @@
 				continue;
 
 			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+			if (signr != info->si_signo) {
+				info->si_signo = signr;
+				info->si_errno = 0;
+				info->si_code = SI_USER;
+				info->si_pid = current->p_pptr->pid;
+				info->si_uid = current->p_pptr->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
 			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
+				send_sig_info(signr, info, current);
 				continue;
 			}
 		}
 
 		ka = &current->sig->action[signr-1];
 
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler);
-
 		if (ka->sa.sa_handler == SIG_IGN) {
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n");
 			if (signr != SIGCHLD)
 				continue;
 			/* Check for SIGCHLD: it's special.  */
@@ -702,7 +627,6 @@
 
 		if (ka->sa.sa_handler == SIG_DFL) {
 			int exit_code = signr;
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n");
 
 			/* Init gets no signals it doesn't want.  */
 			if (current->pid == 1)
@@ -736,48 +660,60 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sig_exit(signr, exit_code, info);
 				/* NOTREACHED */
 			}
 		}
+		return signr;
+	}
+	return 0;
+}
 
-		if ( (ka->sa.sa_flags & SA_ONSTACK)
-		     && (! on_sig_stack(regs->gpr[1])))
-			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		else
-			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs);
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+
+int
+do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * If the current thread is 32 bit - invoke the
+	 * 32 bit signal handling code
+	 */
+	if (current->thread.flags & PPC_FLAG_32BIT)
+		return do_signal32(oldset, regs);
+
+        if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
+		struct k_sigaction *ka = &current->sig->action[signr-1];
 
 		/* Whee!  Actually deliver the signal.  */
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-                break;
+		if (regs->trap == 0x0C00)
+			syscall_restart(regs, ka);
+		handle_signal(signr, ka, &info, oldset, regs);
+		return 1;
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
 	    ((int)regs->result == -ERESTARTNOHAND ||
 	     (int)regs->result == -ERESTARTSYS ||
 	     (int)regs->result == -ERESTARTNOINTR)) {
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n");
 		regs->gpr[3] = regs->orig_gpr3;
 		regs->nip -= 4;		/* Back up & retry system call */
 		regs->result = 0;
 	}
 
-	if (newsp == frame)
-          {
-             PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n");
-             return 0;		/* no signals delivered */
-           }
-  
-     
-
-        if (ka->sa.sa_flags & SA_SIGINFO)
-             setup_rt_frame(regs, (struct sigregs *) frame, newsp);
-        else        
-	    setup_frame(regs, (struct sigregs *) frame, newsp);
-        PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n");
-	return 1;
+	return 0;
 }
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/signal32.c linux-2.4.21-rc3/arch/ppc64/kernel/signal32.c
--- linux-2.4.20/arch/ppc64/kernel/signal32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/signal32.c	2003-05-22 22:06:27.000000000 +0000
@@ -71,34 +71,41 @@
 };
 
 struct sigregs32 {
-    /***********************************************************************/
-    /* the gp_regs array is 32 bit representation of the pt_regs structure */
-    /*  that was stored on the kernle stack during the system call that    */
-    /*  was interrupted for the signal.                                    */
-    /*                                                                     */
-    /* Note that the entire pt_regs regs structure will fit in the gp_regs */
-    /*   structure because the ELF_NREG value is 48 for PPC and the pt_regs*/
-    /*   structure contains 44 registers                                   */
-    /*                                                                     */ 
-    /***********************************************************************/ 
+	/*
+	 * the gp_regs array is 32 bit representation of the pt_regs
+	 * structure that was stored on the kernle stack during the
+	 * system call that was interrupted for the signal.
+	 *
+	 * Note that the entire pt_regs regs structure will fit in
+	 * the gp_regs structure because the ELF_NREG value is 48 for
+	 * PPC and the pt_regs structure contains 44 registers
+	 */
 	elf_gregset_t32	gp_regs;
 	double		fp_regs[ELF_NFPREG];
 	unsigned int	tramp[2];
-	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
-	   and 18 fp regs below sp before decrementing it. */
+	/*
+	 * Programs using the rs6000/xcoff abi can save up to 19 gp
+	 * regs and 18 fp regs below sp before decrementing it.
+	 */
 	int		abigap[56];
 };
 
 
 struct rt_sigframe_32 {
-	/* Unused space at start of frame to allow for storing of stack pointers */
+	/*
+	 * Unused space at start of frame to allow for storing of
+	 * stack pointers
+	 */
 	unsigned long _unused;
-	/* This is a 32 bit pointer in user address space 
+	/*
+	 * This is a 32 bit pointer in user address space 
 	 *     it is a pointer to the siginfo stucture in the rt stack frame 
 	 */
 	u32 pinfo;
-	/* This is a 32 bit pointer in user address space */
-	/*     it is a pointer to the user context in the rt stack frame  */
+	/*
+	 * This is a 32 bit pointer in user address space
+	 * it is a pointer to the user context in the rt stack frame
+	 */
 	u32 puc;
 	struct siginfo32  info;
 	struct ucontext32 uc;
@@ -138,12 +145,9 @@
 	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
 	if (sig < 0)
-	{
 		sig = -sig;
-	}
 
-	if (act)
-	{
+	if (act) {
 		old_sigset_t32 mask;
 
 		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
@@ -214,15 +218,18 @@
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	
-	if (set && get_user (s, set)) return -EFAULT;
+	if (set && get_user(s, set))
+		return -EFAULT;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
 	set_fs (old_fs);
-	if (ret) return ret;
-	if (oset && put_user (s, oset)) return -EFAULT;
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
+	if (ret)
+		return ret;
+	if (oset && put_user (s, oset))
+		return -EFAULT;
 	return 0;
 }
 
@@ -247,21 +254,24 @@
 		     unsigned long r6, unsigned long r7, unsigned long r8,
 		     struct pt_regs *regs)
 {
-	struct sigcontext32_struct *sc, sigctx;
+	struct sigcontext32 *sc, sigctx;
 	struct sigregs32 *sr;
 	int ret;
 	elf_gregset_t32 saved_regs;  /* an array of ELF_NGREG unsigned ints (32 bits) */
 	sigset_t set;
 	unsigned int prevsp;
+	int i;
 
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 
-	sc = (struct sigcontext32_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
+	sc = (struct sigcontext32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
 
-	/* Note that PPC32 puts the upper 32 bits of the sigmask in the  */
-	/*   unused part of the signal stackframe                        */
+	/*
+	 * Note that PPC32 puts the upper 32 bits of the sigmask in the
+	 * unused part of the signal stackframe
+	 */
 	set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3])<< 32);
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
@@ -272,77 +282,50 @@
 	sc++;			/* Look at next sigcontext */
 	/* If the next sigcontext is actually the sigregs (frame)  */
 	/*   - then no more sigcontexts on the user stack          */  
-	if (sc == (struct sigcontext32_struct*)(u64)sigctx.regs)
+	if (sc == (struct sigcontext32*)(u64)sigctx.regs)
 	{
 		/* Last stacked signal - restore registers */
 		sr = (struct sigregs32*)(u64)sigctx.regs;
 		if (regs->msr & MSR_FP )
 			giveup_fpu(current);
-		/* copy the 32 bit register values off the user stack */
-		/*   into the 32 bit register area                    */
+		/* 
+		 * Copy the 32 bit register values off the user stack
+		 * into the 32 bit register area
+		 */
 		if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
 			goto badframe;
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
-
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal
+		 * handler.  
+		 *
+		 * The entries in the elf_grepset have the same index as the
+		 * elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
-
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on
+		 * any calls into the kernel 
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+
+		/*
+		 *  restore the non gpr registers 
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-		/* Insure that the interrupt mode is 64 bit, during 32 bit execution.
-		 * (This is necessary because we only saved lower 32 bits of msr.)
+		/*
+		 * Insure that the interrupt mode is 64 bit, during 32 bit
+		 * execution. (This is necessary because we only saved
+		 * lower 32 bits of msr.)
 		 */
-		regs->msr = regs->msr | MSR_ISF;  /* When this thread is interrupted it should run in 64 bit mode. */
+		regs->msr = regs->msr | MSR_ISF;
 
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
@@ -378,6 +361,7 @@
 		if (get_user(prevsp, &sr->gp_regs[PT_R1])
 		    || put_user(prevsp, (unsigned int*) regs->gpr[1]))
 			goto badframe;
+		current->thread.fpscr = 0;
 	}
   
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm);
@@ -395,97 +379,51 @@
 setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
             unsigned int newsp)
 {
-	struct sigcontext32_struct *sc = (struct sigcontext32_struct *)(u64)newsp;
+	struct sigcontext32 *sc = (struct sigcontext32 *)(u64)newsp;
+	int i;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
-
-  /*****************************************************************************/
-  /* Copy the non gpr registers to the user stack                              */
-  /*****************************************************************************/
-
-	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
-			      sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
-# if 0
-	    || __copy_to_user(&frame->gp_regs[PT_MQ], (u32*)(&regs->gpr[PT_MQ])+1, sizeof(u32))
-#endif
-	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
-			      sizeof(u32)))
-		goto badframe;
-
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 * 
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < sizeof(struct pt_regs32)/sizeof(u32); i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
+	/*
+	 * Now copy the floating point registers onto the user stack 
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002U, &frame->tramp[1]))   /* sc */
+	    /* li r0, __NR_sigreturn */
+	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])
+	    /* sc */
+	    || __put_user(0x44000002U, &frame->tramp[1]))
 		goto badframe;
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
+	current->thread.fpscr = 0;      /* turn off all fp exceptions */
 
 	newsp -= __SIGNAL_FRAMESIZE32;
 	if (put_user(regs->gpr[1], (u32*)(u64)newsp)
@@ -494,12 +432,12 @@
 		goto badframe;
 
 	regs->gpr[1] = newsp & 0xFFFFFFFF;
-	/**************************************************************/
-	/* first parameter to the signal handler is the signal number */
-	/*  - the value is in gpr3                                    */  
-	/* second parameter to the signal handler is the sigcontext   */
-	/*   - set the value into gpr4                                */ 
-	/**************************************************************/
+	/*
+	 * first parameter to the signal handler is the signal number
+	 *  - the value is in gpr3
+	 * second parameter to the signal handler is the sigcontext
+	 *   - set the value into gpr4
+	 */
 	regs->gpr[4] = (unsigned long) sc;
 	regs->link = (unsigned long) frame->tramp;
 	return;
@@ -514,40 +452,40 @@
 }
 
 
-/****************************************************************************/
-/*  Start of RT signal support                                              */
-/*                                                                          */
-/*     sigset_t is 64 bits for rt signals                                   */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaction                sys32_rt_sigaction                        */
-/*       sigpending               sys32_rt_sigpending                       */
-/*       sigprocmask              sys32_rt_sigprocmask                      */
-/*       sigreturn                sys32_rt_sigreturn                        */
-/*       sigtimedwait             sys32_rt_sigtimedwait                     */
-/*       sigqueueinfo             sys32_rt_sigqueueinfo                     */
-/*       sigsuspend               sys32_rt_sigsuspend                       */ 
-/*                                                                          */
-/*  Other routines                                                          */
-/*        setup_rt_frame32                                                  */
-/*        siginfo64to32                                                     */
-/*        siginfo32to64                                                     */
-/*                                                                          */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of RT signal support
+ *
+ *     sigset_t is 64 bits for rt signals
+ *
+ *  System Calls
+ *       sigaction                sys32_rt_sigaction
+ *       sigpending               sys32_rt_sigpending
+ *       sigprocmask              sys32_rt_sigprocmask
+ *       sigreturn                sys32_rt_sigreturn
+ *       sigtimedwait             sys32_rt_sigtimedwait
+ *       sigqueueinfo             sys32_rt_sigqueueinfo
+ *       sigsuspend               sys32_rt_sigsuspend
+ *
+ *  Other routines
+ *        setup_rt_frame32
+ *        copy_siginfo_to_user32
+ *        siginfo32to64
+ */
 
 
-// This code executes after the rt signal handler in 32 bit mode has completed and 
-//  returned  
+/*
+ * This code executes after the rt signal handler in 32 bit mode has
+ * completed and returned  
+ */
 long sys32_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
 			unsigned long r6, unsigned long r7, unsigned long r8,
 			struct pt_regs * regs)
 {
 	struct rt_sigframe_32 *rt_stack_frame;
-	struct sigcontext32_struct sigctx;
+	struct sigcontext32 sigctx;
 	struct sigregs32 *signalregs;
  
-	int ret;
+	int i, ret;
 	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
 	sigset_t signal_set; 
 	stack_t stack;
@@ -560,12 +498,11 @@
 	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
 	    || copy_from_user(&signal_set, &rt_stack_frame->uc.uc_sigmask,sizeof(signal_set))
 	    || copy_from_user(&stack,&rt_stack_frame->uc.uc_stack,sizeof(stack)))
-	{
 		/* unable to copy from user storage */
 		goto badframe;
-	}
 
-	/* Unblock the signal that was processed 
+	/*
+	 * Unblock the signal that was processed 
 	 *   After a signal handler runs - 
 	 *     if the signal is blockable - the signal will be unblocked  
 	 *       ( sigkill and sigstop are not blockable)
@@ -582,76 +519,39 @@
 	 */
 	rt_stack_frame ++;
 
-	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs))
-	{
+	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs)) {
 		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
 		/* If currently owning the floating point - give them up */
 		if (regs->msr & MSR_FP)
-		{
 			giveup_fpu(current);
-		}
+
 		if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) 
-		{
 			goto badframe;
-		}
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
 
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal handler
+		 *
+		 * The entries in the elf_grepset have the same index as
+		 * the elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
- 
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on any
+		 * calls into the kernel
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+		/*
+		 * restore the non gpr registers
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
 		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
@@ -659,14 +559,18 @@
 		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
 		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
 		/* regs->softe is left unchanged (like MSR.EE) */
-		/******************************************************/
-		/* the DAR and the DSISR are only relevant during a   */
-		/*   data or instruction storage interrupt. The value */
-		/*   will be set to zero.                             */
-		/******************************************************/
+		/*
+		 * the DAR and the DSISR are only relevant during a
+		 *   data or instruction storage interrupt. The value
+		 *   will be set to zero.
+		 */
 		regs->dar = 0; 
 		regs->dsisr = 0;
 		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+		if (copy_from_user(current->thread.fpr, &signalregs->fp_regs, sizeof(signalregs->fp_regs))) 
+			goto badframe;
+
 		ret = regs->result;
 	}
 	else  /* more signals to go  */
@@ -696,6 +600,7 @@
 		{
 			goto badframe;
 		}
+		current->thread.fpscr = 0;
 
 	}
 
@@ -772,10 +677,12 @@
 extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
 					  size_t sigsetsize);
 
-/* Note: it is necessary to treat how as an unsigned int, 
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat how as an unsigned int, with the
+ * corresponding cast to a signed int to insure that the proper
+ * conversion (sign extension) between the register representation
+ * of a signed int (msr in 32-bit mode) and the register representation
+ * of a signed int (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigprocmask(u32 how, sigset32_t *set, sigset32_t *oset, size_t sigsetsize)
 {
@@ -802,7 +709,8 @@
 	ret = sys_rt_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL,
 				 sigsetsize); 
 	set_fs (old_fs);
-	if (ret) return ret;
+	if (ret)
+		return ret;
 	if (oset) {
 		switch (_NSIG_WORDS) {
 		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
@@ -853,7 +761,7 @@
 	memset (d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
+	d->si_code = s->si_code & 0xffff;
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
@@ -871,7 +779,7 @@
 	case SIGBUS:
 	case SIGFPE:
 	case SIGILL:
-		d->si_addr = (long)(s->si_addr);
+		d->si_addr = (unsigned int)(s->si_addr);
         break;
 	case SIGPOLL:
 		d->si_band = s->si_band;
@@ -917,12 +825,10 @@
 	}
 	set_fs (KERNEL_DS);
 	if (uts) 
-	{
 		ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
-	} else {
-		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts, sigsetsize);
-	}
-	
+	else
+		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts,
+				sigsetsize);
 	set_fs (old_fs);
 	if (ret >= 0 && uinfo) {
 		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
@@ -974,10 +880,12 @@
 
 extern asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
 
-/* Note: it is necessary to treat pid and sig as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat pid and sig as unsigned ints, with the
+ * corresponding cast to a signed int to insure that the proper conversion
+ * (sign extension) between the register representation of a signed int
+ * (msr in 32-bit mode) and the register representation of a signed int
+ * (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigqueueinfo(u32 pid, u32 sig, siginfo_t32 *uinfo)
 {
@@ -1012,9 +920,11 @@
 	if (copy_from_user(&s32, unewset, sizeof(s32)))
 		return -EFAULT;
 
-	/* Swap the 2 words of the 64-bit sigset_t (they are stored in the "wrong" endian in 32-bit user storage). */
-	switch (_NSIG_WORDS) 
-	{
+	/*
+	 * Swap the 2 words of the 64-bit sigset_t (they are stored
+	 * in the "wrong" endian in 32-bit user storage).
+	 */
+	switch (_NSIG_WORDS) {
 		case 4: newset.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 		case 3: newset.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 		case 2: newset.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
@@ -1029,22 +939,26 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(&saveset, regs))
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
 			return regs->gpr[3];
 	}
 }
 
 
-
-
-
-
-
-
 /*
  * Set up a rt signal frame.
  */
@@ -1054,87 +968,40 @@
 {
 	unsigned int copyreg4,copyreg5;
 	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
-
+	int i;
   
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
 
-	/*****************************************************************************/
-	/* Copy the non gpr registers to the user stack                              */
-	/*****************************************************************************/
-
-	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
-			      sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
-			      sizeof(u32)))
-		goto badframe;
-
-
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 *
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing.
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < sizeof(struct pt_regs32)/sizeof(u32); i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
 
+	/*
+	 * Now copy the floating point registers onto the user stack
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
 	    || __put_user(0x38000000U + __NR_rt_sigreturn, &frame->tramp[0])    /* li r0, __NR_rt_sigreturn */
@@ -1143,10 +1010,11 @@
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
-
+	current->thread.fpscr = 0;	/* turn off all fp exceptions */
   
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
+	/*
+	 * Retrieve rt_sigframe from stack and
+	 * set up registers for signal handler
 	*/
 	newsp -= __SIGNAL_FRAMESIZE32;
       
@@ -1160,17 +1028,12 @@
 
 	regs->gpr[4] = copyreg4;
 	regs->gpr[5] = copyreg5;
-
-   
 	regs->gpr[1] = newsp;
 	regs->gpr[6] = (unsigned long) rt_sf;
-
-
 	regs->link = (unsigned long) frame->tramp;
 
 	return;
 
-
  badframe:
 	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
 #if DEBUG_SIG
@@ -1189,7 +1052,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
 	      unsigned int *newspp, unsigned int frame)
 {
-	struct sigcontext32_struct *sc;
+	struct sigcontext32 *sc;
 	struct rt_sigframe_32 *rt_stack_frame;
 	siginfo_t32 siginfo32bit;
 
@@ -1231,14 +1094,15 @@
 			goto badframe; 
 		}
 	} else {
-		/* Put another sigcontext on the stack */
+		/* Put a sigcontext on the stack */
 		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext32_struct *)(u64)*newspp;
+		sc = (struct sigcontext32 *)(u64)*newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 			goto badframe;
-
-		/* Note the upper 32 bits of the signal mask are stored in the */
-		/*   unused part of the signal stack frame                     */  
+		/*
+		 * Note the upper 32 bits of the signal mask are stored
+		 * in the unused part of the signal stack frame
+		 */
 		if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)
 		    || __put_user(oldset->sig[0], &sc->oldmask)
 		    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])
@@ -1270,15 +1134,12 @@
 }
 
 
-/****************************************************************************/
-/*  Start Alternate signal stack support                                    */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaltatck               sys32_sigaltstack                         */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start Alternate signal stack support
+ *
+ *  System Calls
+ *       sigaltatck               sys32_sigaltstack
+ */
 
 
 asmlinkage int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, int p4, int p6,
@@ -1289,8 +1150,10 @@
 	mm_segment_t old_fs;
 	unsigned long sp;
 
-	/* set sp to the user stack on entry to the system call                  */
-	/*   the system call router sets R9 to the saved registers               */
+	/*
+	 * set sp to the user stack on entry to the system call
+	 * the system call router sets R9 to the saved registers
+	 */
 	sp = regs->gpr[1];
 
 	/*  Put new stack info in local 64 bit stack struct                      */ 
@@ -1314,15 +1177,14 @@
 
 
 
-/****************************************************************************/
-/*  Start of do_signal32 routine                                            */
-/*                                                                          */
-/*   This routine gets control when a pemding signal needs to be processed  */
-/*     in the 32 bit target thread -                                        */
-/*                                                                          */
-/*   It handles both rt and non-rt signals                                  */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of do_signal32 routine
+ *
+ *   This routine gets control when a pending signal needs to be processed
+ *     in the 32 bit target thread -
+ *
+ *   It handles both rt and non-rt signals
+ */
 
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
@@ -1445,9 +1307,8 @@
 
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
-		{
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		} else
+		else
 			newsp = regs->gpr[1];
 		newsp = frame = newsp - sizeof(struct sigregs32);
 
@@ -1466,15 +1327,12 @@
 	}
 
 	if (newsp == frame)
-	{
 		return 0;		/* no signals delivered */
-	}
-	// Invoke correct stack setup routine 
+
+	/* Invoke correct stack setup routine */
 	if (ka->sa.sa_flags & SA_SIGINFO) 
 		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
 	else
 		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
-
 	return 1;
-
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/smp.c linux-2.4.21-rc3/arch/ppc64/kernel/smp.c
--- linux-2.4.20/arch/ppc64/kernel/smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/smp.c	2003-05-22 22:06:50.000000000 +0000
@@ -224,7 +224,7 @@
 	ppc_md.smp_kick_cpu     = smp_iSeries_kick_cpu;
 	ppc_md.smp_setup_cpu    = smp_iSeries_setup_cpu;
 
-	naca->processorCount	= smp_iSeries_numProcs();
+	systemcfg->processorCount	= smp_iSeries_numProcs();
 }
 
 
@@ -255,10 +255,10 @@
 static int
 smp_chrp_probe(void)
 {
-	if (naca->processorCount > 1)
+	if (systemcfg->processorCount > 1)
 		openpic_request_IPIs();
 
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 static void
@@ -299,11 +299,11 @@
 	static atomic_t ready = ATOMIC_INIT(1);
 	static volatile int frozen = 0;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		/* timebases already synced under the hypervisor. */
 		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->tb_orig_stamp = tb_last_stamp;
 			/* Should update naca->stamp_xsec.
 			 * For now we leave it which means the time can be some
 			 * number of msecs off until someone does a settimeofday()
@@ -330,7 +330,7 @@
 			mb();
 			frozen = 0;
 			tb_last_stamp = get_tb();
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->tb_orig_stamp = tb_last_stamp;
 			smp_tb_synchronized = 1;
 		} else {
 			atomic_inc(&ready);
@@ -371,7 +371,7 @@
 static int
 smp_xics_probe(void)
 {
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 /* This is called very early */
@@ -621,7 +621,7 @@
 		if(i != 0) {
 		        /*
 			 * Processor 0's segment table is statically 
-			 * initialized to real address 0x5000.  The
+			 * initialized to real address STAB0_PHYS_ADDR.  The
 			 * Other processor's tables are created and
 			 * initialized here.
 			 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/sys32.S linux-2.4.21-rc3/arch/ppc64/kernel/sys32.S
--- linux-2.4.20/arch/ppc64/kernel/sys32.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/sys32.S	2003-05-22 22:06:27.000000000 +0000
@@ -19,8 +19,6 @@
 #include <asm/errno.h>
 #include <asm/processor.h>
 
-/* NOTE: call as jump breaks return stack, we have to avoid that */
-
 	.text
 
 _GLOBAL(sys32_mmap)
@@ -32,14 +30,6 @@
 	extsw		r4,r4		/* sign extend off_t offset parm */
 	b		.sys_lseek
 
-_GLOBAL(sys32_chmod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_chmod
-
-_GLOBAL(sys32_mknod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_mknod
-
 _GLOBAL(sys32_sendto)
 	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
 	clrldi		r8, r8, 32	/* int addr_len parm */
@@ -58,10 +48,10 @@
 	extsw		r4,r4		/* sign extend long data parm */
 	b		.sys_bdflush
 
-_GLOBAL(sys32_mmap2)
+_GLOBAL(ppc32_mmap2)
 	clrldi		r7, r7, 32	/* unsigned long fd parm */
-	extsw		r8, r8		/* off_t offset */
-	b		.sys_mmap
+	clrldi		r8, r8, 32	/* unsigned long pgoff */
+	b		.sys32_mmap2
 
 _GLOBAL(sys32_socketcall)	/* r3=call, r4=args */
 	cmpwi		r3, 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c linux-2.4.21-rc3/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/sys_ppc32.c	2003-05-22 22:06:28.000000000 +0000
@@ -69,17 +69,6 @@
 extern unsigned long wall_jiffies;
 #define USEC_PER_SEC (1000000)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
@@ -135,10 +124,10 @@
 	 */
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
-		return -EFAULT;
 	if (count > UIO_MAXIOV)
 		return -EINVAL;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
 	if (count > UIO_FASTIOV) {
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
@@ -546,7 +535,6 @@
 	u32		d_ino;
 	u32		d_offset;
 	unsigned short	d_namlen;
-  /* unsigned char	d_type; */
 	char		d_name[1];
 };
 
@@ -639,7 +627,6 @@
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(reclen, &dirent->d_reclen);
-	/* put_user(d_type, &dirent->d_type); */
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
 	((char *) dirent) += reclen;
@@ -837,7 +824,7 @@
 		put_user(usec, &tvp->tv_usec);
 	}
 
-  if (ret < 0)
+	if (ret < 0)
 		goto out;
 	if (!ret) {
 		ret = -ERESTARTNOHAND;
@@ -2448,8 +2435,10 @@
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
 struct semid_ds32 {
-	struct ipc_perm sem_perm;
+	struct ipc_perm32 sem_perm;
+	unsigned int _pad0;
 	__kernel_time_t32 sem_otime;
+	unsigned int _pad1;
 	__kernel_time_t32 sem_ctime;
 	u32 sem_base;
 	u32 sem_pending;
@@ -2459,7 +2448,7 @@
 };
 
 struct semid64_ds32 {
-	struct ipc64_perm sem_perm;
+	struct ipc64_perm32 sem_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 sem_otime;
 	unsigned int __unused2;
@@ -2471,7 +2460,7 @@
 
 struct msqid_ds32
 {
-	struct ipc_perm msg_perm;
+	struct ipc_perm32 msg_perm;
 	u32 msg_first;
 	u32 msg_last;
 	__kernel_time_t32 msg_stime;
@@ -2487,7 +2476,7 @@
 };
 
 struct msqid64_ds32 {
-	struct ipc64_perm msg_perm;
+	struct ipc64_perm32 msg_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 msg_stime;
 	unsigned int __unused2;
@@ -2504,7 +2493,7 @@
 };
 
 struct shmid_ds32 {
-	struct ipc_perm shm_perm;
+	struct ipc_perm32 shm_perm;
 	int shm_segsz;
 	__kernel_time_t32 shm_atime;
 	__kernel_time_t32 shm_dtime;
@@ -2518,7 +2507,7 @@
 };
 
 struct shmid64_ds32 {
-	struct ipc64_perm shm_perm;
+	struct ipc64_perm32 shm_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 shm_atime;
 	unsigned int __unused2;
@@ -2584,7 +2573,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems);
@@ -2601,7 +2590,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s.sem_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user(s.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s.sem_nsems, &usp->sem_nsems);
@@ -2652,11 +2641,15 @@
 			set_fs(old_fs);
 		}
 		break;
+	default:
+		err = -EINVAL;
 	}
 out:
 	return err;
 }
 
+#define MAXBUF (64*1024)
+
 static int 
 do_sys32_msgsnd(int first, int second, int third, void *uptr)
 {
@@ -2665,14 +2658,14 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
-	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= __copy_from_user(p->mtext, &up->mtext, second);
+	err |= copy_from_user(p->mtext, &up->mtext, second);
 	if (err) {
 		err = -EFAULT;
 		goto out;
@@ -2695,35 +2688,35 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
 	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
+		struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
+		struct ipc_kludge_32 ipck;
 
 		err = -EINVAL;
 		if (!uptr)
 			goto out;
 		err = -EFAULT;
-		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge_32)))
 			goto out;
 		uptr = (void *)A(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
 	err = -ENOMEM;
-	p = kmalloc(second + sizeof (struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof (struct msgbuf), GFP_USER);
 	if (!p)
 		goto out;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
 	set_fs(old_fs);
 	if (err < 0)
 		goto free_then_out;
 	up = (struct msgbuf32 *)uptr;
 	if (put_user(p->mtype, &up->mtype) ||
-	    __copy_to_user(&up->mtext, p->mtext, err))
+	    copy_to_user(&up->mtext, p->mtext, err))
 		err = -EFAULT;
 free_then_out:
 	kfree(p);
@@ -2751,7 +2744,7 @@
 			struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
 
 			err2 = copy_from_user(&m64.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc64_perm));
+					      sizeof(struct ipc64_perm32));
 			err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2767,7 +2760,7 @@
 			struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
 
 			err2 = copy_from_user(&m.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc_perm));
+					      sizeof(struct ipc_perm32));
 			err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2793,7 +2786,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m64.msg_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
  			err2 |= __put_user(m64.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
@@ -2814,7 +2807,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m.msg_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
  			err2 |= __put_user(m.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
@@ -2850,7 +2843,7 @@
 static int
 do_sys32_shmctl(int first, int second, void *uptr)
 {
-	int err = -EFAULT, err2;
+	int err = -EINVAL, err2;
 	mm_segment_t old_fs;
 
 	switch (second & (~IPC_64)) {
@@ -2908,7 +2901,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s64.shm_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.shm_atime, &up->shm_atime);
 			err2 |= __put_user(s64.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user(s64.shm_ctime, &up->shm_ctime);
@@ -2930,7 +2923,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s.shm_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user (s.shm_atime, &up->shm_atime);
 			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
@@ -4241,32 +4234,6 @@
 }
 
 
-extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
-
-/* Note: it is necessary to treat on as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on)
-{
-	return sys_ioperm(from, num, (int)on);
-}
-
-
-extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_kill(int pid, int sig);
 
 /* Note: it is necessary to treat pid and sig as unsigned ints,
@@ -4306,19 +4273,6 @@
 }
 
 
-extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
 
 /* Note: it is necessary to treat flags as an unsigned int,
@@ -4344,19 +4298,36 @@
 	return sys_nice((int)increment);
 }
 
-
-extern asmlinkage long sys_open(const char * filename, int flags, int mode);
-
-/* Note: it is necessary to treat flags and mode as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * This is just a version for 32-bit applications which does
+ * not force O_LARGEFILE on.
  */
-asmlinkage long sys32_open(const char * filename, int flags, int mode)
+long sys32_open(const char * filename, int flags, int mode)
 {
-	return sys_open(filename, (int)flags, (int)mode);
-}
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file * f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
 
@@ -4604,23 +4575,6 @@
 	return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
 }
 
-
-extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
-
-
-
 extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 				    size_t count, loff_t pos);
 
@@ -4641,6 +4595,12 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+ssize_t32 sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
+{
+        return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, AA(count));
+}
 
 extern asmlinkage long sys_truncate(const char * path, unsigned long length);
 extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
@@ -4737,3 +4697,15 @@
 
 	return secs;
 }
+
+extern unsigned long sys_mmap(unsigned long addr, size_t len,
+			      unsigned long prot, unsigned long flags,
+			      unsigned long fd, off_t offset);
+
+unsigned long sys32_mmap2(unsigned long addr, size_t len,
+			  unsigned long prot, unsigned long flags,
+			  unsigned long fd, unsigned long pgoff)
+{
+	/* This should remain 12 even if PAGE_SIZE changes */
+	return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/syscalls.c linux-2.4.21-rc3/arch/ppc64/kernel/syscalls.c
--- linux-2.4.20/arch/ppc64/kernel/syscalls.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/syscalls.c	2003-05-22 22:06:48.000000000 +0000
@@ -54,28 +54,9 @@
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	printk(KERN_ERR "sys_ioperm()\n");
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -125,7 +106,7 @@
 						(struct ipc_kludge *) ptr,
 						sizeof (tmp))))
 				break;
-			ret = sys_msgrcv (first, (struct msgbuf *)(unsigned long)tmp.msgp,
+			ret = sys_msgrcv (first, (struct msgbuf *)tmp.msgp,
 						second, tmp.msgtyp, third);
 			break;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/time.c linux-2.4.21-rc3/arch/ppc64/kernel/time.c
--- linux-2.4.20/arch/ppc64/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/time.c	2003-05-22 22:06:39.000000000 +0000
@@ -212,9 +212,9 @@
 				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
 				tb_ticks_per_sec   = new_tb_ticks_per_sec;
 				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
-				naca->tb_ticks_per_sec = tb_ticks_per_sec;
+				systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				naca->tb_to_xs = tb_to_xs;
+				systemcfg->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -258,6 +258,8 @@
 	if ((!user_mode(regs)) && (prof_buffer))
 		ppc_do_profile(instruction_pointer(regs));
 
+	pmc_timeslice_tick(); /* Hack this in for now */
+
 	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
 	while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
@@ -306,9 +308,9 @@
 	unsigned long temp_tb_to_xs, temp_stamp_xsec;
 	unsigned long tb_count_1, tb_count_2;
 	unsigned long always_zero;
-	struct naca_struct *gtdp;
+	struct systemcfg *gtdp;
 	
-	gtdp = (struct naca_struct *)0xC000000000004000;
+	gtdp = systemcfg;
 	/* 
 	 * The following loop guarantees that we see a consistent view of the
 	 * tb_to_xs and stamp_xsec variables.  These two variables can change
@@ -412,23 +414,23 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 
-	delta_xsec = mulhdu( (tb_last_stamp-naca->tb_orig_stamp), naca->tb_to_xs );
+	delta_xsec = mulhdu( (tb_last_stamp-systemcfg->tb_orig_stamp), systemcfg->tb_to_xs );
 	new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC;
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
-		naca->stamp_xsec = new_xsec - delta_xsec;
+		systemcfg->stamp_xsec = new_xsec - delta_xsec;
 	}
 	else {
 		/* This is only for the case where the user is setting the time
 		 * way back to a time such that the boot time would have been
 		 * before 1970 ... eg. we booted ten days ago, and we are
 		 * setting the time to Jan 5, 1970 */
-		naca->stamp_xsec = new_xsec;
-		naca->tb_orig_stamp = tb_last_stamp;
+		systemcfg->stamp_xsec = new_xsec;
+		systemcfg->tb_orig_stamp = tb_last_stamp;
 	}
 
-	naca->tz_minuteswest = sys_tz.tz_minuteswest;
-	naca->tz_dsttime = sys_tz.tz_dsttime;
+	systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
+	systemcfg->tz_dsttime = sys_tz.tz_dsttime;
 
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
@@ -498,11 +500,11 @@
 	xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 			      tm.tm_hour, tm.tm_min, tm.tm_sec);
 	tb_last_stamp = get_tb();
-	naca->tb_orig_stamp = tb_last_stamp;
-	naca->tb_update_count = 0;
-	naca->tb_ticks_per_sec = tb_ticks_per_sec;
-	naca->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
-	naca->tb_to_xs = tb_to_xs;
+	systemcfg->tb_orig_stamp = tb_last_stamp;
+	systemcfg->tb_update_count = 0;
+	systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
+	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	systemcfg->tb_to_xs = tb_to_xs;
 
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
@@ -614,14 +616,14 @@
 	 * tb_to_xs) and so guarantees that the current time remains the same
 	 *
 	 */ 
-	tb_ticks = get_tb() - naca->tb_orig_stamp;
+	tb_ticks = get_tb() - systemcfg->tb_orig_stamp;
 	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
 	new_tb_to_xs = divres.result_low;
 	new_xsec = mulhdu( tb_ticks, new_tb_to_xs );
 
 	write_lock_irqsave( &xtime_lock, flags );
-	old_xsec = mulhdu( tb_ticks, naca->tb_to_xs );
-	new_stamp_xsec = naca->stamp_xsec + old_xsec - new_xsec;
+	old_xsec = mulhdu( tb_ticks, systemcfg->tb_to_xs );
+	new_stamp_xsec = systemcfg->stamp_xsec + old_xsec - new_xsec;
 
 	/*
 	 * tb_update_count is used to allow the problem state gettimeofday code
@@ -632,12 +634,12 @@
 	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
 	 * loops back and reads them again until this criteria is met.
 	 */
-	++(naca->tb_update_count);
+	++(systemcfg->tb_update_count);
 	wmb();
-	naca->tb_to_xs = new_tb_to_xs;
-	naca->stamp_xsec = new_stamp_xsec;
+	systemcfg->tb_to_xs = new_tb_to_xs;
+	systemcfg->stamp_xsec = new_stamp_xsec;
 	wmb();
-	++(naca->tb_update_count);
+	++(systemcfg->tb_update_count);
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/traps.c linux-2.4.21-rc3/arch/ppc64/kernel/traps.c
--- linux-2.4.20/arch/ppc64/kernel/traps.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/traps.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/traps.c
+ *  linux/arch/ppc64/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
@@ -81,7 +81,7 @@
 int (*debugger_bpt)(struct pt_regs *regs);
 int (*debugger_sstep)(struct pt_regs *regs);
 int (*debugger_iabr_match)(struct pt_regs *regs);
-int (*debugger_dabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs) = kdb;
 /* - only defined during (xmon) mread */
 void (*debugger_fault_handler)(struct pt_regs *regs);
 #endif /* kdb */
@@ -94,8 +94,8 @@
  * Trap & Exception support
  */
 
-void
-_exception(int signr, struct pt_regs *regs)
+static void
+_exception(int signr, siginfo_t *info, struct pt_regs *regs)
 {
 	if (!user_mode(regs))
 	{
@@ -104,7 +104,8 @@
 		debugger(regs);
 #endif
 #if defined(CONFIG_KDB)
-		kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
+		if (kdb(KDB_REASON_BREAK, 0, (kdb_eframe_t) regs))
+		    return;
 #endif
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
@@ -115,7 +116,7 @@
 			debugger(regs);
 #endif
 	}
-	force_sig(signr, current);
+	force_sig_info(signr, info, current);
 }
 
 /* Get the error information for errors coming through the
@@ -155,35 +156,47 @@
 SystemResetException(struct pt_regs *regs)
 {
 	char *msg = "System Reset in kernel mode.\n";
-	udbg_printf(msg); printk(msg);
+	printk(msg);
 	if (fwnmi_active) {
 		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
-		struct rtas_error_log *errlog;
-
-		msg = "FWNMI is active with save area at %016lx\n";
-		udbg_printf(msg, r3); printk(msg, r3);
-		errlog = FWNMI_get_errinfo(regs);
+		printk("FWNMI is active with save area at %p\n", r3);
+		FWNMI_release_errinfo();
 	}
 #if defined(CONFIG_XMON)
 	xmon(regs);
 	udbg_printf("leaving xmon...\n");
 #endif
 #if defined(CONFIG_KDB)
-	kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
-	udbg_printf("leaving kdb...\n");
+	{
+		int cpu = smp_processor_id();
+		static int reset_cpu = -1;
+		static spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
+
+		/* Give kdb some help serializing the reset */
+		spin_lock(&reset_lock);
+		if (reset_cpu == -1) {
+			reset_cpu = cpu;
+			spin_unlock(&reset_lock);
+			kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
+			reset_cpu = -1;
+		} else {
+			spin_unlock(&reset_lock);
+			/* Let kdb catch this cpu with an IPI.
+			 * Ideally we need a way to enter kdb w/o it becoming
+			 * confused so we can precisely capture reset state.
+			 */
+			return;
+		}
+	}
 #endif
-
-/*
-allow system to resume after reset.
-	for(;;);
-*/
-
 }
 
 
 void
 MachineCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (fwnmi_active) {
 		struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
 		if (errhdr) {
@@ -191,18 +204,14 @@
 		}
 		FWNMI_release_errinfo();
 	}
-	if ( !user_mode(regs) )
-	{
+
+	if ( !user_mode(regs) ) {
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_fault_handler) {
 			debugger_fault_handler(regs);
 			return;
 		}
 #endif
-#ifdef CONFIG_KDB
-		if (kdb(KDB_REASON_FAULT, 0, regs))
-			return;
-#endif
 		printk("Machine check in kernel mode.\n");
 		printk("Caused by (from SRR1=%lx): ", regs->msr);
 		show_regs(regs);
@@ -216,7 +225,17 @@
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("machine check");
 	}
-	_exception(SIGSEGV, regs);	
+	
+	/*
+	 * XXX we should check RI bit on exception exit and kill the
+	 * task if it was cleared
+	 */
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRERR;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGSEGV, &info, regs);
+
 }
 
 void
@@ -242,33 +261,98 @@
 void
 UnknownException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
 	       regs->nip, regs->msr, regs->trap);
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = 0;
+	info.si_addr = 0;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 InstructionBreakpointException(struct pt_regs *regs)
 {
+	siginfo_t info;
+	
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_iabr_match(regs))
 		return;
 #endif
 #ifdef CONFIG_KDB
 	if (kdb(KDB_REASON_BREAK, 0, regs))
-		return ;
+		return;
 #endif
-	_exception(SIGTRAP, regs);
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_BRKPT;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);
+}
+
+static void
+parse_fpe(siginfo_t *info, struct pt_regs *regs)
+{
+	unsigned long fpscr;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	fpscr = current->thread.fpscr;
+
+	/* Invalid operation */
+	if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
+		info->si_code = FPE_FLTINV;
+
+	/* Overflow */
+	else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
+		info->si_code = FPE_FLTOVF;
+
+	/* Underflow */
+	else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
+		info->si_code = FPE_FLTUND;
+
+	/* Divide by zero */
+	else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
+		info->si_code = FPE_FLTDIV;
+
+	/* Inexact result */
+	else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
+		info->si_code = FPE_FLTRES;
+
+	else
+		info->si_code = 0;
+
+	info->si_signo = SIGFPE;
+	info->si_errno = 0;
+	info->si_addr = (void *)regs->nip;
+	_exception(SIGFPE, info, regs);
 }
 
 void
 ProgramCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */
-		_exception(SIGFPE, regs);
+
+		parse_fpe(&info, regs);
+	} else if (regs->msr & 0x40000) {
+		/* Privileged instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_PRVOPC;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	} else if (regs->msr & 0x20000) {
 		/* trap exception */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_bpt(regs))
 			return;
@@ -277,16 +361,29 @@
 		if (kdb(KDB_REASON_BREAK, 0, regs))
 			return;
 #endif
-		_exception(SIGTRAP, regs);
+		info.si_signo = SIGTRAP;
+		info.si_errno = 0;
+		info.si_code = TRAP_BRKPT;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGTRAP, &info, regs);
 	} else {
-		_exception(SIGILL, regs);
+		/* Illegal instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLTRP;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	}
 }
 
 void
 SingleStepException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_sstep(regs))
 		return;
@@ -295,13 +392,19 @@
 	if (kdb(KDB_REASON_DEBUG, 0, regs))
 		return;
 #endif
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_TRACE;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 AlignmentException(struct pt_regs *regs)
 {
 	int fixed;
+	siginfo_t info;
 
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
@@ -311,15 +414,28 @@
 		regs->nip += 4;	/* skip over emulated instruction */
 		return;
 	}
+	
+	/* Operand address was bad */
 	if (fixed == -EFAULT) {
-		/* fixed == -EFAULT means the operand address was bad */
-		if (user_mode(regs))
-			force_sig(SIGSEGV, current);
-		else
+		if (user_mode(regs)) {
+			info.si_signo = SIGSEGV;
+			info.si_errno = 0;
+			info.si_code = SEGV_MAPERR;
+			info.si_addr = (void *)regs->dar;
+			force_sig_info(SIGSEGV, &info, current);
+		} else {
+			/* Search exception table */
 			bad_page_fault(regs, regs->dar);
+		}
+
 		return;
 	}
-	_exception(SIGBUS, regs);	
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGBUS, &info, regs);
 }
 
 void __init trap_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/udbg.c linux-2.4.21-rc3/arch/ppc64/kernel/udbg.c
--- linux-2.4.20/arch/ppc64/kernel/udbg.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/udbg.c	2003-05-22 22:06:40.000000000 +0000
@@ -82,7 +82,7 @@
 				/* wait for idle */;
 			udbg_comport->thr = '\r'; eieio();
 		}
-	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		/* ToDo: switch this via ppc_md */
 		printk("%c", c);
 	}
@@ -119,8 +119,6 @@
 		if (s && *s != '\0') {
 			while ((c = *s++) != '\0')
 				ppc_md.udbg_putc(c);
-		} else {
-			udbg_puts("NULL");
 		}
 	} else {
 		printk("%s", s);
@@ -138,8 +136,7 @@
 		while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
 			ppc_md.udbg_putc(c);
 		}
-	} else
-		udbg_puts("NULL");
+	}
 	return n - remain;
 }
 
@@ -182,7 +179,7 @@
 void
 udbg_printSP(const char *s)
 {
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long sp;
 		asm("mr %0,1" : "=r" (sp) :);
 		if (s)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/xics.c linux-2.4.21-rc3/arch/ppc64/kernel/xics.c
--- linux-2.4.20/arch/ppc64/kernel/xics.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/kernel/xics.c	2003-05-22 22:06:39.000000000 +0000
@@ -88,6 +88,7 @@
 /* RTAS service tokens */
 int ibm_get_xive;
 int ibm_set_xive;
+int ibm_int_on;
 int ibm_int_off;
 
 struct xics_interrupt_node {
@@ -159,6 +160,14 @@
 		       irq, call_status, status);
 		return;
 	}
+	/* Now unmask the interrupt (often a no-op) */
+	call_status = rtas_call(ibm_int_on, 1, 1, (unsigned long*)&status, 
+				irq);
+	if( call_status != 0 ) {
+		printk("xics_disable_irq on: irq=%x: rtas_call failed, retn=%lx\n",
+		       irq, call_status);
+		return;
+	}
 }
 
 void
@@ -289,6 +298,7 @@
 
 	ibm_get_xive = rtas_token("ibm,get-xive");
 	ibm_set_xive = rtas_token("ibm,set-xive");
+	ibm_int_on  = rtas_token("ibm,int-on");
 	ibm_int_off = rtas_token("ibm,int-off");
 
 	np = find_type_devices("PowerPC-External-Interrupt-Presentation");
@@ -362,9 +372,9 @@
 		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
 	}
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
-		for (i = 0; i < naca->processorCount; ++i) {
+		for (i = 0; i < systemcfg->processorCount; ++i) {
 			xics_info.per_cpu[i] =
 			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 
 				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);
@@ -376,7 +386,7 @@
 	/* actually iSeries does not use any of xics...but it has link dependencies
 	 * for now, except this new one...
 	 */
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		ops = &pSeriesLP_ops;
 #endif
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/Makefile linux-2.4.21-rc3/arch/ppc64/lib/Makefile
--- linux-2.4.20/arch/ppc64/lib/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/Makefile	2003-05-22 22:06:53.000000000 +0000
@@ -6,6 +6,9 @@
 
 O_TARGET = lib.o
 
-obj-y           := checksum.o dec_and_lock.o string.o strcase.o
+export-objs     := dec_and_lock.o
+
+obj-y           := checksum.o dec_and_lock.o string.o strcase.o copypage.o \
+		   memcpy.o copyuser.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/copypage.S linux-2.4.21-rc3/arch/ppc64/lib/copypage.S
--- linux-2.4.20/arch/ppc64/lib/copypage.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/copypage.S	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,121 @@
+/*
+ * arch/ppc64/lib/copypage.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+_GLOBAL(copy_page)
+	std	r31,-8(1)
+	std	r30,-16(1)
+	std	r29,-24(1)
+	std	r28,-32(1)
+	std	r27,-40(1)
+	std	r26,-48(1)
+	std	r25,-56(1)
+	std	r24,-64(1)
+	std	r23,-72(1)
+	std	r22,-80(1)
+	std	r21,-88(1)
+	std	r20,-96(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r12,5
+0:	addi	r5,r5,-24
+	mtctr	r12
+	ld	r22,640(4)
+	ld	r21,512(4)
+	ld	r20,384(4)
+	ld	r11,256(4)
+	ld	r9,128(4)
+	ld	r7,0(4)
+	ld	r25,648(4)
+	ld	r24,520(4)
+	ld	r23,392(4)
+	ld	r10,264(4)
+	ld	r8,136(4)
+	ldu	r6,8(4)
+	cmpwi	r5,24
+1:	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	ld	r28,648(4)
+	ld	r27,520(4)
+	ld	r26,392(4)
+	ld	r31,264(4)
+	ld	r30,136(4)
+	ld	r29,8(4)
+	std	r25,656(3)
+	std	r24,528(3)
+	std	r23,400(3)
+	std	r10,272(3)
+	std	r8,144(3)
+	std	r6,16(3)
+	ld	r22,656(4)
+	ld	r21,528(4)
+	ld	r20,400(4)
+	ld	r11,272(4)
+	ld	r9,144(4)
+	ld	r7,16(4)
+	std	r28,664(3)
+	std	r27,536(3)
+	std	r26,408(3)
+	std	r31,280(3)
+	std	r30,152(3)
+	stdu	r29,24(3)
+	ld	r25,664(4)
+	ld	r24,536(4)
+	ld	r23,408(4)
+	ld	r10,280(4)
+	ld	r8,152(4)
+	ldu	r6,24(4)
+	bdnz	1b
+	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	addi	r4,r4,640
+	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+	ld	r7,0(4)
+	ld	r8,8(4)
+	ldu	r9,16(4)
+3:	ld	r10,8(4)
+	std	r7,8(3)
+	ld	r7,16(4)
+	std	r8,16(3)
+	ld	r8,24(4)
+	std	r9,24(3)
+	ldu	r9,32(4)
+	stdu	r10,32(3)
+	bdnz	3b
+4:	ld	r10,8(4)
+	std	r7,8(3)
+	std	r8,16(3)
+	std	r9,24(3)
+	std	r10,32(3)
+9:	ld	r20,-96(1)
+	ld	r21,-88(1)
+	ld	r22,-80(1)
+	ld	r23,-72(1)
+	ld	r24,-64(1)
+	ld	r25,-56(1)
+	ld	r26,-48(1)
+	ld	r27,-40(1)
+	ld	r28,-32(1)
+	ld	r29,-24(1)
+	ld	r30,-16(1)
+	ld	r31,-8(1)
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/copyuser.S linux-2.4.21-rc3/arch/ppc64/lib/copyuser.S
--- linux-2.4.20/arch/ppc64/lib/copyuser.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/copyuser.S	2003-05-22 22:06:43.000000000 +0000
@@ -0,0 +1,564 @@
+/*
+ * arch/ppc64/lib/copyuser.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(__copy_tofrom_user)
+	/* first check for a whole page copy on a page boundary */
+	cmpldi	cr1,r5,16
+	cmpdi	cr6,r5,4096
+	or	r0,r3,r4
+	neg	r6,r3		/* LS 3 bits = # bytes to 8-byte dest bdry */
+	andi.	r0,r0,4095
+	std	r3,-24(r1)
+	crand	cr0*4+2,cr0*4+2,cr6*4+2
+	std	r4,-16(r1)
+	std	r5,-8(r1)
+	dcbt	0,r4
+	beq	.Lcopy_page
+	andi.	r6,r6,7
+	mtcrf	0x01,r5
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+20:	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,22f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,72f
+21:	ld	r9,8(r4)
+70:	std	r8,8(r3)
+22:	ldu	r8,16(r4)
+71:	stdu	r9,16(r3)
+	bdnz	21b
+72:	std	r8,8(r3)
+	beq+	3f
+	addi	r3,r3,16
+23:	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+73:	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+74:	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+75:	stb	r9,0(r3)
+3:	li	r3,0
+	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpldi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+	bt	cr7*4+0,28f
+
+24:	ld	r9,0(r4)	/* 3+2n loads, 2+2n stores */
+25:	ld	r0,8(r4)
+	sld	r6,r9,r10
+26:	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,79f
+27:	ld	r0,8(r4)
+	b	2f
+
+28:	ld	r0,0(r4)	/* 4+2n loads, 3+2n stores */
+29:	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+30:	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+31:	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,78f
+
+1:	or	r7,r7,r6
+32:	ld	r0,8(r4)
+76:	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+33:	ldu	r9,16(r4)
+	or	r12,r8,r12
+77:	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+78:	std	r12,8(r3)
+	or	r7,r7,r6
+79:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+80:	std	r12,24(r3)
+	bne	6f
+	li	r3,0
+	blr
+6:	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	blt	cr1,.Ldo_tail
+34:	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		/* put #bytes to 8B bdry into cr7 */
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+35:	lbz	r0,0(r4)
+81:	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+36:	lhzx	r0,r7,r4
+82:	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+37:	lwzx	r0,r7,r4
+83:	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+38:	lwz	r0,0(r4)
+39:	lwz	r9,4(r4)
+	addi	r4,r4,8
+84:	stw	r0,0(r3)
+85:	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+40:	lwz	r0,0(r4)
+	addi	r4,r4,4
+86:	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+41:	lhz	r0,0(r4)
+	addi	r4,r4,2
+87:	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+42:	lbz	r0,0(r4)
+88:	stb	r0,0(r3)
+4:	li	r3,0
+	blr
+
+/*
+ * exception handlers follow
+ * we have to return the number of bytes not copied
+ * for an exception on a load, we set the rest of the destination to 0
+ */
+
+136:
+137:
+	add	r3,r3,r7
+	b	1f
+130:
+131:
+	addi	r3,r3,8
+120:
+122:
+124:
+125:
+126:
+127:
+128:
+129:
+133:
+	addi	r3,r3,8
+121:
+132:
+	addi	r3,r3,8
+123:
+134:
+135:
+138:
+139:
+140:
+141:
+142:
+
+/*
+ * here we have had a fault on a load and r3 points to the first
+ * unmodified byte of the destination
+ */
+1:	ld	r6,-24(r1)
+	ld	r4,-16(r1)
+	ld	r5,-8(r1)
+	subf	r6,r6,r3
+	add	r4,r4,r6
+	subf	r5,r6,r5	/* #bytes left to go */
+
+/*
+ * first see if we can copy any more bytes before hitting another exception
+ */
+	mtctr	r5
+43:	lbz	r0,0(r4)
+	addi	r4,r4,1
+89:	stb	r0,0(r3)
+	addi	r3,r3,1
+	bdnz	43b
+	li	r3,0		/* huh? all copied successfully this time? */
+	blr
+
+/*
+ * here we have trapped again, need to clear ctr bytes starting at r3
+ */
+143:	mfctr	r5
+	li	r0,0
+	mr	r4,r3
+	mr	r3,r5		/* return the number of bytes not copied */
+1:	andi.	r9,r4,7
+	beq	3f
+90:	stb	r0,0(r4)
+	addic.	r5,r5,-1
+	addi	r4,r4,1
+	bne	1b
+	blr
+3:	cmpldi	cr1,r5,8
+	srdi	r9,r5,3
+	andi.	r5,r5,7
+	blt	cr1,93f
+	mtctr	r9
+91:	std	r0,0(r4)
+	addi	r4,r4,8
+	bdnz	91b
+93:	beqlr
+	mtctr	r5	
+92:	stb	r0,0(r4)
+	addi	r4,r4,1
+	bdnz	92b
+	blr
+
+/*
+ * exception handlers for stores: we just need to work
+ * out how many bytes weren't copied
+ */
+182:
+183:
+	add	r3,r3,r7
+	b	1f
+180:
+	addi	r3,r3,8
+171:
+177:
+	addi	r3,r3,8
+170:
+172:
+176:
+178:
+	addi	r3,r3,4
+185:
+	addi	r3,r3,4
+173:
+174:
+175:
+179:
+181:
+184:
+186:
+187:
+188:
+189:	
+1:
+	ld	r6,-24(r1)
+	ld	r5,-8(r1)
+	add	r6,r6,r5
+	subf	r3,r3,r6	/* #bytes not copied */
+190:
+191:
+192:
+	blr			/* #bytes not copied in r3 */
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,120b
+	.llong	21b,121b
+	.llong	70b,170b
+	.llong	22b,122b
+	.llong	71b,171b
+	.llong	72b,172b
+	.llong	23b,123b
+	.llong	73b,173b
+	.llong	74b,174b
+	.llong	75b,175b
+	.llong	24b,124b
+	.llong	25b,125b
+	.llong	26b,126b
+	.llong	27b,127b
+	.llong	28b,128b
+	.llong	29b,129b
+	.llong	30b,130b
+	.llong	31b,131b
+	.llong	32b,132b
+	.llong	76b,176b
+	.llong	33b,133b
+	.llong	77b,177b
+	.llong	78b,178b
+	.llong	79b,179b
+	.llong	80b,180b
+	.llong	34b,134b
+	.llong	35b,135b
+	.llong	81b,181b
+	.llong	36b,136b
+	.llong	82b,182b
+	.llong	37b,137b
+	.llong	83b,183b
+	.llong	38b,138b
+	.llong	39b,139b
+	.llong	84b,184b
+	.llong	85b,185b
+	.llong	40b,140b
+	.llong	86b,186b
+	.llong	41b,141b
+	.llong	87b,187b
+	.llong	42b,142b
+	.llong	88b,188b
+	.llong	43b,143b
+	.llong	89b,189b
+	.llong	90b,190b
+	.llong	91b,191b
+	.llong	92b,192b
+	
+	.text
+
+/*
+ * Routine to copy a whole page of data, optimized for POWER4.
+ * On POWER4 it is more than 50% faster than the simple loop
+ * above (following the .Ldst_aligned label) but it runs slightly
+ * slower on POWER3.
+ */
+.Lcopy_page:
+	std	r31,-32(1)
+	std	r30,-40(1)
+	std	r29,-48(1)
+	std	r28,-56(1)
+	std	r27,-64(1)
+	std	r26,-72(1)
+	std	r25,-80(1)
+	std	r24,-88(1)
+	std	r23,-96(1)
+	std	r22,-104(1)
+	std	r21,-112(1)
+	std	r20,-120(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r0,5
+0:	addi	r5,r5,-24
+	mtctr	r0
+20:	ld	r22,640(4)
+21:	ld	r21,512(4)
+22:	ld	r20,384(4)
+23:	ld	r11,256(4)
+24:	ld	r9,128(4)
+25:	ld	r7,0(4)
+26:	ld	r25,648(4)
+27:	ld	r24,520(4)
+28:	ld	r23,392(4)
+29:	ld	r10,264(4)
+30:	ld	r8,136(4)
+31:	ldu	r6,8(4)
+	cmpwi	r5,24
+1:
+32:	std	r22,648(3)
+33:	std	r21,520(3)
+34:	std	r20,392(3)
+35:	std	r11,264(3)
+36:	std	r9,136(3)
+37:	std	r7,8(3)
+38:	ld	r28,648(4)
+39:	ld	r27,520(4)
+40:	ld	r26,392(4)
+41:	ld	r31,264(4)
+42:	ld	r30,136(4)
+43:	ld	r29,8(4)
+44:	std	r25,656(3)
+45:	std	r24,528(3)
+46:	std	r23,400(3)
+47:	std	r10,272(3)
+48:	std	r8,144(3)
+49:	std	r6,16(3)
+50:	ld	r22,656(4)
+51:	ld	r21,528(4)
+52:	ld	r20,400(4)
+53:	ld	r11,272(4)
+54:	ld	r9,144(4)
+55:	ld	r7,16(4)
+56:	std	r28,664(3)
+57:	std	r27,536(3)
+58:	std	r26,408(3)
+59:	std	r31,280(3)
+60:	std	r30,152(3)
+61:	stdu	r29,24(3)
+62:	ld	r25,664(4)
+63:	ld	r24,536(4)
+64:	ld	r23,408(4)
+65:	ld	r10,280(4)
+66:	ld	r8,152(4)
+67:	ldu	r6,24(4)
+	bdnz	1b
+68:	std	r22,648(3)
+69:	std	r21,520(3)
+70:	std	r20,392(3)
+71:	std	r11,264(3)
+72:	std	r9,136(3)
+73:	std	r7,8(3)
+74:	addi	r4,r4,640
+75:	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+76:	ld	r7,0(4)
+77:	ld	r8,8(4)
+78:	ldu	r9,16(4)
+3:
+79:	ld	r10,8(4)
+80:	std	r7,8(3)
+81:	ld	r7,16(4)
+82:	std	r8,16(3)
+83:	ld	r8,24(4)
+84:	std	r9,24(3)
+85:	ldu	r9,32(4)
+86:	stdu	r10,32(3)
+	bdnz	3b
+4:
+87:	ld	r10,8(4)
+88:	std	r7,8(3)
+89:	std	r8,16(3)
+90:	std	r9,24(3)
+91:	std	r10,32(3)
+9:	ld	r20,-120(1)
+	ld	r21,-112(1)
+	ld	r22,-104(1)
+	ld	r23,-96(1)
+	ld	r24,-88(1)
+	ld	r25,-80(1)
+	ld	r26,-72(1)
+	ld	r27,-64(1)
+	ld	r28,-56(1)
+	ld	r29,-48(1)
+	ld	r30,-40(1)
+	ld	r31,-32(1)
+	li	r3,0
+	blr
+
+/*
+ * on an exception, reset to the beginning and jump back into the
+ * standard __copy_tofrom_user
+ */
+100:	ld	r3,-24(r1)
+	ld	r4,-24(r1)
+	li	r5,4096
+	b	.Ldst_aligned
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,100b
+	.llong	21b,100b
+	.llong	22b,100b
+	.llong	23b,100b
+	.llong	24b,100b
+	.llong	25b,100b
+	.llong	26b,100b
+	.llong	27b,100b
+	.llong	28b,100b
+	.llong	29b,100b
+	.llong	30b,100b
+	.llong	31b,100b
+	.llong	32b,100b
+	.llong	33b,100b
+	.llong	34b,100b
+	.llong	35b,100b
+	.llong	36b,100b
+	.llong	37b,100b
+	.llong	38b,100b
+	.llong	39b,100b
+	.llong	40b,100b
+	.llong	41b,100b
+	.llong	42b,100b
+	.llong	43b,100b
+	.llong	44b,100b
+	.llong	45b,100b
+	.llong	46b,100b
+	.llong	47b,100b
+	.llong	48b,100b
+	.llong	49b,100b
+	.llong	50b,100b
+	.llong	51b,100b
+	.llong	52b,100b
+	.llong	53b,100b
+	.llong	54b,100b
+	.llong	55b,100b
+	.llong	56b,100b
+	.llong	57b,100b
+	.llong	58b,100b
+	.llong	59b,100b
+	.llong	60b,100b
+	.llong	61b,100b
+	.llong	62b,100b
+	.llong	63b,100b
+	.llong	64b,100b
+	.llong	65b,100b
+	.llong	66b,100b
+	.llong	67b,100b
+	.llong	68b,100b
+	.llong	69b,100b
+	.llong	70b,100b
+	.llong	71b,100b
+	.llong	72b,100b
+	.llong	73b,100b
+	.llong	74b,100b
+	.llong	75b,100b
+	.llong	76b,100b
+	.llong	77b,100b
+	.llong	78b,100b
+	.llong	79b,100b
+	.llong	80b,100b
+	.llong	81b,100b
+	.llong	82b,100b
+	.llong	83b,100b
+	.llong	84b,100b
+	.llong	85b,100b
+	.llong	86b,100b
+	.llong	87b,100b
+	.llong	88b,100b
+	.llong	89b,100b
+	.llong	90b,100b
+	.llong	91b,100b
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/dec_and_lock.c linux-2.4.21-rc3/arch/ppc64/lib/dec_and_lock.c
--- linux-2.4.20/arch/ppc64/lib/dec_and_lock.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/dec_and_lock.c	2003-05-22 22:06:24.000000000 +0000
@@ -7,32 +7,48 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/system.h>
 
+/*
+ * This is an implementation of the notion of "decrement a
+ * reference count, and return locked if it decremented to zero".
+ *
+ * This implementation can be used on any architecture that
+ * has a cmpxchg, and where atomic->value is an int holding
+ * the value of the atomic (i.e. the high bits aren't used
+ * for a lock or anything like that).
+ *
+ * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h
+ * if spinlocks are empty and thus atomic_dec_and_lock is defined
+ * to be atomic_dec_and_test - in that case we don't need it
+ * defined here as well.
+ */
+
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
 	int newcount;
 
-repeat:
-	counter = atomic_read(atomic);
-	newcount = counter-1;
-
-	if (!newcount)
-		goto slow_path;
+	for (;;) {
+		counter = atomic_read(atomic);
+		newcount = counter - 1;
+		if (!newcount)
+			break;		/* do it the slow way */
+
+		newcount = cmpxchg(&atomic->counter, counter, newcount);
+		if (newcount == counter)
+			return 0;
+	}
 
-	newcount = cmpxchg(&atomic->counter, counter, newcount);
-
-	if (newcount != counter)
-		goto repeat;
-	return 0;
-
-slow_path:
 	spin_lock(lock);
 	if (atomic_dec_and_test(atomic))
 		return 1;
 	spin_unlock(lock);
 	return 0;
 }
+
+#endif /* ATOMIC_DEC_AND_LOCK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/memcpy.S linux-2.4.21-rc3/arch/ppc64/lib/memcpy.S
--- linux-2.4.20/arch/ppc64/lib/memcpy.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/memcpy.S	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,172 @@
+/*
+ * arch/ppc64/lib/memcpy.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(memcpy)
+	mtcrf	0x01,r5
+	cmpldi	cr1,r5,16
+	neg	r6,r3		# LS 3 bits = # bytes to 8-byte dest bdry
+	andi.	r6,r6,7
+	dcbt	0,r4
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,2f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,3f
+1:	ld	r9,8(r4)
+	std	r8,8(r3)
+2:	ldu	r8,16(r4)
+	stdu	r9,16(r3)
+	bdnz	1b
+3:	std	r8,8(r3)
+	beqlr
+	addi	r3,r3,16
+	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+	stb	r9,0(r3)
+3:	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpdi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+
+	bt	cr7*4+0,0f
+
+	ld	r9,0(r4)	# 3+2n loads, 2+2n stores
+	ld	r0,8(r4)
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,4f
+	ld	r0,8(r4)
+	# s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12
+	b	2f
+
+0:	ld	r0,0(r4)	# 4+2n loads, 3+2n stores
+	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,3f
+
+	# d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9
+1:	or	r7,r7,r6
+	ld	r0,8(r4)
+	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+3:	std	r12,8(r3)
+	or	r7,r7,r6
+4:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+	std	r12,24(r3)
+	beqlr
+	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	ble	cr1,.Ldo_tail
+	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		# put #bytes to 8B bdry into cr7
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+	lhzx	r0,r7,r4
+	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+	lwzx	r0,r7,r4
+	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+	lwz	r0,0(r4)
+	lwz	r9,4(r4)
+	addi	r4,r4,8
+	stw	r0,0(r3)
+	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+	lwz	r0,0(r4)
+	addi	r4,r4,4
+	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+	lhz	r0,0(r4)
+	addi	r4,r4,2
+	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+4:	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/string.S linux-2.4.21-rc3/arch/ppc64/lib/string.S
--- linux-2.4.20/arch/ppc64/lib/string.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/lib/string.S	2003-05-22 22:06:39.000000000 +0000
@@ -12,61 +12,6 @@
 #include <asm/processor.h>
 #include <asm/errno.h>
 
-#define CACHE_LINE_SIZE		128
-#define LG_CACHE_LINE_SIZE	7
-#define MAX_COPY_PREFETCH	1
-
-#define COPY_16_BYTES		\
-	lwz	r7,4(r4);	\
-	lwz	r8,8(r4);	\
-	lwz	r9,12(r4);	\
-	lwzu	r10,16(r4);	\
-	stw	r7,4(r6);	\
-	stw	r8,8(r6);	\
-	stw	r9,12(r6);	\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_WITHEX(n)	\
-8 ## n ## 0:			\
-	lwz	r7,4(r4);	\
-8 ## n ## 1:			\
-	lwz	r8,8(r4);	\
-8 ## n ## 2:			\
-	lwz	r9,12(r4);	\
-8 ## n ## 3:			\
-	lwzu	r10,16(r4);	\
-8 ## n ## 4:			\
-	stw	r7,4(r6);	\
-8 ## n ## 5:			\
-	stw	r8,8(r6);	\
-8 ## n ## 6:			\
-	stw	r9,12(r6);	\
-8 ## n ## 7:			\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_EXCODE(n)			\
-9 ## n ## 0:					\
-	addi	r5,r5,-(16 * n);		\
-	b	104f;				\
-9 ## n ## 1:					\
-	addi	r5,r5,-(16 * n);		\
-	b	105f;				\
-.section __ex_table,"a";			\
-	.align	3;				\
-	.llong	8 ## n ## 0b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 1b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 2b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 3b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 4b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 5b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 6b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 7b,9 ## n ## 1b;	\
-.text
-
-CACHELINE_BYTES = CACHE_LINE_SIZE
-LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE
-CACHELINE_MASK = (CACHE_LINE_SIZE-1)
-
 _GLOBAL(strcpy)
 	addi	r5,r3,-1
 	addi	r4,r4,-1
@@ -120,54 +65,6 @@
 	subf	r3,r3,r4
 	blr
 
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-	mr	r5,r4
-	li	r4,0
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
-	add	r8,r7,r5
-	srwi	r9,r8,LG_CACHELINE_BYTES
-	addic.	r9,r9,-1	/* total number of complete cachelines */
-	ble	2f
-	xori	r0,r7,CACHELINE_MASK & ~3
-	srwi.	r0,r0,2
-	beq	3f
-	mtctr	r0
-4:	stwu	r4,4(r6)
-	bdnz	4b
-3:	mtctr	r9
-	li	r7,4
-10:	dcbz	r7,r6
-	addi	r6,r6,CACHELINE_BYTES
-	bdnz	10b
-	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
-	addi	r5,r5,4
-2:	srwi	r0,r5,2
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
 _GLOBAL(memset)
 	rlwimi	r4,r4,8,16,23
 	rlwimi	r4,r4,16,0,15
@@ -196,48 +93,7 @@
 _GLOBAL(memmove)
 	cmplw	0,r3,r4
 	bgt	.backwards_memcpy
-	/* fall through */
-
-_GLOBAL(memcpy)
-	srwi.	r7,r5,3
-	addi	r6,r3,-4
-	addi	r4,r4,-4
-	beq	2f			/* if less than 8 bytes to do */
-	andi.	r0,r6,3			/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-	lwzu	r8,8(r4)
-	stw	r7,4(r6)
-	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4
-	mtctr	r0
-6:	lbz	r7,4(r4)
-	addi	r4,r4,1
-	stb	r7,4(r6)
-	addi	r6,r6,1
-	bdnz	6b
-	subf	r5,r0,r5
-	rlwinm.	r7,r5,32-3,3,31
-	beq	2b
-	mtctr	r7
-	b	1b
+	b	.memcpy
 
 _GLOBAL(backwards_memcpy)
 	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
@@ -301,195 +157,6 @@
 2:	li	r3,0
 	blr
 
-_GLOBAL(__copy_tofrom_user)
-	addi	r4,r4,-4
-	addi	r6,r3,-4
-	neg	r0,r3
-	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
-	beq	58f
-
-	cmplw	0,r5,r0			/* is this more than total to do? */
-	blt	63f			/* if not much to do */
-	andi.	r8,r0,3			/* get it word-aligned first */
-	mtctr	r8
-	beq+	61f
-70:	lbz	r9,4(r4)		/* do some bytes */
-71:	stb	r9,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	70b
-61:	subf	r5,r0,r5
-	srwi.	r0,r0,2
-	mtctr	r0
-	beq	58f
-72:	lwzu	r9,4(r4)		/* do some words */
-73:	stwu	r9,4(r6)
-	bdnz	72b
-
-58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
-	li	r11,4
-	beq	63f
-
-	/* Here we decide how far ahead to prefetch the source */
-#if MAX_COPY_PREFETCH > 1
-	/* Heuristically, for large transfers we prefetch
-	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
-	   we prefetch 1 cacheline ahead. */
-	cmpwi	r0,MAX_COPY_PREFETCH
-	li	r7,1
-	li	r3,4
-	ble	111f
-	li	r7,MAX_COPY_PREFETCH
-111:	mtctr	r7
-112:	dcbt	r3,r4
-	addi	r3,r3,CACHELINE_BYTES
-	bdnz	112b
-#else /* MAX_COPY_PREFETCH == 1 */
-	li	r3,CACHELINE_BYTES + 4
-	dcbt	r11,r4
-#endif /* MAX_COPY_PREFETCH */
-
-	mtctr	r0
-	dcbt	r3,r4
-53:
-54:	dcbz	r11,r6
-/* had to move these to keep extable in order */
-	.section __ex_table,"a"
-	.align	3
-	.llong	70b,100f
-	.llong	71b,101f
-	.llong	72b,102f
-	.llong	73b,103f
-	.llong	54b,105f
-	.text
-/* the main body of the cacheline loop */
-	COPY_16_BYTES_WITHEX(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_WITHEX(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_WITHEX(2)
-	COPY_16_BYTES_WITHEX(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_WITHEX(4)
-	COPY_16_BYTES_WITHEX(5)
-	COPY_16_BYTES_WITHEX(6)
-	COPY_16_BYTES_WITHEX(7)
-#endif
-#endif
-#endif
-	bdnz	53b
-
-63:	srwi.	r0,r5,2
-	mtctr	r0
-	beq	64f
-30:	lwzu	r0,4(r4)
-31:	stwu	r0,4(r6)
-	bdnz	30b
-
-64:	andi.	r0,r5,3
-	mtctr	r0
-	beq+	65f
-40:	lbz	r0,4(r4)
-41:	stb	r0,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	40b
-65:	li	r3,0
-	blr
-
-/* read fault, initial single-byte copy */
-100:	li	r4,0
-	b	90f
-/* write fault, initial single-byte copy */
-101:	li	r4,1
-90:	subf	r5,r8,r5
-	li	r3,0
-	b	99f
-/* read fault, initial word copy */
-102:	li	r4,0
-	b	91f
-/* write fault, initial word copy */
-103:	li	r4,1
-91:	li	r3,2
-	b	99f
-
-/*
- * this stuff handles faults in the cacheline loop and branches to either
- * 104f (if in read part) or 105f (if in write part), after updating r5
- */
-	COPY_16_BYTES_EXCODE(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_EXCODE(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_EXCODE(2)
-	COPY_16_BYTES_EXCODE(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_EXCODE(4)
-	COPY_16_BYTES_EXCODE(5)
-	COPY_16_BYTES_EXCODE(6)
-	COPY_16_BYTES_EXCODE(7)
-#endif
-#endif
-#endif
-
-/* read fault in cacheline loop */
-104:	li	r4,0
-	b	92f
-/* fault on dcbz (effectively a write fault) */
-/* or write fault in cacheline loop */
-105:	li	r4,1
-92:	li	r3,LG_CACHELINE_BYTES
-	b	99f
-/* read fault in final word loop */
-108:	li	r4,0
-	b	93f
-/* write fault in final word loop */
-109:	li	r4,1
-93:	andi.	r5,r5,3
-	li	r3,2
-	b	99f
-/* read fault in final byte loop */
-110:	li	r4,0
-	b	94f
-/* write fault in final byte loop */
-111:	li	r4,1
-94:	li	r5,0
-	li	r3,0
-/*
- * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
- */
-99:	mfctr	r0
-	slw	r3,r0,r3
-	add	r3,r3,r5
-	cmpwi	0,r4,0
-	bne	120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
-	srwi.	r0,r3,2
-	li	r9,0
-	mtctr	r0
-	beq	113f
-112:	stwu	r9,4(r6)
-	bdnz	112b
-113:	andi.	r0,r3,3
-	mtctr	r0
-	beq	120f
-114:	stb	r9,4(r6)
-	addi	r6,r6,1
-	bdnz	114b
-120:	blr
-
-	.section __ex_table,"a"
-	.align	3
-	.llong	30b,108b
-	.llong	31b,109b
-	.llong	40b,110b
-	.llong	41b,111b
-	.llong	112b,120b
-	.llong	114b,120b
-	.text
-
 _GLOBAL(__clear_user)
 	addi	r6,r3,-4
 	li	r3,0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/extable.c linux-2.4.21-rc3/arch/ppc64/mm/extable.c
--- linux-2.4.20/arch/ppc64/mm/extable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/mm/extable.c	2003-05-22 22:06:43.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/arch/ppc/mm/extable.c
+ * linux/arch/ppc64/mm/extable.c
  *
  * from linux/arch/i386/mm/extable.c
  *
@@ -9,54 +9,95 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * as well as the init segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+	      struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (p[0].insn < p[-1].insn) {
+			/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && el.insn < q[-1].insn);
+			*q = el;
+		}
+	}
+}
+
+void
+sort_exception_table(void)
+{
+	sort_ex_table(__start___ex_table, __stop___ex_table);
+}
 
 static inline unsigned long
 search_one_table(const struct exception_table_entry *first,
 		 const struct exception_table_entry *last,
 		 unsigned long value)
 {
-        while (first <= last) {
+	while (first <= last) {
 		const struct exception_table_entry *mid;
 		long diff;
 
 		mid = (last - first) / 2 + first;
 		diff = mid->insn - value;
-                if (diff == 0)
-                        return mid->fixup;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return 0;
+		if (diff == 0)
+			return mid->fixup;
+		else if (diff < 0)
+			first = mid+1;
+		else
+			last = mid-1;
+	}
+	return 0;
 }
 
+extern spinlock_t modlist_lock;
+
 unsigned long
 search_exception_table(unsigned long addr)
 {
-	unsigned long ret;
+	unsigned long ret = 0;
 
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
-	if (ret) return ret;
+	return ret;
 #else
+	unsigned long flags;
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
+
+	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
 		if (ret)
-			return ret;
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/fault.c linux-2.4.21-rc3/arch/ppc64/mm/fault.c
--- linux-2.4.20/arch/ppc64/mm/fault.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/mm/fault.c	2003-05-22 22:06:41.000000000 +0000
@@ -84,17 +84,30 @@
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && (regs->trap == 0x300 ||
-				regs->trap == 0x380)) {
+				       regs->trap == 0x380)) {
 		debugger_fault_handler(regs);
 		return;
 	}
+#endif /* CONFIG_XMON || CONFIG_KGDB */
+
+	/* On an SLB miss we can only check for a valid exception entry */
+	if (regs->trap == 0x380) {
+		bad_page_fault(regs, address);
+		return;
+	}
 
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) || defined(CONFIG_KDB)
 	if (error_code & 0x00400000) {
 		/* DABR match */
+#if defined(CONFIG_KDB)
+	    if (kdb(KDB_REASON_BREAK,regs->trap,regs))
+			return;
+#else
 		if (debugger_dabr_match(regs))
 			return;
+#endif
 	}
-#endif /* CONFIG_XMON || CONFIG_KGDB */
+#endif /* CONFIG_XMON || CONFIG_KGDB || CONFIG_KDB */
 
 	if (in_interrupt() || mm == NULL) {
 		bad_page_fault(regs, address);
@@ -136,6 +149,7 @@
 			goto bad_area;
 	}
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -189,6 +203,11 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/init.c linux-2.4.21-rc3/arch/ppc64/mm/init.c
--- linux-2.4.20/arch/ppc64/mm/init.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/mm/init.c	2003-05-22 22:06:28.000000000 +0000
@@ -82,11 +82,6 @@
 extern char _stext[], etext[];
 extern struct task_struct *current_set[NR_CPUS];
 
-void mm_init_ppc64(void);
-
-unsigned long *pmac_find_end_of_memory(void);
-extern unsigned long *find_end_of_memory(void);
-
 extern pgd_t ioremap_dir[];
 pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir;
 
@@ -171,12 +166,10 @@
 #ifdef CONFIG_PPC_ISERIES
 	return (void*)addr;
 #else
-	if(mem_init_done && (addr >> 60UL)) {
-		if (IS_EEH_TOKEN_DISABLED(addr))
-			return IO_TOKEN_TO_ADDR(addr);
-		return (void*)addr; /* already mapped address or EEH token. */
-	}
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
+	void *ret = __ioremap(addr, size, _PAGE_NO_CACHE);
+	if(mem_init_done)
+		return eeh_ioremap(addr, ret);	/* may remap the addr */
+	return ret;
 #endif
 }
 
@@ -272,6 +265,14 @@
 	}
 }
 
+#ifndef CONFIG_PPC_ISERIES
+int
+io_remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
+{
+	return remap_page_range(from, eeh_token_to_phys(to), size, prot);
+}
+#endif
+
 void
 local_flush_tlb_all(void)
 {
@@ -284,6 +285,8 @@
 void
 local_flush_tlb_mm(struct mm_struct *mm)
 {
+	spin_lock(&mm->page_table_lock);
+
 	if ( mm->map_count ) {
 		struct vm_area_struct *mp;
 		for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
@@ -294,6 +297,8 @@
 		 * when an address space (represented by an mm_struct)
 		 * is being destroyed. */
 		local_flush_tlb_range( mm, USER_START, USER_END );
+
+	spin_unlock(&mm->page_table_lock);
 }
 
 /*
@@ -446,12 +451,12 @@
 	 * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT)
 	 * are stored on a stack/queue for easy allocation and deallocation.
 	 */
-        mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
-        mmu_context_queue.head = 0;
-        mmu_context_queue.tail = NUM_USER_CONTEXT-1;
-        mmu_context_queue.size = NUM_USER_CONTEXT;
+	mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
+	mmu_context_queue.head = 0;
+	mmu_context_queue.tail = NUM_USER_CONTEXT-1;
+	mmu_context_queue.size = NUM_USER_CONTEXT;
 	for(index=0; index < NUM_USER_CONTEXT ;index++) {
-                mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
+		mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
 	}
 
 	/* Setup guard pages for the Paca's */
@@ -491,7 +496,7 @@
 
 	PPCDBG(PPCDBG_MMINIT, "\tstart               = 0x%lx\n", start);
 	PPCDBG(PPCDBG_MMINIT, "\tbootmap_pages       = 0x%lx\n", bootmap_pages);
-	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", naca->physicalMemorySize);
+	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", systemcfg->physicalMemorySize);
 
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
 	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
@@ -585,7 +590,7 @@
 			datapages++;
 	}
 
-        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
 	       (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
 	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
 	       initpages<< (PAGE_SHIFT-10),
@@ -622,6 +627,7 @@
 void clear_user_page(void *page, unsigned long vaddr)
 {
 	clear_page(page);
+	__flush_dcache_icache(page);
 }
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/vmlinux.lds linux-2.4.21-rc3/arch/ppc64/vmlinux.lds
--- linux-2.4.20/arch/ppc64/vmlinux.lds	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/vmlinux.lds	2003-05-22 22:06:25.000000000 +0000
@@ -1,4 +1,4 @@
-OUTPUT_ARCH(powerpc)
+OUTPUT_ARCH(powerpc:common64)
 SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
 /* Do we need any of these for elf?
    __DYNAMIC = 0;    */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/xmon/start.c linux-2.4.21-rc3/arch/ppc64/xmon/start.c
--- linux-2.4.20/arch/ppc64/xmon/start.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/xmon/start.c	2003-05-22 22:06:26.000000000 +0000
@@ -59,9 +59,9 @@
 }
 static struct sysrq_key_op sysrq_xmon_op = 
 {
-	handler:	sysrq_handle_xmon,
-	help_msg:	"xmon",
-	action_msg:	"Entering xmon\n",
+	.handler =	sysrq_handle_xmon,
+	.help_msg =	"xmon",
+	.action_msg =	"Entering xmon\n",
 };
 
 void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/xmon/xmon.c linux-2.4.21-rc3/arch/ppc64/xmon/xmon.c
--- linux-2.4.20/arch/ppc64/xmon/xmon.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/ppc64/xmon/xmon.c	2003-05-22 22:06:39.000000000 +0000
@@ -14,6 +14,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
@@ -48,11 +49,6 @@
 #define setjmp xmon_setjmp
 #define longjmp xmon_longjmp
 
-#define memlist_entry list_entry
-#define memlist_next(x) ((x)->next)
-#define memlist_prev(x) ((x)->prev)
-
-
 /* Max number of stack frames we are willing to produce on a backtrace. */
 #define MAXFRAMECOUNT 50
 
@@ -119,15 +115,12 @@
 static void cpu_cmd(void);
 #endif /* CONFIG_SMP */
 static void csum(void);
+static void bootcmds(void);
 static void mem_translate(void);
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(void);
-static void mem_check_pagetable_vsids (void);
 
-static void mem_map_check_slab(void);
-static void mem_map_lock_pages(void);
-static void mem_check_dup_rpn (void);
 static void debug_trace(void);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
@@ -144,6 +137,14 @@
 
 #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
 
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
+#define isalnum(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'z') \
+			 || ('A' <= (c) && (c) <= 'Z'))
+#define isspace(c)	(c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
+
 static char *help_string = "\
 Commands:\n\
   b	show breakpoints\n\
@@ -173,14 +174,14 @@
   t	print backtrace\n\
   T	Enable/Disable PPCDBG flags\n\
   x	exit monitor\n\
-  z	reboot\n\
-  Z	halt\n\
 ";
 
 static int xmon_trace[NR_CPUS];
 #define SSTEP	1		/* stepping because of 's' command */
 #define BRSTEP	2		/* stepping over breakpoint */
 
+static struct pt_regs *xmon_regs[NR_CPUS];
+
 /*
  * Stuff for reading and writing memory safely
  */
@@ -292,7 +293,6 @@
 			std	29,232(%0)\n\
 			std	30,240(%0)\n\
 			std	31,248(%0)" : : "b" (&regs));
-		printf("xmon called\n");
 		/* Fetch the link reg for this stack frame.
 		 NOTE: the prev printf fills in the lr. */
 		regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
@@ -306,6 +306,7 @@
 
 	msr = get_msr();
 	set_msrd(msr & ~MSR_EE);	/* disable interrupts */
+	xmon_regs[smp_processor_id()] = excp;
 	excprint(excp);
 #ifdef CONFIG_SMP
 	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
@@ -325,14 +326,15 @@
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else if (at_breakpoint(excp->nip)) {
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else {
 		xmon_trace[smp_processor_id()] = 0;
 		insert_bpts();
 	}
+	xmon_regs[smp_processor_id()] = 0;
 #ifdef CONFIG_SMP
 	clear_bit(0, &got_xmon);
 	clear_bit(smp_processor_id(), &cpus_in_xmon);
@@ -340,85 +342,6 @@
 	set_msrd(msr);		/* restore interrupt enable */
 }
 
-/* Code can call this to get a backtrace and continue. */
-void
-xmon_backtrace(const char *fmt, ...)
-{
-	va_list ap;
-	struct pt_regs regs;
-
-
-	/* Ok, grab regs as they are now.
-	 This won't do a particularily good job because the
-	 prologue has already been executed.
-	 ToDo: We could reach back into the callers save
-	 area to do a better job of representing the
-	 caller's state.
-	 */
-	asm volatile ("std	0,0(%0)\n\
-	    std	1,8(%0)\n\
-	    std	2,16(%0)\n\
-	    std	3,24(%0)\n\
-	    std	4,32(%0)\n\
-	    std	5,40(%0)\n\
-	    std	6,48(%0)\n\
-	    std	7,56(%0)\n\
-	    std	8,64(%0)\n\
-	    std	9,72(%0)\n\
-	    std	10,80(%0)\n\
-	    std	11,88(%0)\n\
-	    std	12,96(%0)\n\
-	    std	13,104(%0)\n\
-	    std	14,112(%0)\n\
-	    std	15,120(%0)\n\
-	    std	16,128(%0)\n\
-	    std	17,136(%0)\n\
-	    std	18,144(%0)\n\
-	    std	19,152(%0)\n\
-	    std	20,160(%0)\n\
-	    std	21,168(%0)\n\
-	    std	22,176(%0)\n\
-	    std	23,184(%0)\n\
-	    std	24,192(%0)\n\
-	    std	25,200(%0)\n\
-	    std	26,208(%0)\n\
-	    std	27,216(%0)\n\
-	    std	28,224(%0)\n\
-	    std	29,232(%0)\n\
-	    std	30,240(%0)\n\
-	    std	31,248(%0)" : : "b" (&regs));
-	/* Fetch the link reg for this stack frame.
-	 NOTE: the prev printf fills in the lr. */
-	regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
-	regs.msr = get_msr();
-	regs.ctr = get_ctr();
-	regs.xer = get_xer();
-	regs.ccr = get_cr();
-	regs.trap = 0;
-
-	va_start(ap, fmt);
-	xmon_vfprintf(stdout, fmt, ap);
-	xmon_putc('\n', stdout);
-	va_end(ap);
-	take_input("\n");
-	backtrace(&regs);
-}
-
-/* Call this to poll for ^C during busy operations.
- * Returns true if the user has hit ^C.
- */
-int
-xmon_interrupted(void)
-{
-	int ret = xmon_read_poll();
-	if (ret == 3) {
-		printf("\n^C interrupted.\n");
-		return 1;
-	}
-	return 0;
-}
-
-
 void
 xmon_irq(int irq, void *d, struct pt_regs *regs)
 {
@@ -443,7 +366,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 		xmon(regs);
@@ -473,7 +396,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		dabr.instr = regs->nip;
 		xmon(regs);
@@ -489,7 +412,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		xmon(regs);
 	}
@@ -519,7 +442,7 @@
 	int i;
 	struct bpt *bp;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -550,7 +473,7 @@
 	struct bpt *bp;
 	unsigned instr;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		set_dabr(0);
@@ -597,14 +520,6 @@
 			cmd = inchar();
 		}
 		switch (cmd) {
-		case 'z':
-			printf("Rebooting machine now...");
-			machine_restart(NULL);
-			break;
-		case 'Z':
-			printf("Halting machine now...");
-			machine_halt();
-			break;
 		case 'm':
 			cmd = inchar();
 			switch (cmd) {
@@ -625,27 +540,15 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'j':
-				mem_map_check_slab();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
 			case 'e':
 				mem_find_vsid();
 				break;
-			case 'r':
-				mem_check_dup_rpn();
-				break;           
 			case 'i':
 				show_mem();
 				break;
-			case 'o':
-				mem_check_pagetable_vsids ();
-				break;
-			case 'q':
-				mem_map_lock_pages() ;
-				break;
 			default:
 				termch = cmd;
 				memex();
@@ -700,6 +603,8 @@
 			cpu_cmd();
 			break;
 #endif /* CONFIG_SMP */
+		case 'z':
+			bootcmds();
 		case 'T':
 			debug_trace();
 			break;
@@ -718,6 +623,19 @@
 	}
 }
 
+static void bootcmds(void)
+{
+	int cmd;
+
+	cmd = inchar();
+	if (cmd == 'r')
+		ppc_md.restart(NULL);
+	else if (cmd == 'h')
+		ppc_md.halt();
+	else if (cmd == 'p')
+		ppc_md.power_off();
+}
+
 #ifdef CONFIG_SMP
 static void cpu_cmd(void)
 {
@@ -739,7 +657,7 @@
 		printf("cpus stopped:");
 		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
 			if (test_bit(cpu, &cpus_in_xmon)) {
-				printf(" %d", cpu);
+				printf(" %x", cpu);
 				if (cpu == smp_processor_id())
 					printf("*", cpu);
 			}
@@ -870,6 +788,7 @@
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
 		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+			printf("Not implemented on POWER4\n");
 			break;
 		}
 		iabr.address = 0;
@@ -972,7 +891,9 @@
 	case 0x100:	ret = "(System Reset)"; break; 
 	case 0x200:	ret = "(Machine Check)"; break; 
 	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x380:	ret = "(Data SLB Access)"; break;
 	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x480:	ret = "(Instruction SLB Access)"; break;
 	case 0x500:	ret = "(Hardware Interrupt)"; break; 
 	case 0x600:	ret = "(Alignment)"; break; 
 	case 0x700:	ret = "(Program Check)"; break; 
@@ -1120,7 +1041,7 @@
 	printf("    sp: %lx\n", fp->gpr[1]);
 	printf("   msr: %lx\n", fp->msr);
 
-	if (fp->trap == 0x300 || fp->trap == 0x600) {
+	if (fp->trap == 0x300 || fp->trap == 0x380 || fp->trap == 0x600) {
 		printf("   dar: %lx\n", fp->dar);
 		printf(" dsisr: %lx\n", fp->dsisr);
 	}
@@ -1296,34 +1217,6 @@
 	scannl();
 }
 
-#if 0
-static void
-openforth()
-{
-	int c;
-	char *p;
-	char cmd[1024];
-	int args[5];
-	extern int (*prom_entry)(int *);
-
-	p = cmd;
-	c = skipbl();
-	while (c != '\n') {
-		*p++ = c;
-		c = inchar();
-	}
-	*p = 0;
-	args[0] = (int) "interpret";
-	args[1] = 1;
-	args[2] = 1;
-	args[3] = (int) cmd;
-	(*prom_entry)(args);
-	printf("\n");
-	if (args[4] != 0)
-		printf("error %x\n", args[4]);
-}
-#endif
-
 #ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
@@ -1538,7 +1431,18 @@
 static void
 handle_fault(struct pt_regs *regs)
 {
-	fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+	switch (regs->trap) {
+	case 0x200:
+		fault_type = 0;
+		break;
+	case 0x300:
+	case 0x380:
+		fault_type = 1;
+		break;
+	default:
+		fault_type = 2;
+	}
+
 	longjmp(bus_error_jmp, 1);
 }
 
@@ -2011,6 +1915,16 @@
 	return c;
 }
 
+#define N_PTREGS	44
+static char *regnames[N_PTREGS] = {
+	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+	"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+	"pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
+	"trap", "dar", "dsisr", "res"
+};
+
 int
 scanhex(vp)
 unsigned long *vp;
@@ -2019,6 +1933,36 @@
 	unsigned long v;
 
 	c = skipbl();
+	if (c == '%') {
+		/* parse register name */
+		char regname[8];
+		int i;
+
+		for (i = 0; i < sizeof(regname) - 1; ++i) {
+			c = inchar();
+			if (!isalnum(c)) {
+				termch = c;
+				break;
+			}
+			regname[i] = c;
+		}
+		regname[i] = 0;
+		for (i = 0; i < N_PTREGS; ++i) {
+			if (strcmp(regnames[i], regname) == 0) {
+				unsigned long *rp = (unsigned long *)
+					xmon_regs[smp_processor_id()];
+				if (rp == NULL) {
+					printf("regs not available\n");
+					return 0;
+				}
+				*vp = rp[i];
+				return 1;
+			}
+		}
+		printf("invalid register name '%%%s'\n", regname);
+		return 0;
+	}
+
 	d = hexdigit(c);
 	if( d == EOF ){
 		termch = c;
@@ -2440,249 +2384,6 @@
 	printf("\nDone -------------------\n");
 }
 
-void mem_map_check_slab()
-{
-	int i, slab_count;
-
-	i = max_mapnr;
-	slab_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageSlab(mem_map+i)){
-			printf(" slab entry - mem_map entry =%p  \n", mem_map+i);
-			slab_count ++;
-		}
-	}
-
-	printf(" count of pages for slab = %d \n", slab_count);
-}
-
-void mem_map_lock_pages()
-{
-	int i, lock_count;
-
-	i = max_mapnr;
-	lock_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageLocked(mem_map+i)){
-			printf(" locked entry - mem_map entry =%p  \n", mem_map+i);
-			lock_count ++;
-		}
-	}
-
-	printf(" count of locked pages = %d \n", lock_count); 
-}
-
-void mem_check_dup_rpn ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	HPTE *hpte1, *hpte2;
-	int dup_count;
-	struct task_struct *p;
-	unsigned long kernel_vsid_c0,kernel_vsid_c1,kernel_vsid_c2,kernel_vsid_c3;
-	unsigned long kernel_vsid_c4,kernel_vsid_c5,kernel_vsid_d,kernel_vsid_e;
-	unsigned long kernel_vsid_f;
-	unsigned long vsid0,vsid1,vsidB,vsid2;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				dup_count = 0;
-				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-					if ( hpte2->dw0.dw0.v != 0 ) {
-						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-							dup_count++;
-						}
-					}
-				}
-				if(dup_count > 5) {
-					printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-					printf("    mem map array entry %p count = %d \n",
-					       (mem_map+(hpte1->dw1.dw1.rpn)), (mem_map+(hpte1->dw1.dw1.rpn))->count);
-					for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-						if ( hpte2->dw0.dw0.v != 0 ) {
-							if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-								printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
-								       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
-							}
-						}
-					}
-				}
-			} else {
-				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-		if (xmon_interrupted())
-			return;
-	}                                                                     
-
-
-
-	// print the kernel vsids
-	kernel_vsid_c0 =  get_kernel_vsid(0xC000000000000000);
-	kernel_vsid_c1 =  get_kernel_vsid(0xC000000010000000);
-	kernel_vsid_c2 =  get_kernel_vsid(0xC000000020000000);
-	kernel_vsid_c3 =  get_kernel_vsid(0xC000000030000000);
-	kernel_vsid_c4 =  get_kernel_vsid(0xC000000040000000);
-	kernel_vsid_c5 =  get_kernel_vsid(0xC000000050000000);
-	kernel_vsid_d  =  get_kernel_vsid(0xD000000000000000);
-	kernel_vsid_e  =  get_kernel_vsid(0xE000000000000000);
-	kernel_vsid_f  =  get_kernel_vsid(0xF000000000000000);
-
-	printf(" kernel vsid -  seg c0  = %lx\n",  kernel_vsid_c0 );
-	printf(" kernel vsid -  seg c1  = %lx\n",  kernel_vsid_c1 );
-	printf(" kernel vsid -  seg c2  = %lx\n",  kernel_vsid_c2 );
-	printf(" kernel vsid -  seg c3  = %lx\n",  kernel_vsid_c3 );
-	printf(" kernel vsid -  seg c4  = %lx\n",  kernel_vsid_c4 );
-	printf(" kernel vsid -  seg c5  = %lx\n",  kernel_vsid_c5 );
-	printf(" kernel vsid -  seg d   = %lx\n",  kernel_vsid_d );
-	printf(" kernel vsid -  seg e   = %lx\n",  kernel_vsid_e );
-	printf(" kernel vsid -  seg f   = %lx\n",  kernel_vsid_f );
-
-
-  // print a list of valid vsids for the tasks
-	read_lock(&tasklist_lock);
-	for_each_task(p)
-		if(p->mm) {
-			struct mm_struct *mm = p->mm; 
-			printf(" task = %p  mm =  %lx  pgd   %lx\n", 
-			       p, mm, mm->pgd);
-			vsid0 = get_vsid( mm->context, 0 );
-			vsid1 = get_vsid( mm->context, 0x10000000 );
-			vsid2 = get_vsid( mm->context, 0x20000000 );
-			vsidB = get_vsid( mm->context, 0xB0000000 );
-			printf("            context = %lx  vsid seg 0  = %lx\n",  mm->context, vsid0 );
-			printf("                           vsid seg 1  = %lx\n",  vsid1 );
-			printf("                           vsid seg 2  = %lx\n",  vsid2 );
-			printf("                           vsid seg 2  = %lx\n",  vsidB );
-	  
-			printf("\n");
-		};
-	read_unlock(&tasklist_lock);
-
-	printf("\nDone -------------------\n");
-}
-
-
-
-void mem_check_pagetable_vsids ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	struct task_struct *p;
-	unsigned long valid_table_count,invalid_table_count,bogus_rpn_count;
-	int found;
-	unsigned long user_address_table_count,kernel_page_table_count;
-	unsigned long pt_vsid;
-	HPTE *hpte1;
-
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	valid_table_count = 0;
-	invalid_table_count = 0;
-	bogus_rpn_count = 0;
-	user_address_table_count = 0;
-	kernel_page_table_count = 0;
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			valid_table_count++;
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				pt_vsid =  (hpte1->dw0.dw0.avpn) >> 5;
-				if ((pt_vsid == get_kernel_vsid(0xC000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000010000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000020000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000030000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000040000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000050000000)) |
-				    (pt_vsid == get_kernel_vsid(0xD000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xE000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xF000000000000000)) ) {
-					kernel_page_table_count ++;
-				} else {
-					read_lock(&tasklist_lock);
-					found = 0;
-					for_each_task(p) {
-						if(p->mm && (found == 0)) {
-							struct mm_struct *mm = p->mm; 
-	     
-							if ((pt_vsid == get_vsid( mm->context, 0 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x10000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x20000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x30000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x40000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x50000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x60000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x70000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x80000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x90000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xA0000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xB0000000 ))) {
-								user_address_table_count ++;
-								found = 1;
-							}
-						}
-					}
-					read_unlock(&tasklist_lock);
-					if (found == 0)
-					{
-						printf(" vsid not found vsid = %lx, hpte = %p  \n", 
-						       pt_vsid,hpte1);
-						printf("    rpn in entry = %lx \n", hpte1->dw1.dw1.rpn);
-						printf("    mem map address = %lx  \n", mem_map + (hpte1->dw1.dw1.rpn));
-           
-					} else //  found
-					{
-					}
-
-				}  // good rpn
-       
-			} else {
-				bogus_rpn_count ++;
-			}
-		} else {
-			invalid_table_count++;
-		}
-	}                                                                     
-
-
-	printf(" page table valid counts - valid entries = %lx  invalid entries =  %lx \n",
-	       valid_table_count, invalid_table_count);
-
-	printf("  bogus rpn entries ( probably io) = %lx \n", bogus_rpn_count);
-
- 
-  
-	printf(" page table counts - kernel entries = %lx  user entries =  %lx \n",
-	       kernel_page_table_count, user_address_table_count); 
-
-	printf("\nDone -------------------\n");
-
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/debug.c linux-2.4.21-rc3/arch/s390/kernel/debug.c
--- linux-2.4.20/arch/s390/kernel/debug.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/debug.c	2003-05-22 22:06:27.000000000 +0000
@@ -459,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if ((rc = copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size)))
-			return rc;
+			if (copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size))
+				return -EFAULT;
 		}
 		count += size;
 		entry_offset = 0;
@@ -744,8 +744,10 @@
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
+#ifdef DEBUG
                 printk(KERN_INFO 
 			"debug: %s: new level %i\n",id->name,id->level);
+#endif
         }
 	spin_unlock_irqrestore(&id->lock,flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/entry.S linux-2.4.21-rc3/arch/s390/kernel/entry.S
--- linux-2.4.20/arch/s390/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/entry.S	2003-05-22 22:06:28.000000000 +0000
@@ -556,7 +556,7 @@
         .long  sys_madvise
 	.long  sys_getdents64		 /* 220 */
         .long  sys_fcntl64 
-	.long  sys_ni_syscall
+	.long  sys_readahead
 	.long  sys_ni_syscall
 	.long  sys_ni_syscall		 /* 224 - reserved for setxattr  */
 	.long  sys_ni_syscall            /* 225 - reserved for lsetxattr */
@@ -599,13 +599,14 @@
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
 	SAVE_ALL __LC_PGM_OLD_PSW,1
+        l       %r3,__LC_PGM_ILC         # load program interruption code
+	la	%r8,0x7f
         l       %r7,BASED(.Ljump_table)
-        lh      %r8,__LC_PGM_INT_CODE
+	nr	%r8,%r3
         sll     %r8,2
 	GET_CURRENT
         l       %r7,0(%r8,%r7)		 # load address of handler routine
         la      %r2,SP_PTREGS(%r15)	 # address of register-save area
-        l       %r3,__LC_PGM_ILC         # load program interruption code
 	la      %r14,BASED(sysc_return)
 	br      %r7			 # branch to interrupt-handler
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/head.S linux-2.4.21-rc3/arch/s390/kernel/head.S
--- linux-2.4.20/arch/s390/kernel/head.S	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/head.S	2003-05-22 22:06:39.000000000 +0000
@@ -466,6 +466,18 @@
         mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 	
 #
+# clear bss memory
+#
+        l     %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
+        l     %r3,.Lbss_end-.LPG1(%r13) # end of bss
+        sr    %r3,%r2                   # length of bss
+        sr    %r4,%r4                   #
+        sr    %r5,%r5                   # set src,length and pad to zero
+        sr    %r0,%r0                   #
+        mvcle %r2,%r4,0                 # clear mem
+        jo    .-4                       # branch back, if not finish
+
+#
 # find memory chunks.
 #
 	mvc   __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
@@ -513,15 +525,29 @@
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
-	bno    .Lnovm-.LPG1(%r13)
+	bno    .Lchkpfix-.LPG1(%r13)
         oi     3(%r12),1                # set VM flag
-.Lnovm:
+#
+# we are running under VM, find out if we have PFIX
+#
+        mvc    __LC_PGM_NEW_PSW(8),.Lpcpfix-.LPG1(%r13)
+	lhi    %r0,0x4000
+	slr    %r2,%r2
+	.long  0x83200098		# diag 2,0,x'0098' - lock page
+	lhi    %r2,4
+	.long  0x83200098		# diag 2,0,x'0098' - unlock page
+	oi     3(%r12),128              # set PFIX flag
+.Lchkpfix:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    .Lnop390-.LPG1(%r13)
         oi     3(%r12),4                # set P/390 flag
 .Lnop390:
-
+	chi    %r0,0x2084		# new stidp format?
+	bne    .Loldfmt-.LPG1(%r13)
+	oi     3(%r12),64		# set new stidp flag
+.Loldfmt:	
+		
 #
 # find out if we have an IEEE fpu
 #
@@ -576,9 +602,12 @@
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
+.Lpcpfix:.long 0x00080000,0x80000000 + .Lchkpfix
 .Lmemsize:.long memory_size
 .Lmchunk:.long memory_chunk
 .Lmflags:.long machine_flags
+.Lbss_bgn:  .long  __bss_start
+.Lbss_end:  .long  _end
 
 	.org PARMAREA-64
 .Lduct:	.long 0,0,0,0,0,0,0,0
@@ -620,17 +649,6 @@
         ahi   %r15,-96
         xc    0(4,%r15),0(%r15)         # set backchain to zero
 
-#
-# clear bss memory
-#
-        l     %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
-        l     %r3,.Lbss_end-.LPG2(%r13) # end of bss
-        sr    %r3,%r2                   # length of bss
-        sr    %r4,%r4                   #
-        sr    %r5,%r5                   # set src,length and pad to zero
-        sr    %r0,%r0                   #
-        mvcle %r2,%r4,0                 # clear mem
-        jo    .-4                       # branch back, if not finish
 # check control registers
         stctl  %c0,%c15,0(%r15)
 	oi     2(%r15),0x20             # enable sigp external interrupts
@@ -651,7 +669,5 @@
 .Ldw:	    .long  0x000a0000,0x00000000
 .Linittu:   .long  init_task_union
 .Lstart:    .long  start_kernel
-.Lbss_bgn:  .long  __bss_start
-.Lbss_end:  .long  _end
-.Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+.Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/process.c linux-2.4.21-rc3/arch/s390/kernel/process.c
--- linux-2.4.20/arch/s390/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/process.c	2003-05-22 22:06:51.000000000 +0000
@@ -105,7 +105,7 @@
 		show_trace((unsigned long *) regs->gprs[15]);
 }
 
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
         int retval;
@@ -181,6 +181,8 @@
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
+	/* start process with ar4 pointing to the correct address space */
+	p->thread.ar4 = get_fs().ar4;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/s390_ksyms.c linux-2.4.21-rc3/arch/s390/kernel/s390_ksyms.c
--- linux-2.4.20/arch/s390/kernel/s390_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/s390_ksyms.c	2003-05-22 22:06:26.000000000 +0000
@@ -60,4 +60,5 @@
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL(pfix_table);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/setup.c linux-2.4.21-rc3/arch/s390/kernel/setup.c
--- linux-2.4.20/arch/s390/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/setup.c	2003-05-22 22:06:26.000000000 +0000
@@ -56,6 +56,8 @@
 unsigned long cpu_initialized = 0;
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
+void* *pfix_table=NULL;
+
 /*
  * Setup options
  */
@@ -317,6 +319,10 @@
 	printk((MACHINE_IS_VM) ?
 	       "We are running under VM (31 bit mode)\n" :
 	       "We are running native (31 bit mode)\n");
+	if (MACHINE_IS_VM)
+		printk((MACHINE_HAS_PFIX) ?
+		       "This machine has PFIX support\n" :
+		       "This machine has no PFIX support\n");
 	printk((MACHINE_HAS_IEEE) ?
 	       "This machine has an IEEE fpu\n" :
 	       "This machine has no IEEE fpu\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/signal.c linux-2.4.21-rc3/arch/s390/kernel/signal.c
--- linux-2.4.20/arch/s390/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/signal.c	2003-05-22 22:06:38.000000000 +0000
@@ -544,7 +544,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/time.c linux-2.4.21-rc3/arch/s390/kernel/time.c
--- linux-2.4.20/arch/s390/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/kernel/time.c	2003-05-22 22:06:24.000000000 +0000
@@ -182,13 +182,13 @@
 {
 	unsigned long cr0;
 
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
-	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
-	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/lib/uaccess.S linux-2.4.21-rc3/arch/s390/lib/uaccess.S
--- linux-2.4.20/arch/s390/lib/uaccess.S	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/lib/uaccess.S	2003-05-22 22:06:27.000000000 +0000
@@ -1,9 +1,9 @@
 /*
  *  arch/s390/lib/uaccess.S
- *    fixup routines for copy_{from|to}_user functions.
+ *    __copy_{from|to}_user functions.
  *
  *  s390
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  *  These functions have standard call interface
@@ -19,23 +19,26 @@
 	sacf	512
 0:	mvcle	%r2,%r4,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lr	%r2,%r5
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r3,-4096
-        sll	%r3,1
-        srl	%r3,1
-        n	%r3,__LC_TRANS_EXC_ADDR
-        sr	%r3,%r4
-        bm	4(%r1)
-3:      mvcle	%r2,%r4,0
-        b	4(%r1)
+2:	lhi	%r1,-4096
+	lr	%r3,%r4
+	slr	%r3,%r1      # %r3 = %r4 + 4096
+	nr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
+	slr	%r3,%r4      # %r3 = #bytes to next user page boundary
+	clr	%r5,%r3      # copy crosses next page boundary ?
+	jnh	1b           # no, this page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r2,%r4,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-	.long	0b,1b
-	.long	3b,2b
+	.long	0b,2b
+	.long	3b,1b
         .previous
 
         .align 4
@@ -46,23 +49,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lr	%r2,%r3
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r5,-4096
-        sll	%r5,1
-        srl	%r5,1
-        n	%r5,__LC_TRANS_EXC_ADDR
-        sr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lhi	%r1,-4096
+	lr	%r5,%r4
+	slr	%r5,%r1      # %r5 = %r4 + 4096
+	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clr	%r3,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-	.long   0b,1b
-        .long	3b,2b
+	.long	0b,2b
+	.long	3b,1b
         .previous
 
         .align 4
@@ -76,22 +82,27 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
-	lr	%r2,%r3
+1:	sacf	0
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r5,-4096
-        sll	%r5,1
-        srl	%r5,1
-        n	%r5,__LC_TRANS_EXC_ADDR
-        sr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lr	%r2,%r5
+	lhi	%r1,-4096
+	slr	%r5,%r1      # %r5 = %r4 + 4096
+	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clr	%r2,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+	slr	%r2,%r5
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
+4:	alr	%r2,%r5
+	j	1b
         .section __ex_table,"a"
-	.long   0b,1b
-        .long	3b,2b
+	.long	0b,2b
+        .long	3b,4b
         .previous
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/mm/init.c linux-2.4.21-rc3/arch/s390/mm/init.c
--- linux-2.4.20/arch/s390/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390/mm/init.c	2003-05-22 22:06:28.000000000 +0000
@@ -40,6 +40,7 @@
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
+extern unsigned long memory_size;
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -153,6 +154,11 @@
                         if (address >= end_mem)
                                 pte_clear(&pte);
                         set_pte(pg_table, pte);
+			if (address < memory_size) /* do not set storage
+						      key outside the storage
+						      or die */
+				set_access_key(pte); /* switch to our
+							access key */
                         address += PAGE_SIZE;
                 }
         }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/debug.c linux-2.4.21-rc3/arch/s390x/kernel/debug.c
--- linux-2.4.20/arch/s390x/kernel/debug.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/debug.c	2003-05-22 22:06:27.000000000 +0000
@@ -459,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if ((rc = copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size)))
-			return rc;
+			if (copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size))
+				return -EFAULT;
 		}
 		count += size;
 		entry_offset = 0;
@@ -744,8 +744,10 @@
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
+#ifdef DEBUG
                 printk(KERN_INFO 
 			"debug: %s: new level %i\n",id->name,id->level);
+#endif
         }
 	spin_unlock_irqrestore(&id->lock,flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/entry.S linux-2.4.21-rc3/arch/s390x/kernel/entry.S
--- linux-2.4.20/arch/s390x/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/entry.S	2003-05-22 22:06:39.000000000 +0000
@@ -589,7 +589,7 @@
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
 	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+	.long  SYSCALL(sys_readahead,sys_ni_syscall)
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr  */
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */
@@ -631,13 +631,14 @@
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
 	SAVE_ALL __LC_PGM_OLD_PSW,1
-	llgh    %r8,__LC_PGM_INT_CODE
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+	lghi	%r8,0x7f
+	ngr	%r8,%r3
         sll     %r8,3
 	GET_CURRENT
         larl    %r1,pgm_check_table
         lg      %r1,0(%r8,%r1)		 # load address of handler routine
         la      %r2,SP_PTREGS(%r15)	 # address of register-save area
-	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
 	larl	%r14,sysc_return
         br      %r1			 # branch to interrupt-handler
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/head.S linux-2.4.21-rc3/arch/s390x/kernel/head.S
--- linux-2.4.20/arch/s390x/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/head.S	2003-05-22 22:06:27.000000000 +0000
@@ -467,10 +467,21 @@
 	larl  %r12,_pstart               # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+
+#
+# clear bss memory
+#
+	larl  %r2,__bss_start           # start of bss segment
+        larl  %r3,_end                  # end of bss segment
+        sgr   %r3,%r2                   # length of bss
+        sgr   %r4,%r4                   #
+        sgr   %r5,%r5                   # set src,length and pad to zero
+        mvcle %r2,%r4,0                 # clear mem
+        jo    .-4                       # branch back, if not finish
+
 					 # set program check new psw mask
 	mvc   __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
 
-
 #
 # find memory chunks.
 #
@@ -537,11 +548,26 @@
 	tm     __LC_CPUID,0xff          # running under VM ?
 	bno    0f-.LPG1(%r13)
         oi     7(%r12),1                # set VM flag
+#
+# we are running under VM, find out if we have PFIX
+#
+	la     %r1,0f-.LPG1(%r13)       # set program check address
+	stg    %r1,__LC_PGM_NEW_PSW+8
+        lghi   %r0,0x4000
+	lghi   %r2,0
+	.long  0x83200098               # diag 2,0,x'0098' - lock page
+	lghi   %r2,4
+	.long  0x83200098               # diag 2,0,x'0098' - unlock page
+	oi     7(%r12),128              # set PFIX flag
 0:      lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    1f-.LPG1(%r13)
         oi     7(%r12),4                # set P/390 flag
 1:
+	chi    %r0,0x2084		# new stidp format?
+	bne    2f-.LPG1(%r13)
+	oi     7(%r12),64		# set new stidp flag
+2:	
 
 #
 # find out if we have the MVPG instruction
@@ -631,16 +657,7 @@
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
         xc    0(8,%r15),0(%r15)         # set backchain to zero
-#
-# clear bss memory
-#
-	larl  %r2,__bss_start           # start of bss segment
-        larl  %r3,_end                  # end of bss segment
-        sgr   %r3,%r2                   # length of bss
-        sgr   %r4,%r4                   #
-        sgr   %r5,%r5                   # set src,length and pad to zero
-        mvcle %r2,%r4,0                 # clear mem
-        jo    .-4                       # branch back, if not finish
+
 # check control registers
         stctg  %c0,%c15,0(%r15)
 	oi     6(%r15),0x20             # enable sigp external interrupts
@@ -658,5 +675,5 @@
 #
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
-.Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+.Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/process.c linux-2.4.21-rc3/arch/s390x/kernel/process.c
--- linux-2.4.20/arch/s390x/kernel/process.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/process.c	2003-05-22 22:06:28.000000000 +0000
@@ -102,7 +102,7 @@
 		show_trace((unsigned long *) regs->gprs[15]);
 }
 
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
         int retval;
@@ -178,6 +178,8 @@
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
+	/* start new process with ar4 pointing to the correct address space */
+	p->thread.ar4 = get_fs().ar4;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/s390_ksyms.c linux-2.4.21-rc3/arch/s390x/kernel/s390_ksyms.c
--- linux-2.4.20/arch/s390x/kernel/s390_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/s390_ksyms.c	2003-05-22 22:06:39.000000000 +0000
@@ -70,4 +70,5 @@
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL(pfix_table);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/setup.c linux-2.4.21-rc3/arch/s390x/kernel/setup.c
--- linux-2.4.20/arch/s390x/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/setup.c	2003-05-22 22:06:41.000000000 +0000
@@ -56,6 +56,8 @@
 unsigned long cpu_initialized = 0;
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
+void* *pfix_table=NULL;
+
 /*
  * Setup options
  */
@@ -317,6 +319,10 @@
 	printk((MACHINE_IS_VM) ?
 	       "We are running under VM (64 bit mode)\n" :
 	       "We are running native (64 bit mode)\n");
+	if (MACHINE_IS_VM)
+		printk((MACHINE_HAS_PFIX) ?
+		       "This machine has PFIX support\n" :
+		       "This machine has no PFIX support\n");
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/signal.c linux-2.4.21-rc3/arch/s390x/kernel/signal.c
--- linux-2.4.20/arch/s390x/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/signal.c	2003-05-22 22:06:48.000000000 +0000
@@ -548,7 +548,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/smp.c linux-2.4.21-rc3/arch/s390x/kernel/smp.c
--- linux-2.4.20/arch/s390x/kernel/smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/smp.c	2003-05-22 22:06:47.000000000 +0000
@@ -224,10 +224,6 @@
  */
 void smp_send_stop(void)
 {
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
         /* write magic number to zero page (absolute 0) */
         get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/time.c linux-2.4.21-rc3/arch/s390x/kernel/time.c
--- linux-2.4.20/arch/s390x/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/kernel/time.c	2003-05-22 22:06:39.000000000 +0000
@@ -155,13 +155,13 @@
 {
 	unsigned long cr0;
 
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
-	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
-	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/lib/uaccess.S linux-2.4.21-rc3/arch/s390x/lib/uaccess.S
--- linux-2.4.20/arch/s390x/lib/uaccess.S	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/lib/uaccess.S	2003-05-22 22:06:51.000000000 +0000
@@ -1,9 +1,9 @@
 /*
  *  arch/s390x/lib/uaccess.S
- *    fixup routines for copy_{from|to}_user functions.
+ *    __copy_{from|to}_user functions.
  *
- *  S390
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *  s390
+ *    Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  *  These functions have standard call interface
@@ -19,20 +19,26 @@
 	sacf	512
 0:	mvcle	%r2,%r4,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lgr	%r2,%r5
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:	lghi	%r3,-4096
-        ng	%r3,__LC_TRANS_EXC_ADDR
-        sgr	%r3,%r4
-        bm	4(%r1)
-3:      mvcle	%r2,%r4,0
-        b	4(%r1)
+2:	lghi	%r1,-4096
+	lgr	%r3,%r4
+	slgr	%r3,%r1      # %r3 = %r4 + 4096
+	ngr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
+	slgr	%r3,%r4      # %r3 = #bytes to next user page boundary
+	clgr	%r5,%r3      # copy crosses next page boundary ?
+	jnh	1b           # no, this page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r2,%r4,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-        .align	8
-	.quad	0b,1b
-	.quad	3b,2b
+	.quad	0b,2b
+	.quad	3b,1b
         .previous
 
         .align 4
@@ -43,20 +49,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lgr	%r2,%r3
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:      lghi	%r5,-4096
-        ng	%r5,__LC_TRANS_EXC_ADDR
-        sgr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lghi	%r1,-4096
+	lgr	%r5,%r4
+	slgr	%r5,%r1      # %r5 = %r4 + 4096
+	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clgr	%r3,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-        .align	8
-        .quad	0b,1b
-        .quad	3b,2b
+	.quad	0b,2b
+	.quad	3b,1b
         .previous
 
         .align 4
@@ -70,18 +82,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
-	lgr	%r2,%r5
+1:	sacf	0
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:      lghi	%r5,-4096
-        ng	%r5,__LC_TRANS_EXC_ADDR
-        sgr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lgr	%r2,%r5
+	lghi	%r1,-4096
+	slgr	%r5,%r1      # %r5 = %r4 + 4096
+	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clgr	%r2,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+	slgr	%r2,%r5
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
+4:	algr	%r2,%r5
+	j	1b
         .section __ex_table,"a"
-        .align	8
-        .quad	0b,1b
-        .quad	3b,2b
+	.quad	0b,2b
+        .quad	3b,4b
         .previous
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/mm/init.c linux-2.4.21-rc3/arch/s390x/mm/init.c
--- linux-2.4.20/arch/s390x/mm/init.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/s390x/mm/init.c	2003-05-22 22:06:40.000000000 +0000
@@ -40,6 +40,7 @@
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
+extern unsigned long memory_size;
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -233,6 +234,11 @@
                                         continue;
                                 }
                                 set_pte(pt_dir, pte);
+				if (address < memory_size ) /* do not set storage
+							       key outside the storage
+							       or die */
+					set_access_key(pte); /* switch to our
+								access key */
                                 address += PAGE_SIZE;
                         }
                 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/config.in linux-2.4.21-rc3/arch/sh/config.in
--- linux-2.4.20/arch/sh/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-rc3/arch/sh/config.in	2003-05-22 22:06:47.000000000 +0000
@@ -189,7 +189,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT
 fi
 
 source drivers/pci/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/kernel/irq_intc2.c linux-2.4.21-rc3/arch/sh/kernel/irq_intc2.c
--- linux-2.4.20/arch/sh/kernel/irq_intc2.c	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.21-rc3/arch/sh/kernel/irq_intc2.c	2003-05-22 22:06:50.000000000 +0000
@@ -107,7 +107,7 @@
 	}
 
 	disable_irq_nosync(irq);
-	/* Fill the the data we need */
+	/* Fill the data we need */
 	intc2_data[offset].addr=addr;
 	intc2_data[offset].mask=1<<pos;
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/kernel/process.c linux-2.4.21-rc3/arch/sh/kernel/process.c
--- linux-2.4.20/arch/sh/kernel/process.c	2001-10-15 20:36:48.000000000 +0000
+++ linux-2.4.21-rc3/arch/sh/kernel/process.c	2003-05-22 22:06:50.000000000 +0000
@@ -118,7 +118,7 @@
  * This is the mechanism for creating a new kernel thread.
  *
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
 	register unsigned long __sc0 __asm__ ("r0");
 	register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/config.in linux-2.4.21-rc3/arch/sparc/config.in
--- linux-2.4.20/arch/sparc/config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/config.in	2003-05-22 22:06:26.000000000 +0000
@@ -264,7 +264,15 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+fi
+
 endmenu
 
 source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/apc.c linux-2.4.21-rc3/arch/sparc/kernel/apc.c
--- linux-2.4.20/arch/sparc/kernel/apc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/apc.c	2003-05-22 22:06:47.000000000 +0000
@@ -22,7 +22,6 @@
 /* Debugging
  * 
  * #define APC_DEBUG_LED
- * #define APC_NO_IDLE
  */
 
 #define APC_MINOR	MISC_DYNAMIC_MINOR
@@ -31,10 +30,27 @@
 
 volatile static u8 *regs; 
 static int apc_regsize;
+static int apc_no_idle __initdata = 0;
 
 #define apc_readb(offs)			(sbus_readb(regs+offs))
 #define apc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
 
+/* Specify "apc=noidle" on the kernel command line to 
+ * disable APC CPU standby support.  Certain prototype
+ * systems (SPARCstation-Fox) do not play well with APC
+ * CPU idle, so disable this if your system has APC and 
+ * crashes randomly.
+ */
+static int __init apc_setup(char *str) 
+{
+	if(!strncmp(str, "noidle", strlen("noidle"))) {
+		apc_no_idle = 1;
+		return 1;
+	}
+	return 0;
+}
+__setup("apc=", apc_setup);
+
 /* 
  * CPU idle callback function
  * See .../arch/sparc/kernel/process.c
@@ -127,6 +143,7 @@
 	struct sbus_bus *sbus = NULL;
 	struct sbus_dev *sdev = NULL;
 	int iTmp = 0;
+
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sdev, sbus) {
 			if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
@@ -155,12 +172,12 @@
 		return -ENODEV;
 	}
 
-#ifndef APC_NO_IDLE	
 	/* Assign power management IDLE handler */
-	pm_idle = apc_swift_idle;	
-#endif
+	if(!apc_no_idle)
+		pm_idle = apc_swift_idle;	
 
-	printk(KERN_INFO "%s: power management initialized\n", APC_DEVNAME);
+	printk(KERN_INFO "%s: power management initialized%s\n", 
+		APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
 	return 0;
 }
 
@@ -169,3 +186,4 @@
  * initialized, so we install ourselves thusly:
  */
 __initcall(apc_probe);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/entry.S linux-2.4.21-rc3/arch/sparc/kernel/entry.S
--- linux-2.4.20/arch/sparc/kernel/entry.S	2001-11-13 17:16:05.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/entry.S	2003-05-22 22:06:43.000000000 +0000
@@ -1794,6 +1794,15 @@
 	retl
 	 nop
 
+	.globl	C_LABEL(ndelay)
+C_LABEL(ndelay):
+	save	%sp, -REGWIN_SZ, %sp
+	mov	%i0, %o0
+	call	.umul
+	 mov	5, %o1
+	ba	delay_continue
+	 nop
+
 	.globl	C_LABEL(udelay)
 C_LABEL(udelay):
 	save	%sp, -REGWIN_SZ, %sp
@@ -1801,6 +1810,7 @@
 	sethi	%hi(0x10c6), %o1
 	call	.umul
 	 or	%o1, %lo(0x10c6), %o1
+delay_continue:
 #ifndef CONFIG_SMP
 	sethi	%hi(C_LABEL(loops_per_jiffy)), %o3
 	call	.umul
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/ioport.c linux-2.4.21-rc3/arch/sparc/kernel/ioport.c
--- linux-2.4.20/arch/sparc/kernel/ioport.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/ioport.c	2003-05-22 22:06:53.000000000 +0000
@@ -221,19 +221,7 @@
 		pa += PAGE_SIZE;
 	}
 
-	/*
-	 * XXX Playing with implementation details here.
-	 * On sparc64 Ebus has resources with precise boundaries.
-	 * We share drivers with sparc64. Too clever drivers use
-	 * start of a resource instead of a base address.
-	 *
-	 * XXX-2 This may be not valid anymore, clean when
-	 * interface to sbus_ioremap() is resolved.
-	 */
-	res->start += offset;
-	res->end = res->start + sz - 1;		/* not strictly necessary.. */
-
-	return (void *) res->start;
+	return (void *) (res->start + offset);
 }
 
 /*
@@ -244,7 +232,7 @@
 	unsigned long plen;
 
 	plen = res->end - res->start + 1;
-	plen = (plen + PAGE_SIZE-1) & PAGE_MASK;
+	if ((plen & (PAGE_SIZE-1)) != 0) BUG();
 	while (plen != 0) {
 		plen -= PAGE_SIZE;
 		(*_sparc_unmapioaddr)(res->start + plen);
@@ -515,7 +503,7 @@
 	mmu_inval_dma_area(va, len_total);
 
 #if 1
-/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\n",
+/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n",
   (long)va, (long)res->start, (long)virt_to_phys(va), len_total);
 #endif
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/irq.c linux-2.4.21-rc3/arch/sparc/kernel/irq.c
--- linux-2.4.20/arch/sparc/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/irq.c	2003-05-22 22:06:25.000000000 +0000
@@ -72,7 +72,7 @@
     prom_halt();
 }
 
-void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
+void (*sparc_init_timers)(void (*)(int, void *,struct pt_regs *)) =
     (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;
 
 /*
@@ -92,7 +92,7 @@
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 int static_irq_count;
 
-struct irqaction *irq_action[NR_IRQS+1] = {
+struct irqaction *irq_action[NR_IRQS] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 };
@@ -110,7 +110,7 @@
 		
 		return sun4d_get_irq_list(buf);
 	}
-	for (i = 0 ; i < (NR_IRQS+1) ; i++) {
+	for (i = 0 ; i < NR_IRQS ; i++) {
 	        action = *(i + irq_action);
 		if (!action) 
 		        continue;
@@ -147,7 +147,7 @@
 		
 		return sun4d_free_irq(irq, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
         if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
                 printk("Trying to free bogus IRQ %d\n", irq);
@@ -382,7 +382,7 @@
 	struct irqaction * action;
 	unsigned int cpu_irq;
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
 
         printk("IO device interrupt, irq = %d\n", irq);
@@ -392,7 +392,7 @@
 		printk("Expecting: ");
         	for (i = 0; i < 16; i++)
                 	if (action->handler)
-                        	prom_printf("[%s:%d:0x%x] ", action->name,
+				printk("[%s:%d:0x%x] ", action->name,
 				    (int) i, (unsigned int) action->handler);
 	}
         printk("AIEEE\n");
@@ -461,7 +461,7 @@
 	extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
 #endif
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 	if(!handler)
@@ -551,7 +551,7 @@
 					     unsigned long, const char *, void *);
 		return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 
@@ -636,7 +636,7 @@
 	extern void sun4c_init_IRQ( void );
 	extern void sun4m_init_IRQ( void );
 	extern void sun4d_init_IRQ( void );
-    
+
 	switch(sparc_cpu_model) {
 	case sun4c:
 	case sun4:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/process.c linux-2.4.21-rc3/arch/sparc/kernel/process.c
--- linux-2.4.20/arch/sparc/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/process.c	2003-05-22 22:06:27.000000000 +0000
@@ -676,7 +676,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/signal.c linux-2.4.21-rc3/arch/sparc/kernel/signal.c
--- linux-2.4.20/arch/sparc/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/signal.c	2003-05-22 22:06:50.000000000 +0000
@@ -1241,7 +1241,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c linux-2.4.21-rc3/arch/sparc/kernel/sparc_ksyms.c
--- linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/sparc_ksyms.c	2003-05-22 22:06:26.000000000 +0000
@@ -151,6 +151,7 @@
 #endif
 
 EXPORT_SYMBOL(udelay);
+EXPORT_SYMBOL(ndelay);
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
 #if CONFIG_SUN_AUXIO
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4c_irq.c linux-2.4.21-rc3/arch/sparc/kernel/sun4c_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4c_irq.c	2001-04-27 05:17:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/sun4c_irq.c	2003-05-22 22:06:26.000000000 +0000
@@ -34,6 +34,7 @@
 #include <asm/sun4paddr.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
+#include <asm/sbus.h>
 
 #if 0
 static struct resource sun4c_timer_eb = { "sun4c_timer" };
@@ -51,13 +52,24 @@
  */
 unsigned char *interrupt_enable = 0;
 
+static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
+
+unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
+{
+	if (sbint >= sizeof(sun4c_pil_map)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4c_pil_map[sbint];
+}
+
 static void sun4c_disable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
@@ -86,7 +98,7 @@
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
@@ -213,6 +225,7 @@
 		    int_regs[0].reg_size, "sun4c_intr");
 	}
 
+	BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
@@ -221,7 +234,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4c_init_timers;
+	sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4d_irq.c linux-2.4.21-rc3/arch/sparc/kernel/sun4d_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4d_irq.c	2001-07-20 01:11:13.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/sun4d_irq.c	2003-05-22 22:06:24.000000000 +0000
@@ -251,6 +251,15 @@
 		return irq;
 }
 
+unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
+{
+	if (sbint >= sizeof(sbus_to_pil)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
+}
+
 int sun4d_request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, const char * devname, void *dev_id)
@@ -540,13 +549,14 @@
 {
 	__cli();
 
+	BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4d_init_timers;
+	sparc_init_timers = sun4d_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4m_irq.c linux-2.4.21-rc3/arch/sparc/kernel/sun4m_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4m_irq.c	2001-04-27 05:17:26.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/sun4m_irq.c	2003-05-22 22:06:47.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/sbus.h>
 
 static unsigned long dummy;
 
@@ -77,6 +78,17 @@
 	SUN4M_INT_SBUS(6)				  /* 14 irq 13 */
 };
 
+static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
+
+unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 
+{
+	if (sbint >= sizeof(sun4m_pil_map)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4m_pil_map[sbint] | 0x30;
+}
+
 inline unsigned long sun4m_get_irqmask(unsigned int irq)
 {
 	unsigned long mask;
@@ -366,6 +378,7 @@
 				&sun4m_interrupts->undirected_target;
 		sun4m_interrupts->undirected_target = 0;
 	}
+	BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
@@ -374,7 +387,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4m_init_timers;
+	sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/systbls.S linux-2.4.21-rc3/arch/sparc/kernel/systbls.S
--- linux-2.4.20/arch/sparc/kernel/systbls.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/systbls.S	2003-05-22 22:06:47.000000000 +0000
@@ -51,11 +51,11 @@
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 /*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-/*175*/	.long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-/*185*/	.long sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sys_newuname
+/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+/*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
+/*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/time.c linux-2.4.21-rc3/arch/sparc/kernel/time.c
--- linux-2.4.20/arch/sparc/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/kernel/time.c	2003-05-22 22:06:48.000000000 +0000
@@ -379,7 +379,7 @@
 	else
 		clock_probe();
 
-	init_timers(timer_interrupt);
+	sparc_init_timers(timer_interrupt);
 	
 #ifdef CONFIG_SUN4
 	if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/fault.c linux-2.4.21-rc3/arch/sparc/mm/fault.c
--- linux-2.4.20/arch/sparc/mm/fault.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/mm/fault.c	2003-05-22 22:06:40.000000000 +0000
@@ -139,7 +139,7 @@
 {
 	if((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
-		       "pointer dereference");
+		       "pointer dereference\n");
 	} else {
 		printk(KERN_ALERT "Unable to handle kernel paging request "
 		       "at virtual address %08lx\n", address);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/iommu.c linux-2.4.21-rc3/arch/sparc/mm/iommu.c
--- linux-2.4.20/arch/sparc/mm/iommu.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/mm/iommu.c	2003-05-22 22:06:42.000000000 +0000
@@ -188,7 +188,7 @@
 {
 	unsigned long page, oldpage = 0;
 
-	while(sz >= 0) {
+	while(sz != 0) {
 		sz--;
 		page = ((unsigned long) sg[sz].address) & PAGE_MASK;
 		if (oldpage == page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/sun4c.c linux-2.4.21-rc3/arch/sparc/mm/sun4c.c
--- linux-2.4.20/arch/sparc/mm/sun4c.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/mm/sun4c.c	2003-05-22 22:06:38.000000000 +0000
@@ -290,7 +290,7 @@
 		switch (idprom->id_machtype) {
 
 		case (SM_SUN4|SM_4_110):
-			sun4c_vacinfo.type = NONE;
+			sun4c_vacinfo.type = VAC_NONE;
 			sun4c_vacinfo.num_bytes = 0;
 			sun4c_vacinfo.linesize = 0;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -299,21 +299,21 @@
 			break;
 
 		case (SM_SUN4|SM_4_260):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_330):
-			sun4c_vacinfo.type = WRITE_THROUGH;
+			sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_470):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 32;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -324,7 +324,7 @@
 			prom_halt();
 		};
 	} else {
-		sun4c_vacinfo.type = WRITE_THROUGH;
+		sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 
 		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
 		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
@@ -386,7 +386,7 @@
 		daddr = &(dst);		\
 		iaddr = &(src);		\
 		*daddr = *iaddr;	\
-	} while (0);
+	} while (0)
 
 static void __init patch_kernel_fault_handler(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/prom/printf.c linux-2.4.21-rc3/arch/sparc/prom/printf.c
--- linux-2.4.20/arch/sparc/prom/printf.c	2000-02-09 02:23:13.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc/prom/printf.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,11 +1,15 @@
-/* $Id: printf.c,v 1.7 2000/02/08 20:24:23 davem Exp $
+/*
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* This routine is internal to the prom library, no one else should know
- * about or use it!  It's simple and smelly anyway....
+ * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * We used to warn all over the code: DO NOT USE prom_printf(),
+ * and yet people do. Anton's banking code was outputing banks
+ * with prom_printf for most of the 2.4 lifetime. Since an effective
+ * stick is not available, we deployed a carrot: an early printk
+ * through PROM by means of -p boot option. This ought to fix it.
+ * USE printk; if you need, deploy -p.
  */
 
 #include <linux/kernel.h>
@@ -16,23 +20,27 @@
 static char ppbuf[1024];
 
 void
+prom_write(const char *buf, unsigned int n)
+{
+	char ch;
+
+	while (n != 0) {
+		--n;
+		if ((ch = *buf++) == '\n')
+			prom_putchar('\r');
+		prom_putchar(ch);
+	}
+}
+
+void
 prom_printf(char *fmt, ...)
 {
 	va_list args;
-	char ch, *bptr;
 	int i;
 
 	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
+	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
-	return;
+
+	prom_write(ppbuf, i);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/Makefile linux-2.4.21-rc3/arch/sparc64/Makefile
--- linux-2.4.20/arch/sparc64/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/Makefile	2003-05-22 22:06:53.000000000 +0000
@@ -17,6 +17,7 @@
 NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
+INLINE_LIMIT := $(shell if $(CC) -m64 -finline-limit=100000 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 
 export NEW_GCC
 
@@ -48,6 +49,10 @@
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
 endif
 
+ifeq ($(INLINE_LIMIT),y)
+  CFLAGS := $(CFLAGS) -finline-limit=100000
+endif
+
 ifeq ($(CONFIG_MCOUNT),y)
   CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
   CFLAGS := $(CFLAGS) -pg
@@ -80,9 +85,6 @@
 vmlinux.aout: vmlinux
 	$(ELFTOAOUT) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
 
-archclean:
-	rm -f $(TOPDIR)/vmlinux.aout
-
 archmrproper:
 	rm -f $(TOPDIR)/include/asm-sparc64/asm_offsets.h
 
@@ -91,5 +93,14 @@
 check_asm: include/linux/version.h
 	$(MAKE) -C arch/sparc64/kernel check_asm
 
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+archclean:
+	@$(MAKEBOOT) clean
+
 tftpboot.img:
-	$(MAKE) -C arch/sparc64/boot tftpboot.img
+	@$(MAKEBOOT) tftpboot.img
+
+image:
+	@$(MAKEBOOT) image
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/boot/Makefile linux-2.4.21-rc3/arch/sparc64/boot/Makefile
--- linux-2.4.20/arch/sparc64/boot/Makefile	1998-01-12 23:15:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/boot/Makefile	2003-05-22 22:06:24.000000000 +0000
@@ -19,5 +19,10 @@
 piggyback: piggyback.c
 	$(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
 
+image: $(TOPDIR)/vmlinux
+	$(STRIP) -R .comment -R .note $(TOPDIR)/vmlinux -o $@
+
 dep:
 
+clean:
+	rm -f tftpboot.img piggyback image
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/defconfig linux-2.4.21-rc3/arch/sparc64/defconfig
--- linux-2.4.20/arch/sparc64/defconfig	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/defconfig	2003-05-22 22:06:40.000000000 +0000
@@ -269,15 +269,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
@@ -291,8 +282,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -301,40 +292,44 @@
 # 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_AEC62XX=m
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_AMD74XX=m
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
 # CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_PIIX=m
 CONFIG_BLK_DEV_NS87415=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
 # CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
 # CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_RZ1000=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SIS5513=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
 CONFIG_BLK_DEV_IDE_MODES=y
 CONFIG_BLK_DEV_ATARAID=m
 CONFIG_BLK_DEV_ATARAID_PDC=m
 CONFIG_BLK_DEV_ATARAID_HPT=m
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -405,6 +400,7 @@
 #
 CONFIG_FUSION=m
 # CONFIG_FUSION_BOOT is not set
+CONFIG_FUSION_MAX_SGE=40
 CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 CONFIG_FUSION_LAN=m
@@ -466,6 +462,7 @@
 # CONFIG_ELMC is not set
 # CONFIG_ELMC_II is not set
 CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
@@ -473,6 +470,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=m
+# CONFIG_AMD8111_ETH is not set
 CONFIG_ADAPTEC_STARFIRE=m
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -483,6 +481,7 @@
 CONFIG_DGRS=m
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
 # CONFIG_LNE390 is not set
 CONFIG_FEALNX=m
@@ -518,6 +517,7 @@
 CONFIG_NS83820=m
 # CONFIG_HAMACHI is not set
 CONFIG_YELLOWFIN=m
+# CONFIG_R8169 is not set
 CONFIG_SK98LIN=m
 CONFIG_TIGON3=m
 CONFIG_FDDI=y
@@ -760,7 +760,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -775,7 +774,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
-CONFIG_USB_BLUETOOTH=m
+
+#
+#   USB Bluetooth can only be used with disabled Bluetooth subsystem
+#
 CONFIG_USB_MIDI=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -798,6 +800,8 @@
 # CONFIG_USB_HIDDEV is not set
 CONFIG_USB_AIPTEK=m
 CONFIG_USB_WACOM=m
+CONFIG_USB_KBTAB=m
+CONFIG_USB_POWERMATE=m
 
 #
 # USB Imaging devices
@@ -812,6 +816,7 @@
 # USB Multimedia devices
 #
 CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
 CONFIG_USB_OV511=m
 CONFIG_USB_PWC=m
 CONFIG_USB_SE401=m
@@ -862,9 +867,12 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
 CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
 CONFIG_USB_SERIAL_PL2303=m
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
@@ -885,9 +893,11 @@
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
 CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
 CONFIG_BLUEZ_BNEP=m
-CONFIG_BNEP_MC_FILTER=y
-CONFIG_BNEP_PROTO_FILTER=y
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
 
 #
 # Bluetooth device drivers
@@ -896,9 +906,12 @@
 CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
 # CONFIG_BLUEZ_HCIBT3C is not set
 # CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/Makefile linux-2.4.21-rc3/arch/sparc64/kernel/Makefile
--- linux-2.4.20/arch/sparc64/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/Makefile	2003-05-22 22:06:28.000000000 +0000
@@ -54,9 +54,12 @@
 	fi
 	@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
 	@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
-	@echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h
-	@echo -e "#include <linux/config.h>\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
+	@echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#include <linux/config.h>" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
@@ -86,8 +89,10 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#else /* CONFIG_SMP */" >> asm_offsets.h
+	@echo "#ifndef CONFIG_DEBUG_SPINLOCK" >>asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
@@ -119,7 +124,9 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#else /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
 	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
@@ -148,8 +155,10 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
-	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
+	@echo "#endif /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
 	  if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/binfmt_elf32.c linux-2.4.21-rc3/arch/sparc64/kernel/binfmt_elf32.c
--- linux-2.4.20/arch/sparc64/kernel/binfmt_elf32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/binfmt_elf32.c	2003-05-22 22:06:40.000000000 +0000
@@ -149,7 +149,6 @@
 #ifdef CONFIG_BINFMT_ELF32_MODULE
 #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
 #endif
-#define ELF_FLAGS_INIT	current->thread.flags |= SPARC_FLAG_32BIT
 
 MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
 MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/entry.S linux-2.4.21-rc3/arch/sparc64/kernel/entry.S
--- linux-2.4.20/arch/sparc64/kernel/entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/entry.S	2003-05-22 22:06:24.000000000 +0000
@@ -272,7 +272,7 @@
 	.align		32
 fp_other_bounce:
 	call		do_fpother
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -499,7 +499,7 @@
 	ba,pt		%xcc, etrap
 109:	 or		%g7, %lo(109b), %g7
 	call		catch_disabled_ivec
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -606,7 +606,7 @@
 	done
 utrap_ill:
         call		bad_trap
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -711,7 +711,7 @@
 	mov		11, %o0
 	mov		0, %o1
 	call		sparc_floppy_irq
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+	 add		%sp, PTREGS_OFF, %o2
 
 	b,pt		%xcc, rtrap
 	 clr		%l6
@@ -757,7 +757,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -778,7 +778,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		instruction_access_exception_tl1
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -797,7 +797,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		instruction_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -889,7 +889,7 @@
 
 	mov	%l5, %o1
 	call	cee_log
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o2
+	 add	%sp, PTREGS_OFF, %o2
 	ba,a,pt	%xcc, rtrap_clr_l6
 
 	/* Capture I/D/E-cache state into per-cpu error scoreboard.
@@ -1104,7 +1104,7 @@
 	 rd		%pc, %g7
 	mov		0x0, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1134,7 +1134,7 @@
 	 rd		%pc, %g7
 	mov		0x1, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1196,7 +1196,7 @@
 1:	or		%g7, %lo(1b), %g7
 	mov		0x2, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1234,7 +1234,7 @@
 1:	or		%g7, %lo(1b), %g7
 	mov		0x3, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
@@ -1290,7 +1290,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_fecc_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	/* Our caller has disabled I-cache and performed membar Sync. */
@@ -1316,7 +1316,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_cee_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	/* Our caller has disabled I-cache+D-cache and performed membar Sync. */
@@ -1342,7 +1342,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_deferred_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		__do_privact
@@ -1354,7 +1354,7 @@
 	ba,pt		%xcc, etrap
 109:	or		%g7, %lo(109b), %g7
 	call		do_privact
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1381,7 +1381,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1399,7 +1399,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		handle_lddfmna
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1417,14 +1417,14 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		handle_stdfmna
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
 	.globl	breakpoint_trap
 breakpoint_trap:
 	call		sparc_breakpoint
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 nop
 
@@ -1460,9 +1460,9 @@
 	call	sys_getppid
 	 nop
 	call	sys_getpid
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	/* SunOS getuid() returns uid in %o0 and euid in %o1 */
 	.globl	sunos_getuid
@@ -1470,9 +1470,9 @@
 	call	sys32_geteuid16
 	 nop
 	call	sys32_getuid16
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	/* SunOS getgid() returns gid in %o0 and egid in %o1 */
 	.globl	sunos_getgid
@@ -1480,9 +1480,9 @@
 	call	sys32_getegid16
 	 nop
 	call	sys32_getgid16
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 #endif
 
 	/* SunOS's execv() call only specifies the argv argument, the
@@ -1494,14 +1494,14 @@
 	ba,pt		%xcc, execve_merge
 	 or		%g1, %lo(sparc_execve), %g1
 sunos_execv:
-	stx		%g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+	stx		%g0, [%sp + PTREGS_OFF + PT_V9_I2]
 sys32_execve:
 	sethi		%hi(sparc32_execve), %g1
 	or		%g1, %lo(sparc32_execve), %g1
 execve_merge:
 	flushw
 	jmpl		%g1, %g0
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	.globl	sys_pipe, sys_sigpause, sys_nis_syscall
 	.globl	sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
@@ -1512,12 +1512,12 @@
 	.globl	sys32_sigstack
 	.align	32
 sys_pipe:	ba,pt		%xcc, sparc_pipe
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		 add		%sp, PTREGS_OFF, %o0
 sys_nis_syscall:ba,pt		%xcc, c_sys_nis_syscall
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		 add		%sp, PTREGS_OFF, %o0
 sys_memory_ordering:
 		ba,pt		%xcc, sparc_memory_ordering
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+		 add		%sp, PTREGS_OFF, %o1
 sys_sigaltstack:ba,pt		%xcc, do_sigaltstack
 		 add		%i6, STACK_BIAS, %o2
 sys32_sigstack:	ba,pt		%xcc, do_sys32_sigstack
@@ -1527,41 +1527,41 @@
 		 mov		%i6, %o2
 
 		.align		32
-sys_sigsuspend:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_sigsuspend:	add		%sp, PTREGS_OFF, %o0
 		call		do_sigsuspend
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		add		%sp, PTREGS_OFF, %o2
 		call		do_rt_sigsuspend
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
 		srl		%o0, 0, %o0
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		add		%sp, PTREGS_OFF, %o2
 		call		do_rt_sigsuspend32
 		 add		%o7, 1f-.-4, %o7
 		/* NOTE: %o0 has a correct value already */
-sys_sigpause:	add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+sys_sigpause:	add		%sp, PTREGS_OFF, %o1
 		call		do_sigpause
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_sigreturn32
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys_rt_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_rt_sigreturn
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_rt_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_rt_sigreturn32
 		 add		%o7, 1f-.-4, %o7
 		nop
-sys_ptrace:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_ptrace:	add		%sp, PTREGS_OFF, %o0
 		call		do_ptrace
 		 add		%o7, 1f-.-4, %o7
 		nop
@@ -1612,7 +1612,7 @@
 		movrz		%o1, %fp, %o1
 		mov		0, %o3
 		ba,pt		%xcc, do_fork
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		 add		%sp, PTREGS_OFF, %o2
 ret_from_syscall:
 		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
 		 * %o7 for us.  Check performance counter stuff too.
@@ -1638,7 +1638,7 @@
 		rd		%pic, %g0
 
 1:		b,pt		%xcc, ret_sys_call
-		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+		 ldx		[%sp + PTREGS_OFF + PT_V9_I0], %o0
 sparc_exit:	wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate
 		rdpr		%otherwin, %g1
 		rdpr		%cansave, %g3
@@ -1686,7 +1686,7 @@
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
 	call		syscall_trace_entry
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	srl		%i0, 0, %o0
 #endif
 	mov		%i4, %o4				! IEU1
@@ -1714,7 +1714,7 @@
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
 	call		syscall_trace_entry
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	mov		%i0, %o0
 #endif
 	mov		%i1, %o1				! IEU1
@@ -1731,16 +1731,16 @@
 	 mov		%i5, %o5				! IEU0
 	nop
 
-3:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+3:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 ret_sys_call:
 #ifdef SYSCALL_TRACING
 	mov		%o0, %o1
 	call		syscall_trace_exit
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	mov		%o1, %o0
 #endif
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
+	ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
 	cmp		%o0, -ENOIOCTLCMD
@@ -1749,12 +1749,12 @@
 
 	 andcc		%l0, 0x02, %l6	
 	andn		%g3, %g2, %g3		/* System call success, clear Carry condition code. */
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]	
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2				         ! npc = npc+4
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt		%xcc, rtrap_clr_l6
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 1:
 	/* System call failure, set Carry condition code.
@@ -1762,21 +1762,21 @@
 	 */
 	sub		%g0, %o0, %o0
 	or		%g3, %g2, %g3
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	mov		1, %l6
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2				         !npc = npc+4
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 
 	b,pt		%xcc, rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
 	call		syscall_trace
 	 nop
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt		%xcc, rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 	.align		32
 	.globl		__flushw_user
@@ -1793,69 +1793,3 @@
 	 restore	%g0, %g0, %g0
 2:	retl
 	 nop
-
-/* This need not obtain the xtime_lock as it is coded in
- * an implicitly SMP safe way already.
- */
-	.align		64
-	.globl		do_gettimeofday
-do_gettimeofday:	/* %o0 = timevalp */
-	/* Load doubles must be used on xtime so that what we get
-	 * is guarenteed to be atomic, this is why we can run this
-	 * with interrupts on full blast.  Don't touch this... -DaveM
-	 *
-	 * Note with time_t changes to the timeval type, I must now use
-	 * nucleus atomic quad 128-bit loads.
-	 *
-	 * If xtime was stored recently, I've seen crap from the
-	 * quad load on Cheetah.  Putting a membar SYNC before
-	 * the quad load seems to make the problem go away. -DaveM
-	 * (we should nop out workarounds like this on spitfire)
-	 */
-	sethi	%hi(timer_tick_offset), %g3
-	sethi	%hi(xtime), %g2
-	sethi	%hi(timer_tick_compare), %g1
-	ldx	[%g3 + %lo(timer_tick_offset)], %g3
-	or	%g2, %lo(xtime), %g2
-	or	%g1, %lo(timer_tick_compare), %g1
-1:	membar	#Sync
-	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
-	BRANCH_IF_ANY_CHEETAH(o2,o1,2f)
-	ba,pt	%xcc, 3f
-	 rd	%tick, %o1
-2:	ba,pt	%xcc, 3f
-	 rd	%asr24, %o1
-3:	ldx	[%g1], %g7
-	membar	#Sync
-	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o2
-	xor	%o4, %o2, %o2
-	xor	%o5, %o3, %o3
-	orcc	%o2, %o3, %g0
-	bne,pn	%xcc, 1b
-	 sethi	%hi(wall_jiffies), %o2
-	sethi	%hi(jiffies), %o3
-	ldx	[%o2 + %lo(wall_jiffies)], %o2
-	ldx	[%o3 + %lo(jiffies)], %o3
-	sub	%o3, %o2, %o2
-	sethi	%hi(timer_ticks_per_usec_quotient), %o3
-	add	%g3, %o1, %o1
-	ldx	[%o3 + %lo(timer_ticks_per_usec_quotient)], %o3
-	sub	%o1, %g7, %o1
-	mulx	%o3, %o1, %o1
-	brz,pt	%o2, 1f
-	 srlx	%o1, 32, %o1
-	sethi	%hi(10000), %g2
-	or	%g2, %lo(10000), %g2
-	add	%o1, %g2, %o1
-1:	sethi	%hi(1000000), %o2
-	srlx	%o5, 32, %o5
-	or	%o2, %lo(1000000), %o2
-	add	%o5, %o1, %o5
-	cmp	%o5, %o2
-	bl,a,pn	%xcc, 1f
-	 stx	%o4, [%o0 + 0x0]
-	add	%o4, 0x1, %o4
-	sub	%o5, %o2, %o5
-	stx	%o4, [%o0 + 0x0]
-1:	retl
-	 st	%o5, [%o0 + 0x8]
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/etrap.S linux-2.4.21-rc3/arch/sparc64/kernel/etrap.S
--- linux-2.4.20/arch/sparc64/kernel/etrap.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/etrap.S	2003-05-22 22:06:41.000000000 +0000
@@ -13,7 +13,7 @@
 #include <asm/head.h>
 #include <asm/processor.h>
 
-#define		TASK_REGOFF		(THREAD_SIZE-TRACEREG_SZ-REGWIN_SZ)
+#define		TASK_REGOFF		(THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ)
 #define		ETRAP_PSTATE1		(PSTATE_RMO | PSTATE_PRIV)
 #define		ETRAP_PSTATE2		(PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
 
@@ -32,7 +32,7 @@
 		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
 		or	%g1, %g3, %g1						! IEU0		Group
 		bne,pn	%xcc, 1f							! CTI
-		 sub	%sp, REGWIN_SZ+TRACEREG_SZ-STACK_BIAS, %g2		! IEU1
+		 sub	%sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2		! IEU1
 		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
 
 		sethi	%hi(TASK_REGOFF), %g2					! IEU0		Group		
@@ -44,12 +44,12 @@
 		wr	%g0, 0, %fprs						! Single	Group+4bubbles
 1:		rdpr	%tpc, %g3						! Single	Group
 
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]		! Store		Group
 		rdpr	%tnpc, %g1						! Single	Group
-		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
+		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]			! Store		Group
 		rd	%y, %g3							! Single	Group+4bubbles
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
-		st	%g3, [%g2 + REGWIN_SZ + PT_V9_Y]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]			! Store		Group
+		st	%g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]			! Store		Group
 		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
 		mov	%g6, %l6						! IEU0		Group
 
@@ -73,25 +73,25 @@
 
 		mov	%g7, %l2						! IEU1
 		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
-		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
-		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
-		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-
-		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
-		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]		! Store		Group
+		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]		! Store		Group
+		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]		! Store		Group
+
+		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]		! Store		Group
+		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]		! Store		Group
 		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
+		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]		! Store		Group
 
-		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]		! Store		Group
 		sllx	%g4, 32, %g4						! IEU0
-		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]		! Store		Group
 		wrpr	%g0, ETRAP_PSTATE2, %pstate				! Single	Group+4bubbles
 		jmpl	%l2 + 0x4, %g0						! CTI		Group
 		 mov	%l6, %g6						! IEU0
@@ -165,7 +165,7 @@
 		stx	%g1, [%g2 + STACK_BIAS + 0x80]
 
 		rdpr	%tstate, %g1						! Single	Group+4bubbles
-		sub	%g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+		sub	%g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2	! IEU1
 		ba,pt	%xcc, 1b						! CTI		Group
 		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
 
@@ -177,7 +177,7 @@
 		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
 		or	%g1, %g3, %g1						! IEU0		Group
 		bne,pn	%xcc, 1f						! CTI
-		 sub	%sp, (REGWIN_SZ+TRACEREG_SZ-STACK_BIAS), %g2		! IEU1
+		 sub	%sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2	! IEU1
 		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
 
 		sllx	%g1, 51, %g3						! IEU0		Group
@@ -187,11 +187,11 @@
 		 add	%g6, %g2, %g2						! IEU0		Group
 		wr	%g0, 0, %fprs						! Single	Group+4bubbles
 1:		rdpr	%tpc, %g3						! Single	Group
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]		! Store		Group
 
 		rdpr	%tnpc, %g1						! Single	Group
-		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
+		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]			! Store		Group
 		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
 		mov	%g6, %l6						! IEU0		Group
 		bne,pn	%xcc, 2f						! CTI		
@@ -212,34 +212,34 @@
 		mov	%g5, %l5						! IEU0		Group
 		add	%g7, 0x4, %l2						! IEU1
 		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
-		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
+		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]		! Store		Group
 		sllx	%l7, 24, %l7						! IEU0
 
-		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
+		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]		! Store		Group
 		rdpr	%cwp, %l0						! Single	Group
-		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
+		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]		! Store		Group
+		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]		! Store		Group
 		or	%l7, %l0, %l7						! IEU0
 		sethi	%hi(TSTATE_RMO | TSTATE_PEF), %l0			! IEU1
 
 		or	%l7, %l0, %l7						! IEU0		Group
 		wrpr	%l2, %tnpc						! Single	Group+4bubbles
 		wrpr	%l7, (TSTATE_PRIV | TSTATE_IE), %tstate			! Single	Group+4bubbles
-		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]		! Store		Group
 
 		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
-		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]		! Store		Group
+		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]		! Store		Group
 		sllx	%g4, 32, %g4						! IEU0
 		mov	%l6, %g6						! IEU1
-		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]		! Store		Group
 		done
 		nop
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/head.S linux-2.4.21-rc3/arch/sparc64/kernel/head.S
--- linux-2.4.20/arch/sparc64/kernel/head.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/head.S	2003-05-22 22:06:41.000000000 +0000
@@ -551,7 +551,7 @@
 	wr	%g0, ASI_P, %asi
 	mov	1, %g5
 	sllx	%g5, THREAD_SHIFT, %g5
-	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	sub	%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
 	add	%g6, %g5, %sp
 	mov	0, %fp
 
@@ -673,7 +673,9 @@
 #endif
 
 	/* Kill PROM timer */
-	wr	%g0, 0, %tick_cmpr
+	sethi	%hi(0x80000000), %g1
+	sllx	%g1, 32, %g1
+	wr	%g1, 0, %tick_cmpr
 
 	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/ioctl32.c linux-2.4.21-rc3/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.20/arch/sparc64/kernel/ioctl32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/ioctl32.c	2003-05-22 22:06:52.000000000 +0000
@@ -37,6 +37,7 @@
 #include <linux/cdrom.h>
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
 #include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
@@ -95,9 +96,11 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci.h>
+#include <net/bluetooth/rfcomm.h>
 
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb_scanner_ioctl.h>
 #include <linux/nbd.h>
 #include <linux/random.h>
 #include <linux/filter.h>
@@ -3217,6 +3220,175 @@
 }
 #endif
 
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+#include "../../../drivers/ieee1394/ieee1394-ioctl.h"
+#include "../../../drivers/ieee1394/amdtp.h"
+#include "../../../drivers/ieee1394/dv1394.h"
+#include "../../../drivers/ieee1394/video1394.h"
+
+#define DV1394_IOC32_INIT	_IOW('#', 0x06, struct dv1394_init32)
+#define DV1394_IOC32_GET_STATUS	_IOR('#', 0x0c, struct dv1394_status32)
+
+struct dv1394_init32 {
+	u32 api_version;
+	u32 channel;
+	u32 n_frames;
+	u32 format;
+	u32 cip_n;
+	u32 cip_d;
+	u32 syt_offset;
+};
+
+struct dv1394_status32 {
+	struct dv1394_init32 init;
+	s32 active_frame;
+	u32 first_clear_frame;
+	u32 n_clear_frames;
+	u32 dropped_frames;
+};
+
+static int handle_dv1394_init(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct dv1394_init32 dv32;
+	struct dv1394_init dv;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&dv32, (void *)arg, sizeof(dv32)))
+		return -EFAULT;
+
+	dv.api_version = dv32.api_version;
+	dv.channel = dv32.channel;
+	dv.n_frames = dv32.n_frames;
+	dv.format = dv32.format;
+	dv.cip_n = (unsigned long)dv32.cip_n;
+	dv.cip_d = (unsigned long)dv32.cip_d;
+	dv.syt_offset = dv32.syt_offset;
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DV1394_IOC_INIT, (unsigned long) &dv);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+static int handle_dv1394_get_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct dv1394_status32 dv32;
+	struct dv1394_status dv;
+	mm_segment_t old_fs;
+	int ret;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DV1394_IOC_GET_STATUS, (unsigned long) &dv);
+	set_fs(old_fs);
+
+	if (!ret) {
+		dv32.init.api_version = dv.init.api_version;
+		dv32.init.channel = dv.init.channel;
+		dv32.init.n_frames = dv.init.n_frames;
+		dv32.init.format = dv.init.format;
+		dv32.init.cip_n = (u32)dv.init.cip_n;
+		dv32.init.cip_d = (u32)dv.init.cip_d;
+		dv32.init.syt_offset = dv.init.syt_offset;
+		dv32.active_frame = dv.active_frame;
+		dv32.first_clear_frame = dv.first_clear_frame;
+		dv32.n_clear_frames = dv.n_clear_frames;
+		dv32.dropped_frames = dv.dropped_frames;
+
+		if (copy_to_user((struct dv1394_status32 *)arg, &dv32, sizeof(dv32)))
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER	\
+	_IOW ('#', 0x12, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER	\
+	_IOWR('#', 0x13, struct video1394_wait32)
+#define VIDEO1394_IOC32_TALK_WAIT_BUFFER	\
+        _IOW ('#', 0x17, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER	\
+        _IOWR('#', 0x18, struct video1394_wait32)
+
+struct video1394_wait32 {
+	u32 channel;
+	u32 buffer;
+        struct timeval32 filltime;
+};
+
+static int video1394_wr_wait32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct video1394_wait32 wait32;
+	struct video1394_wait wait;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+		return -EFAULT;
+
+	wait.channel = wait32.channel;
+	wait.buffer = wait32.buffer;
+	wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+	wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_WAIT_BUFFER, (unsigned long) &wait);
+	else
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_POLL_BUFFER, (unsigned long) &wait);
+	set_fs(old_fs);
+
+	if (!ret) {
+		wait32.channel = wait.channel;
+		wait32.buffer = wait.buffer;
+		wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
+		wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
+
+		if (copy_to_user((struct video1394_wait32 *)arg, &wait32, sizeof(wait32)))
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static int video1394_w_wait32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct video1394_wait32 wait32;
+	struct video1394_wait wait;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+		return -EFAULT;
+
+	wait.channel = wait32.channel;
+	wait.buffer = wait32.buffer;
+	wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+	wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_QUEUE_BUFFER, (unsigned long) &wait);
+	else
+		ret = sys_ioctl(fd, VIDEO1394_IOC_TALK_WAIT_BUFFER, (unsigned long) &wait);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+static int video1394_queue_buf32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EFAULT;
+}
+
+#endif /* CONFIG_IEEE1394 */
+
 #if defined(CONFIG_DRM_NEW) || defined(CONFIG_DRM_NEW_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
@@ -4286,6 +4458,15 @@
 	return sys_ioctl(fd, BLKGETSIZE64, arg);
 }
 
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO	_IOW('U', 200, int)
+#define HCIUARTGETPROTO	_IOR('U', 201, int)
+
+#define BNEPCONNADD	_IOW('B', 200, int)
+#define BNEPCONNDEL	_IOW('B', 201, int)
+#define BNEPGETCONNLIST	_IOR('B', 210, int)
+#define BNEPGETCONNINFO	_IOR('B', 211, int)
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -4307,6 +4488,7 @@
 COMPATIBLE_IOCTL(TCSETAW)
 COMPATIBLE_IOCTL(TCSETAF)
 COMPATIBLE_IOCTL(TCSBRK)
+COMPATIBLE_IOCTL(TCSBRKP)
 COMPATIBLE_IOCTL(TCXONC)
 COMPATIBLE_IOCTL(TCFLSH)
 COMPATIBLE_IOCTL(TCGETS)
@@ -4870,6 +5052,7 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -4987,6 +5170,21 @@
 COMPATIBLE_IOCTL(HCISETACLMTU)
 COMPATIBLE_IOCTL(HCISETSCOMTU)
 COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+/* Scanner */
+COMPATIBLE_IOCTL(SCANNER_IOCTL_VENDOR)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_PRODUCT)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_CTRLMSG)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
@@ -5023,7 +5221,33 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
 COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* Linux-1394 */
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+COMPATIBLE_IOCTL(AMDTP_IOC_CHANNEL)
+COMPATIBLE_IOCTL(AMDTP_IOC_PLUG)
+COMPATIBLE_IOCTL(AMDTP_IOC_PING)
+COMPATIBLE_IOCTL(AMDTP_IOC_ZAP)
+COMPATIBLE_IOCTL(DV1394_IOC_SHUTDOWN)
+COMPATIBLE_IOCTL(DV1394_IOC_SUBMIT_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_WAIT_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_RECEIVE_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_START_RECEIVE)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_LISTEN_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_UNLISTEN_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_TALK_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_UNTALK_CHANNEL)
+#endif
+
 /* And these ioctls need translation */
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+HANDLE_IOCTL(DV1394_IOC32_INIT, handle_dv1394_init)
+HANDLE_IOCTL(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER, video1394_w_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER, video1394_wr_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC_TALK_QUEUE_BUFFER, video1394_queue_buf32)
+HANDLE_IOCTL(VIDEO1394_IOC32_TALK_WAIT_BUFFER, video1394_w_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_POLL_BUFFER, video1394_wr_wait32)
+#endif
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 #ifdef CONFIG_NET
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/irq.c linux-2.4.21-rc3/arch/sparc64/kernel/irq.c
--- linux-2.4.20/arch/sparc64/kernel/irq.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/irq.c	2003-05-22 22:06:41.000000000 +0000
@@ -341,7 +341,7 @@
 	}	
 	if(action == NULL)
 	    action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
-						 GFP_KERNEL);
+						 GFP_ATOMIC);
 	
 	if(!action) { 
 		restore_flags(flags);
@@ -361,7 +361,7 @@
 				goto free_and_ebusy;
 			}
 			if((bucket->flags & IBF_MULTI) == 0) {
-				vector = kmalloc(sizeof(void *) * 4, GFP_KERNEL);
+				vector = kmalloc(sizeof(void *) * 4, GFP_ATOMIC);
 				if(vector == NULL)
 					goto free_and_enomem;
 
@@ -803,12 +803,8 @@
 	 */
 	{
 		unsigned long clr_mask = 1 << irq;
-		unsigned long tick_mask;
+		unsigned long tick_mask = tick_ops->softint_mask;
 
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
 		if ((irq == 14) && (get_softint() & tick_mask)) {
 			irq = 0;
 			clr_mask = tick_mask;
@@ -983,7 +979,7 @@
 	}
 	if(action == NULL)
 		action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
-						     GFP_KERNEL);
+						     GFP_ATOMIC);
 	if(!action) {
 		restore_flags(flags);
 		return -ENOMEM;
@@ -1025,113 +1021,6 @@
 	return 0;
 }
 
-/* This is gets the master TICK_INT timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
-		 unsigned long *clock)
-{
-	unsigned long pstate;
-	extern unsigned long timer_tick_offset;
-	int node, err;
-#ifdef CONFIG_SMP
-	extern void smp_tick_init(void);
-#endif
-
-	if (!SPARC64_USE_STICK) {
-		node = linux_cpus[0].prom_node;
-		*clock = prom_getint(node, "clock-frequency");
-	} else {
-		node = prom_root_node;
-		*clock = prom_getint(node, "stick-frequency");
-	}
-	timer_tick_offset = *clock / HZ;
-#ifdef CONFIG_SMP
-	smp_tick_init();
-#endif
-
-	/* Register IRQ handler. */
-	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
-			  "timer", NULL);
-
-	if(err) {
-		prom_printf("Serious problem, cannot register TICK_INT\n");
-		prom_halt();
-	}
-
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 sllx	%%g1, 32, %%g1\n"
-	"	.align	64\n"
-	"1:	rd	%%tick, %%g2\n"
-	"	add	%%g2, 6, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wrpr	%%g2, 0, %%tick\n"
-	"	rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 add	%%g1, %0, %%g1\n"
-	"	.align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
-	"	rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	} else {
-	/* Let the user get at STICK too. */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	sllx	%%g1, 32, %%g1\n"
-	"	rd	%%asr24, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wr	%%g2, 0, %%asr24"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	__asm__ __volatile__(
-	"	rd	%%asr24, %%g1\n"
-	"	add	%%g1, %0, %%g1\n"
-	"	wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
-	sti();
-}
-
 #ifdef CONFIG_SMP
 static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/itlb_base.S linux-2.4.21-rc3/arch/sparc64/kernel/itlb_base.S
--- linux-2.4.20/arch/sparc64/kernel/itlb_base.S	2001-08-28 14:09:44.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/itlb_base.S	2003-05-22 22:06:26.000000000 +0000
@@ -59,7 +59,7 @@
 
 /* ITLB ** ICACHE line 3: Finish faults + window fixups	*/
 	call		do_sparc64_fault		! Call fault handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
+	 add		%sp, PTREGS_OFF, %o0		! Compute pt_regs arg
 	ba,pt		%xcc, rtrap_clr_l6		! Restore cpu state
 	 nop
 winfix_trampoline:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/pci_iommu.c linux-2.4.21-rc3/arch/sparc64/kernel/pci_iommu.c
--- linux-2.4.20/arch/sparc64/kernel/pci_iommu.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/pci_iommu.c	2003-05-22 22:06:27.000000000 +0000
@@ -788,6 +788,26 @@
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
+static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
+{
+	struct pci_dev *ali_isa_bridge;
+	u8 val;
+
+	/* ALI sound chips generate 31-bits of DMA, a special register
+	 * determines what bit 31 is emitted as.
+	 */
+	ali_isa_bridge = pci_find_device(PCI_VENDOR_ID_AL,
+					 PCI_DEVICE_ID_AL_M1533,
+					 NULL);
+
+	pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
+	if (set_bit)
+		val |= 0x01;
+	else
+		val &= ~0x01;
+	pci_write_config_byte(ali_isa_bridge, 0x7e, val);
+}
+
 int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
@@ -799,6 +819,14 @@
 		struct pci_iommu *iommu = pcp->pbm->iommu;
 
 		dma_addr_mask = iommu->dma_addr_mask;
+
+		if (pdev->vendor == PCI_VENDOR_ID_AL &&
+		    pdev->device == PCI_DEVICE_ID_AL_M5451 &&
+		    device_mask == 0x7fffffff) {
+			ali_sound_dma_hack(pdev,
+					   (dma_addr_mask & 0x80000000) != 0);
+			return 1;
+		}
 	}
 
 	return (device_mask & dma_addr_mask) == dma_addr_mask;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/process.c linux-2.4.21-rc3/arch/sparc64/kernel/process.c
--- linux-2.4.20/arch/sparc64/kernel/process.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/process.c	2003-05-22 22:06:42.000000000 +0000
@@ -39,6 +39,7 @@
 #include <asm/pstate.h>
 #include <asm/elf.h>
 #include <asm/fpumacro.h>
+#include <asm/head.h>
 
 /* #define VERBOSE_SHOWREGS */
 
@@ -362,8 +363,8 @@
 	    regs->u_regs[14] >= (long)current - PAGE_SIZE &&
 	    regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) {
 		printk ("*********parent**********\n");
-		__show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ));
-		idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc);
+		__show_regs((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF));
+		idump_from_user(((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF))->tpc);
 		printk ("*********endpar**********\n");
 	}
 #endif
@@ -538,11 +539,11 @@
 
 	flush_user_windows();
 	if ((window = t->w_saved) != 0) {
-		int winsize = REGWIN_SZ;
+		int winsize = sizeof(struct reg_window);
 		int bias = 0;
 
 		if (t->flags & SPARC_FLAG_32BIT)
-			winsize = REGWIN32_SZ;
+			winsize = sizeof(struct reg_window32);
 		else
 			bias = STACK_BIAS;
 
@@ -563,11 +564,11 @@
 {
 	struct thread_struct *t = &current->thread;
 	unsigned long window;
-	int winsize = REGWIN_SZ;
+	int winsize = sizeof(struct reg_window);
 	int bias = 0;
 
 	if (t->flags & SPARC_FLAG_32BIT)
-		winsize = REGWIN32_SZ;
+		winsize = sizeof(struct reg_window32);
 	else
 		bias = STACK_BIAS;
 
@@ -610,11 +611,11 @@
 #endif
 
 	/* Calculate offset to stack_frame & pt_regs */
-	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
-	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
+	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
+	memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
 	t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
 	t->flags |= SPARC_FLAG_NEWCHILD;
-	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
+	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf));
 	t->cwp = (regs->tstate + 1) & TSTATE_CWP;
 	t->fpsaved[0] = 0;
 
@@ -634,7 +635,7 @@
 		flush_register_windows();
 		memcpy((void *)(t->ksp + STACK_BIAS),
 		       (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
-		       sizeof(struct reg_window));
+		       sizeof(struct sparc_stackf));
 		t->kregs->u_regs[UREG_G6] = (unsigned long) p;
 	} else {
 		if (t->flags & SPARC_FLAG_32BIT) {
@@ -673,7 +674,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/rtrap.S linux-2.4.21-rc3/arch/sparc64/kernel/rtrap.S
--- linux-2.4.20/arch/sparc64/kernel/rtrap.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/rtrap.S	2003-05-22 22:06:43.000000000 +0000
@@ -55,7 +55,7 @@
 		mov			%l5, %o2
 		mov			%l6, %o3
 
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
@@ -94,7 +94,7 @@
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
@@ -122,7 +122,7 @@
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
@@ -174,6 +174,7 @@
 		 * sched+signal checks with IRQs disabled.
 		 */
 to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		wrpr			0, %pil
 __handle_preemption_continue:
 		ldx			[%g6 + AOFF_task_need_resched], %l0
 		brnz,pn			%l0, __handle_preemption
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal.c linux-2.4.21-rc3/arch/sparc64/kernel/signal.c
--- linux-2.4.20/arch/sparc64/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/signal.c	2003-05-22 22:06:48.000000000 +0000
@@ -219,7 +219,7 @@
 	err |= __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4]));
 	err |= __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5]));
 	err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6]));
-	err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7]));
+	err |= __put_user(regs->u_regs[UREG_G7], &((*grp)[MC_G7]));
 	err |= __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0]));
 	err |= __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1]));
 	err |= __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2]));
@@ -438,8 +438,8 @@
 	err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs));
 
 	/* User can only change condition codes in %tstate. */
-	regs->tstate &= ~(TSTATE_ICC);
-	regs->tstate |= (tstate & TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
+	regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
 
 	err |= __get_user(fpu_save, &sf->fpu_save);
 	if (fpu_save)
@@ -783,7 +783,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal32.c linux-2.4.21-rc3/arch/sparc64/kernel/signal32.c
--- linux-2.4.20/arch/sparc64/kernel/signal32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/signal32.c	2003-05-22 22:06:24.000000000 +0000
@@ -828,7 +828,7 @@
 	save_and_clear_fpu();
 	
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
-	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, REGWIN_SZ + SVR4_SF_ALIGNED);
+	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, sizeof(struct reg_window32) + SVR4_SF_ALIGNED);
 
 	if (invalid_frame_pointer (sfp, sizeof (*sfp))){
 #ifdef DEBUG_SIGNALS
@@ -1444,7 +1444,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/smp.c linux-2.4.21-rc3/arch/sparc64/kernel/smp.c
--- linux-2.4.20/arch/sparc64/kernel/smp.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/smp.c	2003-05-22 22:06:24.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/cache.h>
+#include <linux/timer.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -137,7 +138,6 @@
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
-	unsigned long pstate;
 	extern int bigkernel;
 	extern unsigned long kern_locked_tte_data;
 
@@ -155,50 +155,6 @@
 
 	cpu_probe();
 
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-		"sethi	%%hi(0x80000000), %%g1\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		"sllx	%%g1, 32, %%g1\n\t"
-		".align	64\n"
-	"1:	rd	%%tick, %%g2\n\t"
-		"add	%%g2, 6, %%g2\n\t"
-		"andn	%%g2, %%g1, %%g2\n\t"
-		"wrpr	%%g2, 0, %%tick\n\t"
-		"rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	if (SPARC64_USE_STICK) {
-		/* Let the user get at STICK too. */
-		__asm__ __volatile__(
-			"sethi	%%hi(0x80000000), %%g1\n\t"
-			"sllx	%%g1, 32, %%g1\n\t"
-			"rd	%%asr24, %%g2\n\t"
-			"andn	%%g2, %%g1, %%g2\n\t"
-			"wr	%%g2, 0, %%asr24"
-		: /* no outputs */
-		: /* no inputs */
-		: "g1", "g2");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
 	smp_setup_percpu_timer();
 
 	__sti();
@@ -242,6 +198,158 @@
 	panic("SMP bolixed\n");
 }
 
+static unsigned long current_tick_offset;
+
+/* This tick register synchronization scheme is taken entirely from
+ * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
+ *
+ * The only change I've made is to rework it so that the master
+ * initiates the synchonization instead of the slave. -DaveM
+ */
+
+#define MASTER	0
+#define SLAVE	(SMP_CACHE_BYTES/sizeof(unsigned long))
+
+#define NUM_ROUNDS	64	/* magic value */
+#define NUM_ITERS	5	/* likewise */
+
+static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long go[SLAVE + 1];
+
+#define DEBUG_TICK_SYNC	0
+
+static inline long get_delta (long *rt, long *master)
+{
+	unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
+	unsigned long tcenter, t0, t1, tm;
+	unsigned long i;
+
+	for (i = 0; i < NUM_ITERS; i++) {
+		t0 = tick_ops->get_tick();
+		go[MASTER] = 1;
+		membar("#StoreLoad");
+		while (!(tm = go[SLAVE]))
+			membar("#LoadLoad");
+		go[SLAVE] = 0;
+		membar("#StoreStore");
+		t1 = tick_ops->get_tick();
+
+		if (t1 - t0 < best_t1 - best_t0)
+			best_t0 = t0, best_t1 = t1, best_tm = tm;
+	}
+
+	*rt = best_t1 - best_t0;
+	*master = best_tm - best_t0;
+
+	/* average best_t0 and best_t1 without overflow: */
+	tcenter = (best_t0/2 + best_t1/2);
+	if (best_t0 % 2 + best_t1 % 2 == 2)
+		tcenter++;
+	return tcenter - best_tm;
+}
+
+void smp_synchronize_tick_client(void)
+{
+	long i, delta, adj, adjust_latency = 0, done = 0;
+	unsigned long flags, rt, master_time_stamp, bound;
+#if DEBUG_TICK_SYNC
+	struct {
+		long rt;	/* roundtrip time */
+		long master;	/* master's timestamp */
+		long diff;	/* difference between midpoint and master's timestamp */
+		long lat;	/* estimate of itc adjustment latency */
+	} t[NUM_ROUNDS];
+#endif
+
+	go[MASTER] = 1;
+
+	while (go[MASTER])
+		membar("#LoadLoad");
+
+	local_irq_save(flags);
+	{
+		for (i = 0; i < NUM_ROUNDS; i++) {
+			delta = get_delta(&rt, &master_time_stamp);
+			if (delta == 0) {
+				done = 1;	/* let's lock on to this... */
+				bound = rt;
+			}
+
+			if (!done) {
+				if (i > 0) {
+					adjust_latency += -delta;
+					adj = -delta + adjust_latency/4;
+				} else
+					adj = -delta;
+
+				tick_ops->add_tick(adj, current_tick_offset);
+			}
+#if DEBUG_TICK_SYNC
+			t[i].rt = rt;
+			t[i].master = master_time_stamp;
+			t[i].diff = delta;
+			t[i].lat = adjust_latency/4;
+#endif
+		}
+	}
+	local_irq_restore(flags);
+
+#if DEBUG_TICK_SYNC
+	for (i = 0; i < NUM_ROUNDS; i++)
+		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
+		       t[i].rt, t[i].master, t[i].diff, t[i].lat);
+#endif
+
+	printk(KERN_INFO "CPU %d: synchronized TICK with master CPU (last diff %ld cycles,"
+	       "maxerr %lu cycles)\n", smp_processor_id(), delta, rt);
+}
+
+static void smp_start_sync_tick_client(int cpu);
+
+static void smp_synchronize_one_tick(int cpu)
+{
+	unsigned long flags, i;
+
+	go[MASTER] = 0;
+
+	smp_start_sync_tick_client(cpu);
+
+	/* wait for client to be ready */
+	while (!go[MASTER])
+		membar("#LoadLoad");
+
+	/* now let the client proceed into his loop */
+	go[MASTER] = 0;
+	membar("#StoreLoad");
+
+	spin_lock_irqsave(&itc_sync_lock, flags);
+	{
+		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
+			while (!go[MASTER])
+				membar("#LoadLoad");
+			go[MASTER] = 0;
+			membar("#StoreStore");
+			go[SLAVE] = tick_ops->get_tick();
+			membar("#StoreLoad");
+		}
+	}
+	spin_unlock_irqrestore(&itc_sync_lock, flags);
+}
+
+static void smp_synchronize_tick(void)
+{
+	int cpu = smp_processor_id();
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_present_map & (1UL << i)) {
+			if (i == cpu)
+				continue;
+			smp_synchronize_one_tick(i);
+		}
+	}
+}
+
 extern struct prom_cpuinfo linux_cpus[64];
 
 extern unsigned long sparc64_cpu_startup;
@@ -340,6 +448,8 @@
 	}
 	smp_processors_ready = 1;
 	membar("#StoreStore | #StoreLoad");
+
+	smp_synchronize_tick();
 }
 
 static void spitfire_xcall_helper(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
@@ -542,6 +652,15 @@
 	}
 }
 
+extern unsigned long xcall_sync_tick;
+
+static void smp_start_sync_tick_client(int cpu)
+{
+	smp_cross_call_masked(&xcall_sync_tick,
+			      0, 0, 0,
+			      (1UL << cpu));
+}
+
 /* Send cross call to all processors except self. */
 #define smp_cross_call(func, ctx, data1, data2) \
 	smp_cross_call_masked(func, ctx, data1, data2, cpu_present_map)
@@ -987,8 +1106,6 @@
 
 extern void sparc64_do_profile(unsigned long pc, unsigned long o7);
 
-static unsigned long current_tick_offset;
-
 #define prof_multiplier(__cpu)		cpu_data[(__cpu)].multiplier
 #define prof_counter(__cpu)		cpu_data[(__cpu)].counter
 
@@ -1002,12 +1119,7 @@
 	 * Check for level 14 softint.
 	 */
 	{
-		unsigned long tick_mask;
-
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
+		unsigned long tick_mask = tick_ops->softint_mask;
 
 		if (!(get_softint() & tick_mask)) {
 			extern void handler_irq(int, struct pt_regs *);
@@ -1022,17 +1134,17 @@
 		if (!user)
 			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
 		if (!--prof_counter(cpu)) {
-			if (cpu == boot_cpu_id) {
-				irq_enter(cpu, 0);
+			irq_enter(cpu, 0);
 
+			if (cpu == boot_cpu_id) {
 				kstat.irqs[cpu][0]++;
 				timer_tick_interrupt(regs);
-
-				irq_exit(cpu, 0);
 			}
 
 			update_process_times(user);
 
+			irq_exit(cpu, 0);
+
 			prof_counter(cpu) = prof_multiplier(cpu);
 		}
 
@@ -1044,47 +1156,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-				     "ba,pt	%%xcc, 1f\n\t"
-				     " add	%0, %2, %0\n\t"
-				     ".align	64\n"
-				  "1: wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "rd	%%tick_cmpr, %%g0\n\t"
-				     "rd	%%tick, %1\n\t"
-				     "mov	%1, %1"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		} else {
-		__asm__ __volatile__("rd	%%asr25, %0\n\t"
-				     "add	%0, %2, %0\n\t"
-				     "wr	%0, 0x0, %%asr25\n\t"
-				     "rd	%%asr24, %1\n\t"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		}
+		compare = tick_ops->add_compare(current_tick_offset);
+		tick = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (tick >= compare);
+	} while (time_after_eq(tick, compare));
 }
 
 static void __init smp_setup_percpu_timer(void)
@@ -1102,35 +1181,7 @@
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
 
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-		"rd	%%tick, %%g1\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		" add	%%g1, %0, %%g1\n\t"
-		".align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n\t"
-		"rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	} else {
-	__asm__ __volatile__(
-		"rd	%%asr24, %%g1\n\t"
-		"add	%%g1, %0, %%g1\n\t"
-		"wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	}
+	tick_ops->init_tick(current_tick_offset);
 
 	/* Restore PSTATE_IE. */
 	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.21-rc3/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/sparc64_ksyms.c	2003-05-22 22:06:39.000000000 +0000
@@ -51,6 +51,7 @@
 #include <asm/isa.h>
 #endif
 #include <asm/a.out.h>
+#include <asm/timer.h>
 
 struct poll {
 	int fd;
@@ -60,7 +61,6 @@
 
 extern unsigned prom_cpu_nodes[64];
 extern void die_if_kernel(char *str, struct pt_regs *regs);
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 void _sigpause_common (unsigned int set, struct pt_regs *);
 extern void *__bzero(void *, size_t);
 extern void *__bzero_noasi(void *, size_t);
@@ -195,6 +195,7 @@
 EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_dcache_range);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
@@ -367,3 +368,5 @@
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(do_BUG);
 #endif
+
+EXPORT_SYMBOL(tick_ops);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c linux-2.4.21-rc3/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/sys_sparc32.c	2003-05-22 22:06:48.000000000 +0000
@@ -50,6 +50,7 @@
 #include <linux/icmpv6.h>
 #include <linux/sysctl.h>
 #include <linux/dnotify.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -1150,7 +1151,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	if ((retval + (type == VERIFY_WRITE)) > 0)
 		dnotify_parent(file->f_dentry,
-			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
+			(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
 
 	return retval;
 }
@@ -2618,10 +2619,28 @@
 		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
 
 		clen64 = kcmsg32->cmsg_len;
-		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
-			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
-		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
-			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		if (kcmsg32->cmsg_level == SOL_SOCKET &&
+			kcmsg32->cmsg_type == SO_TIMESTAMP) {
+			struct timeval tv;
+			struct timeval32 *tv32;
+
+			if (clen64 != CMSG_LEN(sizeof(struct timeval))) {
+				kfree(workbuf);
+				goto fail;
+			}
+
+			copy_from_user(&tv, CMSG_DATA(ucmsg), sizeof(tv));
+			tv32 = (struct timeval32 *)CMSG32_DATA(kcmsg32);
+			tv32->tv_sec = tv.tv_sec;
+			tv32->tv_usec = tv.tv_usec;
+			clen32 = sizeof(*tv32) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32));
+		} else {
+			copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+				       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+			clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		}
 		kcmsg32->cmsg_len = clen32;
 
 		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
@@ -2777,6 +2796,78 @@
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
+static int do_netfilter_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct ipt_replace32 {
+		char name[IPT_TABLE_MAXNAMELEN];
+		__u32 valid_hooks;
+		__u32 num_entries;
+		__u32 size;
+		__u32 hook_entry[NF_IP_NUMHOOKS];
+		__u32 underflow[NF_IP_NUMHOOKS];
+		__u32 num_counters;
+		__u32 counters;
+		struct ipt_entry entries[0];
+	} *repl32 = (struct ipt_replace32 *)optval;
+	struct ipt_replace *krepl;
+	struct ipt_counters *counters32;
+	__u32 origsize;
+	unsigned int kreplsize, kcountersize;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (optlen < sizeof(repl32))
+		return -EINVAL;
+
+	if (copy_from_user(&origsize,
+			&repl32->size,
+			sizeof(origsize)))
+		return -EFAULT;
+
+	kreplsize = sizeof(*krepl) + origsize;
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+
+	/* Hack: Causes ipchains to give correct error msg --RR */
+	if (optlen != kreplsize)
+		return -ENOPROTOOPT;
+
+	krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
+	if (krepl == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(krepl, optval, kreplsize)) {
+		kfree(krepl);
+		return -EFAULT;
+	}
+
+	counters32 = (struct ipt_counters *)AA(
+		((struct ipt_replace32 *)krepl)->counters);
+
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+	krepl->counters = (struct ipt_counters *)kmalloc(
+					kcountersize, GFP_KERNEL);
+	if (krepl->counters == NULL) {
+		kfree(krepl);
+		return -ENOMEM;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)krepl, kreplsize);
+	set_fs(old_fs);
+
+	if (ret == 0 &&
+		copy_to_user(counters32, krepl->counters, kcountersize))
+			ret = -EFAULT;
+
+	kfree(krepl->counters);
+	kfree(krepl);
+
+	return ret;
+}
+
 static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
@@ -2870,6 +2961,9 @@
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
+	if (optname == IPT_SO_SET_REPLACE)
+		return do_netfilter_replace(fd, level, optname,
+					    optval, optlen);
 	if (optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/systbls.S linux-2.4.21-rc3/arch/sparc64/kernel/systbls.S
--- linux-2.4.20/arch/sparc64/kernel/systbls.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/systbls.S	2003-05-22 22:06:42.000000000 +0000
@@ -52,11 +52,11 @@
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
@@ -111,11 +111,11 @@
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
-	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/time.c linux-2.4.21-rc3/arch/sparc64/kernel/time.c
--- linux-2.4.20/arch/sparc64/kernel/time.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/time.c	2003-05-22 22:06:47.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
 #include <linux/delay.h>
+#include <linux/timer.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -34,8 +35,10 @@
 #include <asm/ebus.h>
 #include <asm/isa.h>
 #include <asm/starfire.h>
+#include <asm/smp.h>
 
 extern rwlock_t xtime_lock;
+extern unsigned long wall_jiffies;
 
 spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
@@ -49,6 +52,352 @@
 
 static int set_rtc_mmss(unsigned long);
 
+struct sparc64_tick_ops *tick_ops;
+
+#define TICK_PRIV_BIT	(1UL << 63)
+
+static void tick_disable_protection(void)
+{
+	/* Set things up so user can access tick register for profiling
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
+	 */
+	__asm__ __volatile__(
+	"	ba,pt	%%xcc, 1f\n"
+	"	 nop\n"
+	"	.align	64\n"
+	"1:	rd	%%tick, %%g2\n"
+	"	add	%%g2, 6, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wrpr	%%g2, 0, %%tick\n"
+	"	rdpr	%%tick, %%g0"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g2");
+}
+
+static void tick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	__asm__ __volatile__(
+	"	rd	%%tick, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	ba,pt	%%xcc, 1f\n"
+	"	 add	%%g1, %0, %%g1\n"
+	"	.align	64\n"
+	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
+	"	rd	%%tick_cmpr, %%g0"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long tick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long tick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long tick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%0, %1, %0\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%0, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	/* Also need to handle Blackbird bug here too. */
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wrpr	%0, 0, %%tick\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%1, %3, %1\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%1, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static struct sparc64_tick_ops tick_operations = {
+	.init_tick	=	tick_init_tick,
+	.get_tick	=	tick_get_tick,
+	.get_compare	=	tick_get_compare,
+	.add_tick	=	tick_add_tick,
+	.add_compare	=	tick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
+static void stick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	/* Let the user get at STICK too. */
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wr	%%g2, 0, %%asr24"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g1", "g2");
+
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	add	%%g1, %0, %%g1\n"
+	"	wr	%%g1, 0x0, %%asr25"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long stick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr24, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long stick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr25, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long stick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	__asm__ __volatile__("rd	%%asr24, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wr	%0, 0, %%asr24\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "add	%1, %3, %1\n\t"
+			     "wr	%1, 0, %%asr25"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static unsigned long stick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	__asm__ __volatile__("rd	%%asr25, %0\n\t"
+			     "add	%0, %1, %0\n\t"
+			     "wr	%0, 0, %%asr25"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static struct sparc64_tick_ops stick_operations = {
+	.init_tick	=	stick_init_tick,
+	.get_tick	=	stick_get_tick,
+	.get_compare	=	stick_get_compare,
+	.add_tick	=	stick_add_tick,
+	.add_compare	=	stick_add_compare,
+	.softint_mask	=	1UL << 16,
+};
+
+/* On Hummingbird the STICK/STICK_CMPR register is implemented
+ * in I/O space.  There are two 64-bit registers each, the
+ * first holds the low 32-bits of the value and the second holds
+ * the high 32-bits.
+ *
+ * Since STICK is constantly updating, we have to access it carefully.
+ *
+ * The sequence we use to read is:
+ * 1) read low
+ * 2) read high
+ * 3) read low again, if it rolled over increment high by 1
+ *
+ * Writing STICK safely is also tricky:
+ * 1) write low to zero
+ * 2) write high
+ * 3) write low
+ */
+#define HBIRD_STICKCMP_ADDR	0x1fe0000f060UL
+#define HBIRD_STICK_ADDR	0x1fe0000f070UL
+
+static unsigned long __hbird_read_stick(void)
+{
+	unsigned long ret, tmp1, tmp2, tmp3;
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("ldxa	[%1] %5, %2\n\t"
+			     "add	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %3\n\t"
+			     "sub	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %4\n\t"
+			     "cmp	%4, %2\n\t"
+			     "blu,a,pn	%%xcc, 1f\n\t"
+			     " add	%3, 1, %3\n"
+			     "1:\n\t"
+			     "sllx	%3, 32, %3\n\t"
+			     "or	%3, %4, %0\n\t"
+			     : "=&r" (ret), "=&r" (addr),
+			       "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "1" (addr));
+
+	return ret;
+}
+
+static unsigned long __hbird_read_compare(void)
+{
+	unsigned long low, high;
+	unsigned long addr = HBIRD_STICKCMP_ADDR;
+
+	__asm__ __volatile__("ldxa	[%2] %3, %0\n\t"
+			     "add	%2, 0x8, %2\n\t"
+			     "ldxa	[%2] %3, %1"
+			     : "=&r" (low), "=&r" (high), "=&r" (addr)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));
+
+	return (high << 32UL) | low;
+}
+
+static void __hbird_write_stick(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("stxa	%%g0, [%0] %4\n\t"
+			     "add	%0, 0x8, %0\n\t"
+			     "stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void __hbird_write_compare(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICKCMP_ADDR + 0x8UL;
+
+	__asm__ __volatile__("stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void hbtick_init_tick(unsigned long offset)
+{
+	unsigned long val;
+
+	tick_disable_protection();
+
+	/* XXX This seems to be necessary to 'jumpstart' Hummingbird
+	 * XXX into actually sending STICK interrupts.  I think because
+	 * XXX of how we store %tick_cmpr in head.S this somehow resets the
+	 * XXX {TICK + STICK} interrupt mux.  -DaveM
+	 */
+	__hbird_write_stick(__hbird_read_stick());
+
+	val = __hbird_read_stick() & ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+}
+
+static unsigned long hbtick_get_tick(void)
+{
+	return __hbird_read_stick() & ~TICK_PRIV_BIT;
+}
+
+static unsigned long hbtick_get_compare(void)
+{
+	return __hbird_read_compare();
+}
+
+static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long val;
+
+	val = __hbird_read_stick() + adj;
+	__hbird_write_stick(val);
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+
+	return val;
+}
+
+static unsigned long hbtick_add_compare(unsigned long adj)
+{
+	unsigned long val = __hbird_read_compare() + adj;
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val);
+
+	return val;
+}
+
+static struct sparc64_tick_ops hbtick_operations = {
+	.init_tick	=	hbtick_init_tick,
+	.get_tick	=	hbtick_get_tick,
+	.get_compare	=	hbtick_get_compare,
+	.add_tick	=	hbtick_add_tick,
+	.add_compare	=	hbtick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
 /* timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  *
@@ -129,49 +478,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__(
-		"	rd	%%tick_cmpr, %0\n"
-		"	ba,pt	%%xcc, 1f\n"
-		"	 add	%0, %2, %0\n"
-		"	.align	64\n"
-		"1: 	wr	%0, 0, %%tick_cmpr\n"
-		"	rd	%%tick_cmpr, %%g0\n"
-		"	rd	%%tick, %1\n"
-		"	mov	%1, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		} else {
-		__asm__ __volatile__(
-		"	rd	%%asr25, %0\n"
-		"	add	%0, %2, %0\n"
-		"	wr	%0, 0, %%asr25\n"
-		"	rd	%%asr24, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		}
+		timer_tick_compare = tick_ops->add_compare(timer_tick_offset);
+		ticks = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (ticks >= timer_tick_compare);
+	} while (time_after_eq(ticks, timer_tick_compare));
 
 	timer_check_rtc();
 
@@ -188,19 +502,7 @@
 	/*
 	 * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
 	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick_cmpr, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	} else {
-	__asm__ __volatile__(
-	"	rd	%%asr25, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	}
+	timer_tick_compare = tick_ops->get_compare() + timer_tick_offset;
 
 	timer_check_rtc();
 
@@ -611,43 +913,90 @@
 	__restore_flags(flags);
 }
 
-extern void init_timers(void (*func)(int, void *, struct pt_regs *),
-			unsigned long *);
+/* This is gets the master TICK_INT timer going. */
+static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+{
+	unsigned long pstate, clock;
+	int node, err;
+#ifdef CONFIG_SMP
+	extern void smp_tick_init(void);
+#endif
+
+	if (tlb_type == spitfire) {
+		unsigned long ver, manuf, impl;
+
+		__asm__ __volatile__ ("rdpr %%ver, %0"
+				      : "=&r" (ver));
+		manuf = ((ver >> 48) & 0xffff);
+		impl = ((ver >> 32) & 0xffff);
+		if (manuf == 0x17 && impl == 0x13) {
+			/* Hummingbird, aka Ultra-IIe */
+			tick_ops = &hbtick_operations;
+			node = prom_root_node;
+			clock = prom_getint(node, "stick-frequency");
+		} else {
+			tick_ops = &tick_operations;
+			node = linux_cpus[0].prom_node;
+			clock = prom_getint(node, "clock-frequency");
+		}
+	} else {
+		tick_ops = &stick_operations;
+		node = prom_root_node;
+		clock = prom_getint(node, "stick-frequency");
+	}
+	timer_tick_offset = clock / HZ;
+
+#ifdef CONFIG_SMP
+	smp_tick_init();
+#endif
+
+	/* Register IRQ handler. */
+	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
+			  "timer", NULL);
+
+	if(err) {
+		prom_printf("Serious problem, cannot register TICK_INT\n");
+		prom_halt();
+	}
+
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	tick_ops->init_tick(timer_tick_offset);
+
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
+	sti();
+
+	return clock;
+}
 
+/* The quotient formula is taken from the IA64 port. */
 void __init time_init(void)
 {
-	/* clock_probe() is now done at end of [se]bus_init on sparc64
-	 * so that sbus, fhc and ebus bus information is probed and
-	 * available.
-	 */
-	unsigned long clock;
+	unsigned long clock = sparc64_init_timers(timer_interrupt);
 
-	init_timers(timer_interrupt, &clock);
-	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
+	timer_ticks_per_usec_quotient =
+		(((1000000UL << 30) +
+		  (clock / 2)) / clock);
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
-	unsigned long ticks;
+	unsigned long ticks = tick_ops->get_tick();
 
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	add	%1, %%g1, %0\n"
-	"	sub	%0, %2, %0\n"
-		: "=r" (ticks)
-		: "r" (timer_tick_offset), "r" (timer_tick_compare)
-		: "g1", "g2");
-	} else {
-	__asm__ __volatile__("rd	%%asr24, %%g1\n\t"
-			     "add	%1, %%g1, %0\n\t"
-			     "sub	%0, %2, %0\n\t"
-			     : "=&r" (ticks)
-			     : "r" (timer_tick_offset), "r" (timer_tick_compare)
-			     : "g1");
-	}
+	ticks += timer_tick_offset;
+	ticks -= timer_tick_compare;
 
-	return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
+	return (ticks * timer_ticks_per_usec_quotient) >> 30UL;
 }
 
 void do_settimeofday(struct timeval *tv)
@@ -658,7 +1007,9 @@
 	write_lock_irq(&xtime_lock);
 
 	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
+	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
@@ -672,6 +1023,31 @@
 	write_unlock_irq(&xtime_lock);
 }
 
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long usec, sec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
 static int set_rtc_mmss(unsigned long nowtime)
 {
 	int real_seconds, real_minutes, chip_minutes;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/trampoline.S linux-2.4.21-rc3/arch/sparc64/kernel/trampoline.S
--- linux-2.4.20/arch/sparc64/kernel/trampoline.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/trampoline.S	2003-05-22 22:06:41.000000000 +0000
@@ -85,7 +85,10 @@
 
 startup_continue:
 	wrpr		%g0, 15, %pil
-	wr		%g0, 0, %tick_cmpr
+
+	sethi		%hi(0x80000000), %g2
+	sllx		%g2, 32, %g2
+	wr		%g2, 0, %tick_cmpr
 
 	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
 	mov		%o0, %l0
@@ -195,7 +198,7 @@
 
 	mov		1, %g5
 	sllx		%g5, THREAD_SHIFT, %g5
-	sub		%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	sub		%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
 	add		%g6, %g5, %sp
 	mov		0, %fp
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/winfixup.S linux-2.4.21-rc3/arch/sparc64/kernel/winfixup.S
--- linux-2.4.20/arch/sparc64/kernel/winfixup.S	2000-03-27 18:35:56.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/kernel/winfixup.S	2003-05-22 22:06:43.000000000 +0000
@@ -81,7 +81,7 @@
 	 * since we must preserve %l5 and %l6, see comment above.
 	 */
 	call		do_sparc64_fault
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 nop						! yes, nop is correct
 
@@ -159,7 +159,7 @@
 	ba,pt		%xcc, etrap
 	 rd		%pc, %g7
 	call		do_sparc64_fault
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		winfix_mna, fill_fixup_mna, spill_fixup_mna
@@ -199,7 +199,7 @@
 	mov		%o7, %g6			! Get current back.
 	sllx		%g4, 32, %g4			! Finish it.
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
@@ -260,7 +260,7 @@
 	mov		%l4, %o2
 	mov		%l5, %o1
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
@@ -306,7 +306,7 @@
 	mov		%o7, %g6			! Get current back.
 	sllx		%g4, 32, %g4			! Finish it.
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
@@ -367,7 +367,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/mm/ultra.S linux-2.4.21-rc3/arch/sparc64/mm/ultra.S
--- linux-2.4.20/arch/sparc64/mm/ultra.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/mm/ultra.S	2003-05-22 22:06:50.000000000 +0000
@@ -524,6 +524,24 @@
 	nop
 	nop
 
+	/* This runs in a very controlled environment, so we do
+	 * not need to worry about BH races etc.
+	 */
+	.globl		xcall_sync_tick
+xcall_sync_tick:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	call		smp_synchronize_tick_client
+	 nop
+	clr		%l6
+	b		rtrap_xcall
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+
 	/* NOTE: This is SPECIAL!!  We do etrap/rtrap however
 	 *       we choose to deal with the "BH's run with
 	 *       %pil==15" problem (described in asm/pil.h)
@@ -543,7 +561,7 @@
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		__show_regs
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	clr		%l6
 	/* Has to be a non-v9 branch due to the large distance. */
 	b		rtrap_xcall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/solaris/entry64.S linux-2.4.21-rc3/arch/sparc64/solaris/entry64.S
--- linux-2.4.20/arch/sparc64/solaris/entry64.S	2000-01-13 20:03:00.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/solaris/entry64.S	2003-05-22 22:06:24.000000000 +0000
@@ -33,7 +33,7 @@
 	be,pt		%icc, 2f
 	 srl		%i2, 0, %o2
 	b,pt		%xcc, 2f
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 solaris_sucks:
 /* Solaris is a big system which needs to be able to do all the things
@@ -89,7 +89,7 @@
 	 sethi		%hi(sys_call_table32), %l6
 	andcc		%l3, 1, %g0
 	bne,a,pn	%icc, 10f
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 10:	srl		%i2, 0, %o2
 	mov		%i5, %o5
 	andn		%l3, 3, %l7
@@ -99,11 +99,11 @@
 2:	call		%l7
 	 srl		%i3, 0, %o3
 ret_from_solaris:
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	ldx		[%g6 + AOFF_task_flags], %l6
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
 	cmp		%o0, -ENOIOCTLCMD
 	sllx		%g2, 32, %g2
 	bgeu,pn		%xcc, 1f
@@ -111,21 +111,21 @@
 
 	/* System call success, clear Carry condition code. */
 	andn		%g3, %g2, %g3
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]	
 	bne,pn		%icc, solaris_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2f
 	 clr		%l6
 	add		%l1, 0x4, %l2				         
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]	 ! pc = npc
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]	 ! pc = npc
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4
 
 	/* When tnpc & 1, this comes from setcontext and we don't want to advance pc */
 2:	andn		%l1, 3, %l1
 	call		rtrap
-	 stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc&~3
+	 stx		%l1, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc&~3
 
 1:
 	/* System call failure, set Carry condition code.
@@ -141,17 +141,17 @@
 	sll		%o0, 2, %o0
 	or		%l6, %lo(solaris_err_table), %l6
 	ldsw		[%l6 + %o0], %o0
-1:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+1:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	mov		1, %l6
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
 	bne,pn		%icc, solaris_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2b
 	 add		%l1, 0x4, %l2
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]  ! pc = npc
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]  ! pc = npc
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4 
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4 
 
 solaris_syscall_trace2:
 	call		syscall_trace
@@ -159,9 +159,9 @@
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2b
 	 nop
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 	/* This one is tricky, so that's why we do it in assembly */
 	.globl		solaris_sigsuspend
@@ -171,13 +171,13 @@
 	brlz,pn		%o0, ret_from_solaris
 	 nop
 	call		sys_sigsuspend
-	 stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	.globl		solaris_getpid
 solaris_getpid:
 	call		sys_getppid	/* This is tricky, so don't do it in assembly */
 	 nop
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt		%xcc, ret_from_solaris
 	 lduw		[%g6 + AOFF_task_pid], %o0
 
@@ -186,19 +186,19 @@
 	lduw		[%g6 + AOFF_task_euid], %o1
 	lduw		[%g6 + AOFF_task_uid], %o0
 	b,pt		%xcc, ret_from_solaris
-	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
 
 	.globl	solaris_getgid
 solaris_getgid:
 	lduw		[%g6 + AOFF_task_egid], %o1
 	lduw		[%g6 + AOFF_task_gid], %o0
 	b,pt		%xcc, ret_from_solaris
-	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
 
 	.globl		solaris_unimplemented
 solaris_unimplemented:
 	call		do_sol_unimplemented
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, ret_from_solaris
 	 nop
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/solaris/ioctl.c linux-2.4.21-rc3/arch/sparc64/solaris/ioctl.c
--- linux-2.4.20/arch/sparc64/solaris/ioctl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/arch/sparc64/solaris/ioctl.c	2003-05-22 22:06:48.000000000 +0000
@@ -367,6 +367,7 @@
 	case 106: /* SI_GETINTRANSIT */
 	case 107: /* SI_TCL_LINK */
 	case 108: /* SI_TCL_UNLINK */
+		;
 	}
 	return TNOTSUPPORT;
 }
@@ -454,6 +455,7 @@
 	case 145: /* TI_GETPEERNAME */
 	case 146: /* TI_SETMYNAME */
 	case 147: /* TI_SETPEERNAME */
+		;
 	}
 	return TNOTSUPPORT;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/Makefile linux-2.4.21-rc3/arch/x86_64/Makefile
--- linux-2.4.20/arch/x86_64/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -19,7 +19,7 @@
 # 20010105  Andi Kleen, add IA32 compiler.
 #           ....and later removed it again....
 #
-# $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $
+# $Id: Makefile,v 1.32 2003/03/03 16:06:43 ak Exp $
 
 #
 # early bootup linking needs 32bit. You can either use real 32bit tools
@@ -47,6 +47,9 @@
 # needed for earlier gcc 3.1
 CFLAGS += -fno-strength-reduce
 #CFLAGS += -g
+ifneq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CFLAGS += -fno-asynchronous-unwind-tables
+endif
 
 # prevent gcc from keeping the stack 16 byte aligned (FIXME)
 #CFLAGS += -mpreferred-stack-boundary=2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/bootsect.S linux-2.4.21-rc3/arch/x86_64/boot/bootsect.S
--- linux-2.4.20/arch/x86_64/boot/bootsect.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/boot/bootsect.S	2003-05-22 22:06:50.000000000 +0000
@@ -395,9 +395,9 @@
 # NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
 
 kill_motor:
-	movw	$0x3f2, %dx
-	xorb	%al, %al
-	outb	%al, %dx
+	xorw	%ax, %ax		# reset FDC
+	xorb	%dl, %dl
+	int	$0x13
 	ret
 
 sectors:	.word 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/compressed/misc.c linux-2.4.21-rc3/arch/x86_64/boot/compressed/misc.c
--- linux-2.4.20/arch/x86_64/boot/compressed/misc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/boot/compressed/misc.c	2003-05-22 22:06:39.000000000 +0000
@@ -279,7 +279,7 @@
 	puts(x);
 	puts("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	while(1);
 }
 
 void setup_normal_output_buffer(void)
@@ -332,76 +332,6 @@
 	}
 }
 
-void check_cpu(void)
-{
-	int res = 0;
-	asm volatile( " \n\
-	movl $3,%%edx		# at least 386 \n\
-	pushfl			# push EFLAGS \n\
-	popl %%eax		# get EFLAGS \n\
-	movl %%eax,%%ecx		# save original EFLAGS \n\
-	xorl $0x40000,%%eax	# flip AC bit in EFLAGS \n\
-	pushl %%eax		# copy to EFLAGS \n\
-	popfl			# set EFLAGS \n\
-	pushfl			# get new EFLAGS \n\
-	popl %%eax		# put it in eax \n\
-	xorl %%ecx,%%eax		# change in flags \n\
-	andl $0x40000,%%eax	# check if AC bit changed \n\
-	je 1f \n\
-\n\
-	movl $4,%%edx		# at least 486 \n\
-	movl %%ecx,%%eax \n\
-	xorl $0x200000,%%eax	# check ID flag \n\
-	pushl %%eax \n\
-	popfl			# if we are on a straight 486DX, SX, or \n\
-	pushfl			# 487SX we can't change it \n\
-	popl %%eax \n\
-	xorl %%ecx,%%eax \n\
-	pushl %%ecx		# restore original EFLAGS \n\
-	popfl \n\
-	andl $0x200000,%%eax \n\
-	je 1f \n\
-\n\
-	/* get vendor info */ \n\
-#	xorl %%eax,%%eax			# call CPUID with 0 -> return vendor ID \n\
-#	cpuid \n\
-#	movl $5, %%edx \n\
-#	cmpl $0x41757468,%%ebx		# check thats amd \n\
-#	jne 1f \n\
-\n\
-	mov $0x80000000,%%eax		# Is extended cpuid supported?\n\
-	cpuid\n\
-	test $0x80000000,%%eax\n\
-	movl $5, %%edx \n\
-	jz 1f\n\
-\n\
-	movl $0x80000001,%%eax \n\
-	cpuid \n\
-	andl $0x20000000,%%edx \n\
-	movl $6, %%edx \n\
-	jz 1f \n\
-\n\
-	movl $7, %%edx \n\
-1:" : "=d" (res) : : "eax", "ebx", "ecx" );
-
-	switch (res) {
-	case 3: puts( "386" );
-		break;
-	case 4: puts( "486" );
-		break;
-	case 5: puts( "no extended cpuid" );
-		break;
-	case 6: puts( "non-64bit 586+" );
-		break;
-	case 7: puts( "64bit" );
-		break;
-	default:puts( "internal error" );
-		break;
-	}
-	if (res !=7)
-		error( "Sorry, your CPU is not capable of running 64-bit kernel." );
-}
-
 int decompress_kernel(struct moveparams *mv, void *rmode)
 {
 	real_mode = rmode;
@@ -421,8 +351,6 @@
 	else setup_output_buffer_if_we_run_high(mv);
 
 	makecrc();
-	puts("Checking CPU type...");
-	check_cpu();
 	puts(".\nDecompressing Linux...");
 	gunzip();
 	puts("done.\nBooting the kernel.\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/setup.S linux-2.4.21-rc3/arch/x86_64/boot/setup.S
--- linux-2.4.20/arch/x86_64/boot/setup.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/boot/setup.S	2003-05-22 22:06:50.000000000 +0000
@@ -42,6 +42,7 @@
  * if CX/DX have been changed in the e801 call and if so use AX/BX .
  * Michael Miller, April 2001 <michaelm@mjmm.org>
  *
+ * Added long mode checking and SSE force. March 2003, Andi Kleen.		
  */
 
 #include <linux/config.h>
@@ -197,10 +198,10 @@
 prtsp2:	call	prtspc		# Print double space
 prtspc:	movb	$0x20, %al	# Print single space (note: fall-thru)
 
-# Part of above routine, this one just prints ascii al
-prtchr:	pushw	%ax
+prtchr:	
+	pushw	%ax
 	pushw	%cx
-	xorb	%bh, %bh
+	movw	$0007,%bx
 	movw	$0x01, %cx
 	movb	$0x0e, %ah
 	int	$0x10
@@ -277,6 +278,75 @@
 loader_panic_mess: .string "Wrong loader, giving up..."
 
 loader_ok:
+	/* check for long mode. */
+	/* we have to do this before the VESA setup, otherwise the user
+	   can't see the error message. */
+	
+	pushw	%ds
+	movw	%cs,%ax
+	movw	%ax,%ds
+	
+	/* minimum CPUID flags for x86-64 */
+	/* see http://www.x86-64.org/lists/discuss/msg02971.html */		
+#define SSE_MASK ((1<<25)|(1<<26))
+#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \
+					   (1<<13)|(1<<15)|(1<<24)|(1<<29))
+
+	pushfl				/* standard way to check for cpuid */
+	popl	%eax
+	movl	%eax,%ebx
+	xorl	$0x200000,%eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	cmpl	%eax,%ebx
+	jz	no_longmode		/* cpu has no cpuid */
+	movl	$0x80000000,%eax
+	cpuid
+	cmpl	$0x80000001,%eax
+	jb	no_longmode		/* no extended cpuid */
+	xor	%di,%di
+	cmpl	$0x68747541,%ebx	/* AuthenticAMD */
+	jnz	noamd
+	cmpl	$0x69746e65,%edx
+	jnz	noamd
+	cmpl	$0x444d4163,%ecx
+	jnz	noamd
+	mov	$1,%di			/* cpu is from AMD */
+noamd:		
+	movl	$0x80000001,%eax		
+	cpuid
+	andl	$REQUIRED_MASK1,%edx
+	xorl	$REQUIRED_MASK1,%edx
+	jnz	no_longmode
+sse_test:		
+	movl	$1,%eax
+	cpuid
+	andl	$SSE_MASK,%edx
+	cmpl	$SSE_MASK,%edx
+	je	sse_ok
+	test	%di,%di
+	jz	no_longmode	/* only try to force SSE on AMD */ 
+	movl	$0xc0010015,%ecx	/* HWCR */
+	rdmsr
+	btr	$15,%eax	/* enable SSE */
+	wrmsr
+	xor	%di,%di		/* don't loop */
+	jmp	sse_test	/* try again */	
+no_longmode:
+	call	beep
+	lea	long_mode_panic,%si
+	call	prtstr
+no_longmode_loop:		
+	jmp	no_longmode_loop
+long_mode_panic:
+	.string "Your CPU does not support long mode. Use a 32bit distribution."
+	.byte 0
+	
+sse_ok:
+	popw	%ds
+	
 # Get memory size (extended mem, kB)
 
 	xorl	%eax, %eax
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/config.in linux-2.4.21-rc3/arch/x86_64/config.in
--- linux-2.4.20/arch/x86_64/config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/config.in	2003-05-22 22:06:50.000000000 +0000
@@ -95,6 +95,7 @@
    source drivers/hotplug/Config.in
 else
    define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_HOTPLUG_PCI n
 fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -199,9 +200,8 @@
 source drivers/input/Config.in
 source drivers/char/Config.in
 
-source net/bluetooth/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source drivers/media/Config.in
 
@@ -230,6 +230,8 @@
 
 source drivers/usb/Config.in
 
+source net/bluetooth/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
@@ -241,7 +243,10 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Additional run-time checks' CONFIG_CHECKING
    bool '  Debug __init statements' CONFIG_INIT_DEBUG
+   bool '  IOMMU debugging' CONFIG_IOMMU_DEBUG
    bool '  IOMMU leak tracing' CONFIG_IOMMU_LEAK
    bool '  Probalistic stack overflow check' CONFIG_DEBUG_STACKOVERFLOW
 fi
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/defconfig linux-2.4.21-rc3/arch/x86_64/defconfig
--- linux-2.4.20/arch/x86_64/defconfig	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/defconfig	2003-05-22 22:06:43.000000000 +0000
@@ -42,8 +42,7 @@
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
 CONFIG_HPET_TIMER=y
-# CONFIG_GART_IOMMU is not set
-CONFIG_DUMMY_IOMMU=y
+CONFIG_GART_IOMMU=y
 CONFIG_X86_UP_IOAPIC=y
 CONFIG_MCE=y
 # CONFIG_K8_NUMA is not set
@@ -57,6 +56,7 @@
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -195,15 +195,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # 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
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -217,8 +208,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -227,30 +218,31 @@
 # 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
 # CONFIG_WDC_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -263,6 +255,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -302,10 +295,8 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
@@ -333,13 +324,11 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -388,6 +377,7 @@
 # CONFIG_ELMC is not set
 # CONFIG_ELMC_II is not set
 CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
@@ -406,6 +396,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
@@ -496,13 +487,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
 # CONFIG_AMD_RNG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -514,6 +512,7 @@
 #
 # CONFIG_FTAPE is not set
 CONFIG_AGP=y
+CONFIG_AGP_AMD_8151=y
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
 CONFIG_AGP_VIA=y
@@ -525,15 +524,6 @@
 # CONFIG_MWAVE is not set
 
 #
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Misc devices
-#
-
-#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -592,6 +582,7 @@
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+CONFIG_SIMICSFS=y
 
 #
 # Network File Systems
@@ -603,7 +594,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD_TCP=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -692,6 +683,11 @@
 # CONFIG_USB is not set
 
 #
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
 # Kernel hacking
 #
 CONFIG_DEBUG_KERNEL=y
@@ -700,5 +696,12 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_CHECKING is not set
 # CONFIG_INIT_DEBUG is not set
-# CONFIG_IOMMU_LEAK is not set
-CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_LEAK=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/fpu32.c linux-2.4.21-rc3/arch/x86_64/ia32/fpu32.c
--- linux-2.4.20/arch/x86_64/ia32/fpu32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/fpu32.c	2003-05-22 22:06:27.000000000 +0000
@@ -2,7 +2,7 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  * This is used for ptrace, signals and coredumps in 32bit emulation.
- * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
+ * $Id: fpu32.c,v 1.8 2003/03/24 09:29:51 ak Exp $
  */ 
 
 #include <linux/sched.h>
@@ -77,17 +77,20 @@
 	struct _fpxreg *to;
 	struct _fpreg *from;
 	int i;
-	int err; 
-	__u32 v;
+	int err = 0; 
+	u32 v;
 
-	err = __get_user(fxsave->cwd, (u16 *)&buf->cw); 
-	err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
-	err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
+#define G(num,val) err |= __get_user(val, num + (u32 *)buf)
+	G(0, fxsave->cwd);
+	G(1, fxsave->swd);
+	G(2, fxsave->twd);
 	fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
-	err |= __get_user(fxsave->rip, &buf->ipoff); 
-	err |= __get_user(fxsave->rdp, &buf->dataoff); 
-	err |= __get_user(v, &buf->cssel); 
-	fxsave->fop = v >> 16;
+	G(3, fxsave->rip);
+	G(4, v);
+	fxsave->fop = v>>16;	/* cs ignored */
+	G(5, fxsave->rdp);
+	/* 6: ds ignored */
+#undef G
 	if (err) 
 		return -1; 
 
@@ -109,21 +112,29 @@
 	struct _fpreg *to;
 	struct _fpxreg *from;
 	int i;
-	u32 ds; 
-	int err; 
+	u16 cs,ds; 
+	int err = 0; 
 
-	err = __put_user((unsigned long)fxsave->cwd | 0xffff0000, &buf->cw);
-	err |= __put_user((unsigned long)fxsave->swd | 0xffff0000, &buf->sw);
-	err |= __put_user((u32)fxsave->rip, &buf->ipoff); 
-	err |= __put_user((u32)(regs->cs | ((u32)fxsave->fop << 16)), 
-			  &buf->cssel); 
-	err |= __put_user((u32)twd_fxsr_to_i387(fxsave), &buf->tag); 
-	err |= __put_user((u32)fxsave->rdp, &buf->dataoff); 
-	if (tsk == current) 
-		asm("movl %%ds,%0 " : "=r" (ds)); 
-	else /* ptrace. task has stopped. */
+	if (tsk == current) {
+		/* should be actually ds/cs at fpu exception time,
+		   but that information is not available in 64bit mode. */
+		asm("movw %%ds,%0 " : "=r" (ds)); 
+		asm("movw %%cs,%0 " : "=r" (cs)); 		
+	} else { /* ptrace. task has stopped. */
 		ds = tsk->thread.ds;
-	err |= __put_user(ds, &buf->datasel); 
+		cs = regs->cs;
+	} 
+
+#define P(num,val) err |= __put_user(val, num + (u32 *)buf)
+	P(0, (u32)fxsave->cwd | 0xffff0000);
+	P(1, (u32)fxsave->swd | 0xffff0000);
+	P(2, twd_fxsr_to_i387(fxsave));
+	P(3, (u32)fxsave->rip);
+	P(4,  cs | ((u32)fxsave->fop) << 16); 
+	P(5, fxsave->rdp);
+	P(6, 0xffff0000 | ds);
+#undef P
+
 	if (err) 
 		return -1; 
 
@@ -144,8 +155,9 @@
 				     &buf->_fxsr_env[0],
 				     sizeof(struct i387_fxsave_struct)))
 			return -1;
-	} 
 	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
+	}
+	tsk->used_math = 1;
 	return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
 }  
 
@@ -156,12 +168,11 @@
 {
 	int err = 0;
 
-	if (!tsk->used_math) 
-		return 0;
-	tsk->used_math = 0; 
-	unlazy_fpu(tsk);
+	init_fpu(tsk);
 	if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
 		return -1;
+	if (fsave) 
+		return 0;
 	err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
 	if (fsave) 
 		return err ? -1 : 1; 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.21-rc3/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ia32_binfmt.c	2003-05-22 22:06:25.000000000 +0000
@@ -25,7 +25,9 @@
 
 #define IA32_EMULATOR 1
 
-#define IA32_PAGE_OFFSET 0xFFFFF000
+#define ELF_NAME "elf/i386"
+
+#define IA32_PAGE_OFFSET 0xFFFFe000
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 #define ELF_ET_DYN_BASE		(IA32_PAGE_OFFSET/3 + 0x1000000)
 
@@ -163,11 +165,13 @@
 #define ELF_PLAT_INIT(r)		elf32_init(r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
 
+extern void load_gs_index(unsigned);
+
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
-	__asm__("movl %0,%%fs": :"r" (0)); \
-	__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
-	wrmsrl(MSR_KERNEL_GS_BASE, 0); \
+	asm volatile("movl %0,%%fs": :"r" (0)); \
+	load_gs_index(0);	\
+	asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
 	(regs)->rip = (new_rip); \
 	(regs)->rsp = (new_rsp); \
 	(regs)->eflags = 0x200; \
@@ -203,6 +207,8 @@
 	regs->rax = 0;
 	regs->rbx = 0; 
 	regs->rbp = 0; 
+	regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = regs->r13 =
+		regs->r14 = regs->r15 = 0;	
 	me->thread.fs = 0; 
 	me->thread.gs = 0;
 	me->thread.fsindex = 0; 
@@ -237,7 +243,7 @@
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
 		mpnt->vm_end = IA32_STACK_TOP;
-		mpnt->vm_page_prot = PAGE_COPY;
+		mpnt->vm_page_prot = PAGE_COPY_EXEC;
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
 		mpnt->vm_pgoff = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.21-rc3/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ia32_ioctl.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ia32_ioctl.c,v 1.24 2002/09/17 15:23:41 ak Exp $
+/* $Id: ia32_ioctl.c,v 1.31 2003/03/21 07:50:07 ak Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -38,6 +38,7 @@
 #include <linux/cdrom.h>
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
 #include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
@@ -56,6 +57,10 @@
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/reiserfs_fs.h>
+#include <linux/if_tun.h>
+#include <linux/ctype.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 /* Ugh. This header really is not clean */
 #define min min
@@ -74,9 +79,14 @@
 #include <asm/ia32.h>
 #include <asm/uaccess.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_bonding.h>
+#include <linux/watchdog.h>
+
 #include <asm/module.h>
 #include <asm/ioctl32.h>
 #include <linux/soundcard.h>
+#include <linux/lp.h>
 
 #include <linux/atm.h>
 #include <linux/atmarp.h>
@@ -89,6 +99,19 @@
 #include <linux/atm_tcp.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
+#include <linux/mtd/mtd.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/nbd.h>
+#include <linux/random.h>
+#include <linux/filter.h>
+
+#include <asm/mtrr.h>
+
 
 #define A(__x) ((void *)(unsigned long)(__x))
 #define AA(__x)	A(__x)
@@ -442,6 +465,7 @@
         __kernel_caddr_t32  ifcbuf;
 };
 
+#ifdef CONFIG_NET
 static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct net_device *dev;
@@ -457,10 +481,12 @@
 
 	strncpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)-1);
 	ifr32.ifr_name[sizeof(ifr32.ifr_name)-1] = 0; 
+	dev_put(dev);
 	
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
 }
+#endif
 
 static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -557,9 +583,25 @@
 	}
 	switch (ethcmd) {
 	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_SMSGLVL:
+	case ETHTOOL_GLINK:
+	case ETHTOOL_NWAY_RST:  len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&regaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		len += sizeof(struct ethtool_regs);
+		break;
+	}
 	case ETHTOOL_GSET:
-	case ETHTOOL_SSET:
-	default:		len = sizeof(struct ethtool_cmd); break;
+	case ETHTOOL_SSET:      len = sizeof(struct ethtool_cmd); break;
+	default:
+               err = -EOPNOTSUPP;
+               goto out;
 	}
 
 	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
@@ -585,6 +627,91 @@
 	return err;
 }
 
+
+static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	switch (cmd) {
+	case SIOCBONDENSLAVE:
+	case SIOCBONDRELEASE:
+	case SIOCBONDSETHWADDR:
+	case SIOCBONDCHANGEACTIVE:
+		len = IFNAMSIZ * sizeof(char);
+		break;
+	case SIOCBONDSLAVEINFOQUERY:
+		len = sizeof(struct ifslave);
+		break;
+	case SIOCBONDINFOQUERY:
+		len = sizeof(struct ifbond);
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	};
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static __inline__ void *alloc_user_space(long len)
+{
+	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
+	return (void *)regs->rsp - len; 
+}
+
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq *u_ifreq64;
+	struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg;
+	char tmp_buf[IFNAMSIZ];
+	void *data64;
+	u32 data32;
+
+	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
+			   IFNAMSIZ))
+		return -EFAULT;
+	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
+		return -EFAULT;
+	data64 = (void *) A(data32);
+
+	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+
+	/* Don't check these user accesses, just let that get trapped
+	 * in the ioctl handler instead.
+	 */
+	copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
+	__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+}
+
 static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
@@ -603,15 +730,6 @@
 		if (err)
 			return -EFAULT;
 		break;
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
-		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
-			return -EFAULT;
-		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
-		if (!ifr.ifr_data)
-			return -EAGAIN;
-		break;
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
@@ -637,27 +755,6 @@
 			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-		{
-			u32 data;
-			int len;
-
-			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(cmd == SIOCGPPPVER)
-				len = strlen((char *)ifr.ifr_data) + 1;
-			else if(cmd == SIOCGPPPCSTATS)
-				len = sizeof(struct ppp_comp_stats);
-			else
-				len = sizeof(struct ppp_stats);
-
-			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
-			free_page((unsigned long)ifr.ifr_data);
-			if(len)
-				return -EFAULT;
-			break;
-		}
 		case SIOCGIFMAP:
 			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
 			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
@@ -670,14 +767,6 @@
 				err = -EFAULT;
 			break;
 		}
-	} else {
-		switch (cmd) {
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-			free_page((unsigned long)ifr.ifr_data);
-			break;
-		}
 	}
 	return err;
 }
@@ -716,11 +805,6 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
-extern __inline__ void sockfd_put(struct socket *sock)
-{
-	fput(sock->file);
-}
-
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -769,9 +853,6 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
-	if (mysock)
-		sockfd_put(mysock);
-
 	return ret;
 }
 
@@ -798,14 +879,6 @@
 	return err ? -EFAULT : 0;
 }
 
-struct  fbcmap32 {
-	int             index;          /* first element (0 origin) */
-	int             count;
-	u32		red;
-	u32		green;
-	u32		blue;
-};
-
 struct fb_fix_screeninfo32 {
 	char			id[16];
         __kernel_caddr_t32	smem_start;
@@ -889,7 +962,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("%s: Unknown fb ioctl cmd fd(%d) "
 				       "cmd(%08x) arg(%08lx)\n",
@@ -1268,6 +1341,269 @@
 	return err;
 }
 
+
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	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) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	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, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
+struct sock_fprog32 {
+	__u16	len;
+	__u32	filter;
+};
+
+#define PPPIOCSPASS32	_IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32	_IOW('t', 70, struct sock_fprog32)
+
+static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
+	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	void *fptr64;
+	u32 fptr32;
+	u16 flen;
+
+	if (get_user(flen, &u_fprog32->len) ||
+	    get_user(fptr32, &u_fprog32->filter))
+		return -EFAULT;
+
+	fptr64 = (void *) A(fptr32);
+
+	if (put_user(flen, &u_fprog64->len) ||
+	    put_user(fptr64, &u_fprog64->filter))
+		return -EFAULT;
+
+	if (cmd == PPPIOCSPASS32)
+		cmd = PPPIOCSPASS;
+	else
+		cmd = PPPIOCSACTIVE;
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -1314,7 +1650,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("ppp_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1424,7 +1760,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("mt_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1542,7 +1878,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("cdrom_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1629,7 +1965,7 @@
 		}
 		break;
 	default: {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("%s: Unknown loop ioctl cmd, fd(%d) "
 			       "cmd(%08x) arg(%08lx)\n",
@@ -2443,791 +2779,826 @@
 }
 #endif
 
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-/* This really belongs in include/linux/drm.h -DaveM */
-#include "../../../drivers/char/drm/drm.h"
-
-typedef struct drm32_version {
-	int    version_major;	  /* Major version			    */
-	int    version_minor;	  /* Minor version			    */
-	int    version_patchlevel;/* Patch level			    */
-	int    name_len;	  /* Length of name buffer		    */
-	u32    name;		  /* Name of driver			    */
-	int    date_len;	  /* Length of date buffer		    */
-	u32    date;		  /* User-space buffer to hold date	    */
-	int    desc_len;	  /* Length of desc buffer		    */
-	u32    desc;		  /* User-space buffer to hold desc	    */
-} drm32_version_t;
-#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
-
-static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_version_t *uversion = (drm32_version_t *)arg;
-	char *name_ptr, *date_ptr, *desc_ptr;
-	u32 tmp1, tmp2, tmp3;
-	drm_version_t kversion;
-	mm_segment_t old_fs;
-	int ret;
-
-	memset(&kversion, 0, sizeof(kversion));
-	if (get_user(kversion.name_len, &uversion->name_len) ||
-	    get_user(kversion.date_len, &uversion->date_len) ||
-	    get_user(kversion.desc_len, &uversion->desc_len) ||
-	    get_user(tmp1, &uversion->name) ||
-	    get_user(tmp2, &uversion->date) ||
-	    get_user(tmp3, &uversion->desc))
-		return -EFAULT;
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
 
-	name_ptr = (char *) A(tmp1);
-	date_ptr = (char *) A(tmp2);
-	desc_ptr = (char *) A(tmp3);
-
-	ret = -ENOMEM;
-	if (kversion.name_len && name_ptr) {
-		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
-		if (!kversion.name)
-			goto out;
-	}
-	if (kversion.date_len && date_ptr) {
-		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
-		if (!kversion.date)
-			goto out;
-	}
-	if (kversion.desc_len && desc_ptr) {
-		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
-		if (!kversion.desc)
-			goto out;
-	}
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
 
-        old_fs = get_fs();
-	set_fs(KERNEL_DS);
-        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
-        set_fs(old_fs);
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
 
-	if (!ret) {
-		if ((kversion.name &&
-		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
-		    (kversion.date &&
-		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
-		    (kversion.desc &&
-		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
-			ret = -EFAULT;
-		if (put_user(kversion.version_major, &uversion->version_major) ||
-		    put_user(kversion.version_minor, &uversion->version_minor) ||
-		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
-		    put_user(kversion.name_len, &uversion->name_len) ||
-		    put_user(kversion.date_len, &uversion->date_len) ||
-		    put_user(kversion.desc_len, &uversion->desc_len))
-			ret = -EFAULT;
-	}
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
 
-out:
-	if (kversion.name)
-		kfree(kversion.name);
-	if (kversion.date)
-		kfree(kversion.date);
-	if (kversion.desc)
-		kfree(kversion.desc);
-	return ret;
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
 }
 
-typedef struct drm32_unique {
-	int	unique_len;	  /* Length of unique			    */
-	u32	unique;		  /* Unique name for driver instantiation   */
-} drm32_unique_t;
-#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
-#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
-
-static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	drm32_unique_t *uarg = (drm32_unique_t *)arg;
-	drm_unique_t karg;
-	mm_segment_t old_fs;
-	char *uptr;
-	u32 tmp;
-	int ret;
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
 
-	if (get_user(karg.unique_len, &uarg->unique_len))
-		return -EFAULT;
-	karg.unique = NULL;
+#ifndef TIOCGDEV
+#define TIOCGDEV       _IOR('T',0x32, unsigned int)
+#endif
+static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
+{ 
 
-	if (get_user(tmp, &uarg->unique))
-		return -EFAULT;
+	struct file *file = fget(fd);
+	struct tty_struct *real_tty;
+
+	if (!fd)
+		return -EBADF;
+	if (file->f_op->ioctl != tty_ioctl)
+		return -EINVAL; 
+	real_tty = (struct tty_struct *)file->private_data;
+	if (!real_tty) 	
+		return -EINVAL; 
+	return put_user(kdev_t_to_nr(real_tty->device), ptr); 
+} 
 
-	uptr = (char *) A(tmp);
 
-	if (uptr) {
-		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
-		if (!karg.unique)
-			return -ENOMEM;
-		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
-		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
-			kfree(karg.unique);
+struct raw32_config_request 
+{
+	int	raw_minor;
+	__u64	block_major;
+	__u64	block_minor;
+} __attribute__((packed));
+
+static int raw_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+{ 
+	int ret;
+	switch (cmd) { 
+	case RAW_SETBIND:
+	case RAW_GETBIND: {
+		struct raw_config_request req; 
+		struct raw32_config_request *user_req = ptr;
+		mm_segment_t oldfs = get_fs(); 
+
+		if (get_user(req.raw_minor, &user_req->raw_minor) ||
+		    get_user(req.block_major, &user_req->block_major) ||
+		    get_user(req.block_minor, &user_req->block_minor))
 			return -EFAULT;
-		}
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd,cmd,(unsigned long)&req); 
+		set_fs(oldfs); 
+		break;
 	}
+	default:
+		ret = sys_ioctl(fd,cmd,(unsigned long)ptr);
+		break;
+	} 
+	return ret; 		
+} 
 
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	if (cmd == DRM32_IOCTL_GET_UNIQUE)
-		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
-	else
-		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
-        set_fs(old_fs);
+struct serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	__u32 iomem_base;
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
 
-	if (!ret) {
-		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
-		    uptr != NULL &&
-		    copy_to_user(uptr, karg.unique, karg.unique_len))
-			ret = -EFAULT;
-		if (put_user(karg.unique_len, &uarg->unique_len))
-			ret = -EFAULT;
+static int serial_struct_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+{
+	typedef struct serial_struct SS;
+	struct serial_struct32 *ss32 = ptr; 
+	int err;
+	struct serial_struct ss; 
+	mm_segment_t oldseg = get_fs(); 
+	if (cmd == TIOCSSERIAL) { 
+		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
+			return -EFAULT;
+		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
+			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
+		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
 	}
+	set_fs(KERNEL_DS);
+		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+	set_fs(oldseg);
+	if (cmd == TIOCGSERIAL && err >= 0) { 
+		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
+		    __put_user((unsigned long)ss.iomem_base  >> 32 ? 
+			       0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
+			       &ss32->iomem_base) ||
+		    __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) || 
+		    __put_user(ss.port_high, &ss32->port_high))
+			return -EFAULT;
+	} 
+	return err;	
+}
 
-	if (karg.unique != NULL)
-		kfree(karg.unique);
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+#define HCIUARTGETPROTO        _IOR('U', 201, int)
+
+#define BNEPCONNADD    _IOW('B', 200, int)
+#define BNEPCONNDEL    _IOW('B', 201, int)
+#define BNEPGETCONNLIST        _IOR('B', 210, int)
+#define BNEPGETCONNINFO        _IOR('B', 211, int)
 
-	return ret;
-}
+#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
+
+static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
+{ 
+	if (cmd == REISERFS_IOC_UNPACK32) 
+		cmd = REISERFS_IOC_UNPACK; 
+	return sys_ioctl(fd,cmd,ptr); 
+} 
+
+struct dirent32 {
+	unsigned int		d_ino;
+	__kernel_off_t32	d_off;
+	unsigned short	d_reclen;
+	char		d_name[256]; /* We must not include limits.h! */
+};
+
+#define	VFAT_IOCTL_READDIR_BOTH32	_IOR('r', 1, struct dirent32 [2])
+#define	VFAT_IOCTL_READDIR_SHORT32	_IOR('r', 2, struct dirent32 [2])
 
-typedef struct drm32_map {
-	u32		offset;	 /* Requested physical address (0 for SAREA)*/
-	u32		size;	 /* Requested physical size (bytes)	    */
-	drm_map_type_t	type;	 /* Type of memory to map		    */
-	drm_map_flags_t flags;	 /* Flags				    */
-	u32		handle;  /* User-space: "Handle" to pass to mmap    */
-				 /* Kernel-space: kernel-virtual address    */
-	int		mtrr;	 /* MTRR slot used			    */
-				 /* Private data			    */
-} drm32_map_t;
-#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
+static int put_dirent32(struct dirent *src, struct dirent32 *dst)
+{ 
+	int ret;
+	ret = put_user(src->d_ino, &dst->d_ino); 
+	ret |= __put_user(src->d_off, &dst->d_off); 
+	ret |= __put_user(src->d_reclen, &dst->d_reclen); 
+	if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen))
+		ret |= -EFAULT;
+	return ret;
+} 
 
-static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
 {
-	drm32_map_t *uarg = (drm32_map_t *) arg;
-	drm_map_t karg;
-	mm_segment_t old_fs;
-	u32 tmp;
 	int ret;
+	mm_segment_t oldfs = get_fs();
+	struct dirent d[2]; 
 
-	ret  = get_user(karg.offset, &uarg->offset);
-	ret |= get_user(karg.size, &uarg->size);
-	ret |= get_user(karg.type, &uarg->type);
-	ret |= get_user(karg.flags, &uarg->flags);
-	ret |= get_user(tmp, &uarg->handle);
-	ret |= get_user(karg.mtrr, &uarg->mtrr);
-	if (ret)
-		return -EFAULT;
+	set_fs(KERNEL_DS); 
+	ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
+	set_fs(oldfs); 
+	if (!ret) { 
+		ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); 
+		ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); 
+	} 
+	return ret;
+}
 
-	karg.handle = (void *) A(tmp);
+#define RTC_IRQP_READ32	_IOR('p', 0x0b, unsigned int)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET32	_IOW('p', 0x0c, unsigned int)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ32	_IOR('p', 0x0d, unsigned)	 /* Read epoch      */
+#define RTC_EPOCH_SET32		_IOW('p', 0x0e, unsigned)	 /* Set epoch       */
 
-	old_fs = get_fs();
+static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) 
+{
+	unsigned long val;
+	mm_segment_t oldfs = get_fs(); 
+	int ret; 
+	
+	switch (cmd) { 
+	case RTC_IRQP_READ32: 
 	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
-	set_fs(old_fs);
+		ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+	return ret; 
 
-	if (!ret) {
-		ret  = put_user(karg.offset, &uarg->offset);
-		ret |= put_user(karg.size, &uarg->size);
-		ret |= put_user(karg.type, &uarg->type);
-		ret |= put_user(karg.flags, &uarg->flags);
-		tmp = (u32) (long)karg.handle;
-		ret |= put_user(tmp, &uarg->handle);
-		ret |= put_user(karg.mtrr, &uarg->mtrr);
-		if (ret)
-			ret = -EFAULT;
-	}
+	case RTC_IRQP_SET32: 
+		cmd = RTC_EPOCH_SET; 
+		break; 
 
-	return ret;
-}
+	case RTC_EPOCH_READ32:
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+		return ret; 
 
-typedef struct drm32_buf_info {
-	int	       count;	/* Entries in list			     */
-	u32	       list;    /* (drm_buf_desc_t *) */ 
-} drm32_buf_info_t;
-#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
-
-static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
-	drm_buf_desc_t *ulist;
-	drm_buf_info_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
+	case RTC_EPOCH_SET32:
+		cmd = RTC_EPOCH_SET; 
+		break; 
+	} 
+	return sys_ioctl(fd,cmd,arg); 
+} 
 
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
-		return -EFAULT;
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32   _IOR(0x12,106,int)
+#define BLKELVSET_32   _IOW(0x12,107,int)
+#define BLKBSZGET_32   _IOR(0x12,112,int)
+#define BLKBSZSET_32   _IOW(0x12,113,int)
+#define BLKGETSIZE64_32        _IOR(0x12,114,int)
 
-	ulist = (drm_buf_desc_t *) A(tmp);
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVGET, arg);
+}
 
-	orig_count = karg.count;
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVSET, arg);
+}
 
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
-	if (!karg.list)
-		return -EFAULT;
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZGET, arg);
+}
 
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZSET, arg);
+}
 
-	if (!ret) {
-		if (karg.count <= orig_count &&
-		    (copy_to_user(ulist, karg.list,
-				  karg.count * sizeof(drm_buf_desc_t))))
-			ret = -EFAULT;
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+                          unsigned long arg)
+{
+       return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
 
-	kfree(karg.list);
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+#define HCIUARTGETPROTO        _IOR('U', 201, int)
 
-	return ret;
-}
+#define BNEPCONNADD    _IOW('B', 200, int)
+#define BNEPCONNDEL    _IOW('B', 201, int)
+#define BNEPGETCONNLIST        _IOR('B', 210, int)
+#define BNEPGETCONNINFO        _IOR('B', 211, int)
 
-typedef struct drm32_buf_free {
-	int	       count;
-	u32	       list;	/* (int *) */
-} drm32_buf_free_t;
-#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
+struct usbdevfs_ctrltransfer32 {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+	__u32 data;
+};
 
-static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+
+static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
-	drm_buf_free_t karg;
+	struct usbdevfs_ctrltransfer kctrl;
+	struct usbdevfs_ctrltransfer32 *uctrl;
 	mm_segment_t old_fs;
-	int *ulist;
-	int ret;
-	u32 tmp;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
 
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
+	if (copy_from_user(&kctrl, uctrl,
+			   (sizeof(struct usbdevfs_ctrltransfer) -
+			    sizeof(void *))))
 		return -EFAULT;
 
-	ulist = (int *) A(tmp);
+	if (get_user(udata, &uctrl->data))
+		return -EFAULT;
+	uptr = (void *) A(udata);
 
-	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kctrl.length > PAGE_SIZE)
+		return -EINVAL;
 
-	ret = -EFAULT;
-	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
-		goto out;
+	kptr = (void *)__get_free_page(GFP_KERNEL);
+
+	if ((kctrl.requesttype & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kctrl.length))
+			goto out;
+	}
+
+	kctrl.data = kptr;
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+	err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
 	set_fs(old_fs);
 
-out:
-	kfree(karg.list);
+	if (err >= 0 &&
+	    ((kctrl.requesttype & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.length))
+			err = -EFAULT;
+	}
 
-	return ret;
+out:
+	free_page((unsigned long) kptr);
+	return err;
 }
 
-typedef struct drm32_buf_pub {
-	int		  idx;	       /* Index into master buflist	     */
-	int		  total;       /* Buffer size			     */
-	int		  used;	       /* Amount of buffer in use (for DMA)  */
-	u32		  address;     /* Address of buffer (void *)	     */
-} drm32_buf_pub_t;
-
-typedef struct drm32_buf_map {
-	int	      count;	/* Length of buflist			    */
-	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
-	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
-} drm32_buf_map_t;
-#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
-
-static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
-	drm32_buf_pub_t *ulist;
-	drm_buf_map_t karg;
+struct usbdevfs_bulktransfer32 {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+
+static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_bulktransfer kbulk;
+	struct usbdevfs_bulktransfer32 *ubulk;
 	mm_segment_t old_fs;
-	int orig_count, ret, i;
-	u32 tmp1, tmp2;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	ubulk = (struct usbdevfs_bulktransfer32 *) arg;
 
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp1, &uarg->virtual) ||
-	    get_user(tmp2, &uarg->list))
+	if (get_user(kbulk.ep, &ubulk->ep) ||
+	    get_user(kbulk.len, &ubulk->len) ||
+	    get_user(kbulk.timeout, &ubulk->timeout) ||
+	    get_user(udata, &ubulk->data))
 		return -EFAULT;
 
-	karg.virtual = (void *) A(tmp1);
-	ulist = (drm32_buf_pub_t *) A(tmp2);
+	uptr = (void *) A(udata);
 
-	orig_count = karg.count;
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kbulk.len > PAGE_SIZE)
+		return -EINVAL;
 
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
+	kptr = (void *) __get_free_page(GFP_KERNEL);
 
-	ret = -EFAULT;
-	for (i = 0; i < karg.count; i++) {
-		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
-		    get_user(karg.list[i].total, &ulist[i].total) ||
-		    get_user(karg.list[i].used, &ulist[i].used) ||
-		    get_user(tmp1, &ulist[i].address))
+	if ((kbulk.ep & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kbulk.len))
 			goto out;
-
-		karg.list[i].address = (void *) A(tmp1);
 	}
 
+	kbulk.data = kptr;
+
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+	err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
 	set_fs(old_fs);
 
-	if (!ret) {
-		for (i = 0; i < orig_count; i++) {
-			tmp1 = (u32) (long) karg.list[i].address;
-			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
-			    put_user(karg.list[i].total, &ulist[i].total) ||
-			    put_user(karg.list[i].used, &ulist[i].used) ||
-			    put_user(tmp1, &ulist[i].address)) {
-				ret = -EFAULT;
-				goto out;
-			}
-		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
+	if (err >= 0 &&
+	    ((kbulk.ep & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kbulk.len))
+			err = -EFAULT;
 	}
 
 out:
-	kfree(karg.list);
-	return ret;
+	free_page((unsigned long) kptr);
+	return err;
 }
 
-typedef struct drm32_dma {
-				/* Indices here refer to the offset into
-				   buflist in drm_buf_get_t.  */
-	int		context;	  /* Context handle		    */
-	int		send_count;	  /* Number of buffers to send	    */
-	u32		send_indices;	  /* List of handles to buffers (int *) */
-	u32		send_sizes;	  /* Lengths of data to send (int *) */
-	drm_dma_flags_t flags;		  /* Flags			    */
-	int		request_count;	  /* Number of buffers requested    */
-	int		request_size;	  /* Desired size for buffers	    */
-	u32		request_indices;  /* Buffer information (int *)	    */
-	u32		request_sizes;    /* (int *) */
-	int		granted_count;	  /* Number of buffers granted	    */
-} drm32_dma_t;
-#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
-
-/* RED PEN	The DRM layer blindly dereferences the send/request
- * 		indice/size arrays even though they are userland
- * 		pointers.  -DaveM
+/* This needs more work before we can enable it.  Unfortunately
+ * because of the fancy asynchronous way URB status/error is written
+ * back to userspace, we'll need to fiddle with USB devio internals
+ * and/or reimplement entirely the frontend of it ourselves. -DaveM
+ *
+ * The issue is:
+ *
+ *	When an URB is submitted via usbdevicefs it is put onto an
+ *	asynchronous queue.  When the URB completes, it may be reaped
+ *	via another ioctl.  During this reaping the status is written
+ *	back to userspace along with the length of the transfer.
+ *
+ *	We must translate into 64-bit kernel types so we pass in a kernel
+ *	space copy of the usbdevfs_urb structure.  This would mean that we
+ *	must do something to deal with the async entry reaping.  First we
+ *	have to deal somehow with this transitory memory we've allocated.
+ *	This is problematic since there are many call sites from which the
+ *	async entries can be destroyed (and thus when we'd need to free up
+ *	this kernel memory).  One of which is the close() op of usbdevicefs.
+ *	To handle that we'd need to make our own file_operations struct which
+ *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
+ *	real release op then frees up the kernel memory.
+ *
+ *	But how to keep track of these kernel buffers?  We'd need to either
+ *	keep track of them in some table _or_ know about usbdevicefs internals
+ *	(ie. the exact layout of it's file private, which is actually defined
+ *	in linux/usbdevice_fs.h, the layout of the async queues are private to
+ *	devio.c)
+ *
+ * There is one possible other solution I considered, also involving knowledge
+ * of usbdevicefs internals:
+ *
+ *	After an URB is submitted, we "fix up" the address back to the user
+ *	space one.  This would work if the status/length fields written back
+ *	by the async URB completion lines up perfectly in the 32-bit type with
+ *	the 64-bit kernel type.  Unfortunately, it does not because the iso
+ *	frame descriptors, at the end of the struct, can be written back.
+ *
+ * I think we'll just need to simply duplicate the devio URB engine here.
  */
-static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_dma_t *uarg = (drm32_dma_t *) arg;
-	int *u_si, *u_ss, *u_ri, *u_rs;
-	drm_dma_t karg;
-	mm_segment_t old_fs;
-	int ret;
-	u32 tmp1, tmp2, tmp3, tmp4;
+#if 0
+struct usbdevfs_urb32 {
+	__u8 type;
+	__u8 endpoint;
+	__s32 status;
+	__u32 flags;
+	__u32 buffer;
+	__s32 buffer_length;
+	__s32 actual_length;
+	__s32 start_frame;
+	__s32 number_of_packets;
+	__s32 error_count;
+	__u32 signr;
+	__u32 usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
 
-	karg.send_indices = karg.send_sizes = NULL;
-	karg.request_indices = karg.request_sizes = NULL;
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
 
-	if (get_user(karg.context, &uarg->context) ||
-	    get_user(karg.send_count, &uarg->send_count) ||
-	    get_user(tmp1, &uarg->send_indices) ||
-	    get_user(tmp2, &uarg->send_sizes) ||
-	    get_user(karg.flags, &uarg->flags) ||
-	    get_user(karg.request_count, &uarg->request_count) ||
-	    get_user(karg.request_size, &uarg->request_size) ||
-	    get_user(tmp3, &uarg->request_indices) ||
-	    get_user(tmp4, &uarg->request_sizes) ||
-	    get_user(karg.granted_count, &uarg->granted_count))
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
 		return -EFAULT;
 
-	u_si = (int *) A(tmp1);
-	u_ss = (int *) A(tmp2);
-	u_ri = (int *) A(tmp3);
-	u_rs = (int *) A(tmp4);
-
-	if (karg.send_count) {
-		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
-		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+	kurb->usercontext = 0; /* unused currently */
 
-		ret = -ENOMEM;
-		if (!karg.send_indices || !karg.send_sizes)
-			goto out;
+	return 0;
+}
 
-		ret = -EFAULT;
-		if (copy_from_user(karg.send_indices, u_si,
-				   (karg.send_count * sizeof(int))) ||
-		    copy_from_user(karg.send_sizes, u_ss,
-				   (karg.send_count * sizeof(int))))
-			goto out;
+/* Just put back the values which usbdevfs actually changes. */
+static int put_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (put_user(kurb->status, &uurb->status) ||
+	    __put_user(kurb->actual_length, &uurb->actual_length) ||
+	    __put_user(kurb->error_count, &uurb->error_count))
+		return -EFAULT;
+
+	if (kurb->number_of_packets != 0) {
+		int i;
+
+		for (i = 0; i < kurb->number_of_packets; i++) {
+			if (__put_user(kurb->iso_frame_desc[i].actual_length,
+				       &uurb->iso_frame_desc[i].actual_length) ||
+			    __put_user(kurb->iso_frame_desc[i].status,
+				       &uurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
 	}
 
-	if (karg.request_count) {
-		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
-		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+	return 0;
+}
 
-		ret = -ENOMEM;
-		if (!karg.request_indices || !karg.request_sizes)
-			goto out;
+static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+			       struct usbdevfs_urb32 *uurb)
+{
+	unsigned int totlen;
+	int i;
 
-		ret = -EFAULT;
-		if (copy_from_user(karg.request_indices, u_ri,
-				   (karg.request_count * sizeof(int))) ||
-		    copy_from_user(karg.request_sizes, u_rs,
-				   (karg.request_count * sizeof(int))))
-			goto out;
+	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+		kurb->number_of_packets = 0;
+		return 0;
 	}
 
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
-	set_fs(old_fs);
+	if (kurb->number_of_packets < 1 ||
+	    kurb->number_of_packets > 128)
+		return -EINVAL;
 
-	if (!ret) {
-		if (put_user(karg.context, &uarg->context) ||
-		    put_user(karg.send_count, &uarg->send_count) ||
-		    put_user(karg.flags, &uarg->flags) ||
-		    put_user(karg.request_count, &uarg->request_count) ||
-		    put_user(karg.request_size, &uarg->request_size) ||
-		    put_user(karg.granted_count, &uarg->granted_count))
-			ret = -EFAULT;
-
-		if (karg.send_count) {
-			if (copy_to_user(u_si, karg.send_indices,
-					 (karg.send_count * sizeof(int))) ||
-			    copy_to_user(u_ss, karg.send_sizes,
-					 (karg.send_count * sizeof(int))))
-				ret = -EFAULT;
-		}
-		if (karg.request_count) {
-			if (copy_to_user(u_ri, karg.request_indices,
-					 (karg.request_count * sizeof(int))) ||
-			    copy_to_user(u_rs, karg.request_sizes,
-					 (karg.request_count * sizeof(int))))
-				ret = -EFAULT;
-		}
+	if (copy_from_user(&kurb->iso_frame_desc[0],
+			   &uurb->iso_frame_desc[0],
+			   sizeof(struct usbdevfs_iso_packet_desc) *
+			   kurb->number_of_packets))
+		return -EFAULT;
+
+	totlen = 0;
+	for (i = 0; i < kurb->number_of_packets; i++) {
+		unsigned int this_len;
+
+		this_len = kurb->iso_frame_desc[i].length;
+		if (this_len > 1023)
+			return -EINVAL;
+
+		totlen += this_len;
 	}
 
-out:
-	if (karg.send_indices)
-		kfree(karg.send_indices);
-	if (karg.send_sizes)
-		kfree(karg.send_sizes);
-	if (karg.request_indices)
-		kfree(karg.request_indices);
-	if (karg.request_sizes)
-		kfree(karg.request_sizes);
+	if (totlen > 32768)
+		return -EINVAL;
 
-	return ret;
+	kurb->buffer_length = totlen;
+
+	return 0;
 }
 
-typedef struct drm32_ctx_res {
-	int		count;
-	u32		contexts; /* (drm_ctx_t *) */
-} drm32_ctx_res_t;
-#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
-
-static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
-	drm_ctx_t *ulist;
-	drm_ctx_res_t karg;
+static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_urb *kurb;
+	struct usbdevfs_urb32 *uurb;
 	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
+	__u32 udata;
+	void *uptr, *kptr;
+	unsigned int buflen;
+	int err;
 
-	karg.contexts = NULL;
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->contexts))
-		return -EFAULT;
+	uurb = (struct usbdevfs_urb32 *) arg;
 
-	ulist = (drm_ctx_t *) A(tmp);
+	err = -ENOMEM;
+	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+		       GFP_KERNEL);
+	if (!kurb)
+		goto out;
 
-	orig_count = karg.count;
-	if (karg.count && ulist) {
-		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
-		if (!karg.contexts)
-			return -ENOMEM;
-		if (copy_from_user(karg.contexts, ulist,
-				   (karg.count * sizeof(drm_ctx_t)))) {
-			kfree(karg.contexts);
-			return -EFAULT;
-		}
-	}
+	err = -EFAULT;
+	if (get_urb32(kurb, uurb))
+		goto out;
+
+	err = get_urb32_isoframes(kurb, uurb);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (__get_user(udata, &uurb->buffer))
+		goto out;
+	uptr = (void *) A(udata);
+
+	err = -ENOMEM;
+	buflen = kurb->buffer_length;
+	kptr = kmalloc(buflen, GFP_KERNEL);
+	if (!kptr)
+		goto out;
+
+	kurb->buffer = kptr;
+
+	err = -EFAULT;
+	if (copy_from_user(kptr, uptr, buflen))
+		goto out_kptr;
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
 	set_fs(old_fs);
 
-	if (!ret) {
-		if (orig_count) {
-			if (copy_to_user(ulist, karg.contexts,
-					 (orig_count * sizeof(drm_ctx_t))))
-				ret = -EFAULT;
+	if (err >= 0) {
+		/* XXX Shit, this doesn't work for async URBs :-( XXX */
+		if (put_urb32(kurb, uurb)) {
+			err = -EFAULT;
+		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+			if (copy_to_user(uptr, kptr, buflen))
+				err = -EFAULT;
 		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
 	}
 
-	if (karg.contexts)
-		kfree(karg.contexts);
+out_kptr:
+	kfree(kptr);
 
-	return ret;
-}
-
-#endif
-
-static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
-static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	/* The mkswap binary hard codes it to Intel value :-((( */
-	return w_long(fd, BLKGETSIZE, arg);
-}
-
-struct blkpg_ioctl_arg32 {
-	int op;
-	int flags;
-	int datalen;
-	u32 data;
-};
-                                
-static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
-{
-	struct blkpg_ioctl_arg a;
-	struct blkpg_partition p;
-	int err;
-	mm_segment_t old_fs = get_fs();
-	
-	err = get_user(a.op, &arg->op);
-	err |= __get_user(a.flags, &arg->flags);
-	err |= __get_user(a.datalen, &arg->datalen);
-	err |= __get_user((long)a.data, &arg->data);
-	if (err) return err;
-	switch (a.op) {
-	case BLKPG_ADD_PARTITION:
-	case BLKPG_DEL_PARTITION:
-		if (a.datalen < sizeof(struct blkpg_partition))
-			return -EINVAL;
-                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-			return -EFAULT;
-		a.data = &p;
-		set_fs (KERNEL_DS);
-		err = sys_ioctl(fd, cmd, (unsigned long)&a);
-		set_fs (old_fs);
-	default:
-		return -EINVAL;
-	}                                        
+out:
+	kfree(kurb);
 	return err;
 }
+#endif
 
-static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+
+static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
-}
+	mm_segment_t old_fs;
+	void *kptr;
+	int err;
 
-/* SuSE extension */ 
-#ifndef TIOCGDEV
-#define TIOCGDEV       _IOR('T',0x32, unsigned int)
-#endif
-static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
-{ 
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd,
+			(cmd == USBDEVFS_REAPURB32 ?
+			 USBDEVFS_REAPURB :
+			 USBDEVFS_REAPURBNDELAY),
+			(unsigned long) &kptr);
+	set_fs(old_fs);
 
-	struct file *file = fget(fd);
-	struct tty_struct *real_tty;
+	if (err >= 0 &&
+	    put_user(((u32)(long)kptr), (u32 *) A(arg)))
+		err = -EFAULT;
 
-	if (!fd)
-		return -EBADF;
-	if (file->f_op->ioctl != tty_ioctl)
-		return -EINVAL; 
-	real_tty = (struct tty_struct *)file->private_data;
-	if (!real_tty) 	
-		return -EINVAL; 
-	return put_user(kdev_t_to_nr(real_tty->device), ptr); 
-} 
+	return err;
+}
 
+struct usbdevfs_disconnectsignal32 {
+	unsigned int signr;
+	u32 context;
+};
 
-struct raw32_config_request 
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+
+static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	int	raw_minor;
-	__u64	block_major;
-	__u64	block_minor;
-} __attribute__((packed));
+	struct usbdevfs_disconnectsignal kdis;
+	struct usbdevfs_disconnectsignal32 *udis;
+	mm_segment_t old_fs;
+	u32 uctx;
+	int err;
 
-static int raw_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
-{ 
-	int ret;
-	switch (cmd) { 
-	case RAW_SETBIND:
-	case RAW_GETBIND: {
-		struct raw_config_request req; 
-		struct raw32_config_request *user_req = ptr;
-		mm_segment_t oldfs = get_fs(); 
+	udis = (struct usbdevfs_disconnectsignal32 *) arg;
 
-		if (get_user(req.raw_minor, &user_req->raw_minor) ||
-		    get_user(req.block_major, &user_req->block_major) ||
-		    get_user(req.block_minor, &user_req->block_minor))
-			return -EFAULT;
-		set_fs(KERNEL_DS); 
-		ret = sys_ioctl(fd,cmd,(unsigned long)&req); 
-		set_fs(oldfs); 
-		break;
-	}
-	default:
-		ret = sys_ioctl(fd,cmd,(unsigned long)ptr);
-		break;
-	} 
-	return ret; 		
-} 
+	if (get_user(kdis.signr, &udis->signr) ||
+	    __get_user(uctx, &udis->context))
+		return -EFAULT;
 
-struct serial_struct32 {
-	int	type;
-	int	line;
-	unsigned int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	io_type;
-	char	reserved_char[1];
-	int	hub6;
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	__u32 iomem_base;
-	unsigned short	iomem_reg_shift;
-	unsigned int	port_high;
-	int	reserved[1];
+	kdis.context = (void *) (long)uctx;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+	set_fs(old_fs);
+
+	return err;
+}
+
+struct mtd_oob_buf32 {
+	u32 start;
+	u32 length;
+	u32 ptr;	/* unsigned char* */
 };
 
-static int serial_struct_ioctl(unsigned fd, unsigned cmd,  void *ptr) 
+#define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
+#define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
+
+static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	typedef struct serial_struct SS;
-	struct serial_struct32 *ss32 = ptr; 
-	int err = 0;
-	struct serial_struct ss; 
-	mm_segment_t oldseg = get_fs(); 
-	set_fs(KERNEL_DS);
-	if (cmd == TIOCSSERIAL) { 
-		err = -EFAULT;
-		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
-			goto out;
-		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
-			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
-		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
+	mm_segment_t 			old_fs 	= get_fs();
+	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
+	struct mtd_oob_buf		karg;
+	u32 tmp;
+	char *ptr;
+	int ret;
+
+	if (get_user(karg.start, &uarg->start) 		||
+	    get_user(karg.length, &uarg->length)	||
+	    get_user(tmp, &uarg->ptr))
+		return -EFAULT;
+
+	ptr = (char *)A(tmp);
+	if (0 >= karg.length) 
+		return -EINVAL;
+
+	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
+	if (NULL == karg.ptr)
+		return -ENOMEM;
+
+	if (copy_from_user(karg.ptr, ptr, karg.length)) {
+		kfree(karg.ptr);
+		return -EFAULT;
 	}
-	if (!err)
-		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
-	if (cmd == TIOCGSERIAL && err >= 0) { 
-		__u32 base;
-		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
-		    __copy_to_user(&ss32->iomem_reg_shift,
-				   &ss.iomem_reg_shift,
-				   sizeof(SS) - offsetof(SS, iomem_reg_shift)))
-			err = -EFAULT;
-		if (ss.iomem_base > (unsigned char *)0xffffffff)
-			base = -1; 
-		else
-			base = (unsigned long)ss.iomem_base;
-		err |= __put_user(base, &ss32->iomem_base); 		
-	} 
- out:
-	set_fs(oldseg);
-	return err;	
-}
 
+	set_fs(KERNEL_DS);
+	if (MEMREADOOB32 == cmd) 
+		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
+	else if (MEMWRITEOOB32 == cmd)
+		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
+	else
+		ret = -EINVAL;
+	set_fs(old_fs);
 
-#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
+	if (0 == ret && cmd == MEMREADOOB32) {
+		ret = copy_to_user(ptr, karg.ptr, karg.length);
+		ret |= put_user(karg.start, &uarg->start);
+		ret |= put_user(karg.length, &uarg->length);
+	}
 
-static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
-{ 
-	if (cmd == REISERFS_IOC_UNPACK32) 
-		cmd = REISERFS_IOC_UNPACK; 
-	return sys_ioctl(fd,cmd,ptr); 
-} 
+	kfree(karg.ptr);
+	return ((0 == ret) ? 0 : -EFAULT);
+}	
 
-struct dirent32 {
-	unsigned int		d_ino;
-	__kernel_off_t32	d_off;
-	unsigned short	d_reclen;
-	char		d_name[256]; /* We must not include limits.h! */
-};
+/* /proc/mtrr ioctls */
 
-#define	VFAT_IOCTL_READDIR_BOTH32	_IOR('r', 1, struct dirent32 [2])
-#define	VFAT_IOCTL_READDIR_SHORT32	_IOR('r', 2, struct dirent32 [2])
 
-static int put_dirent32(struct dirent *src, struct dirent32 *dst)
-{ 
-	int ret;
-	ret = put_user(src->d_ino, &dst->d_ino); 
-	ret |= __put_user(src->d_off, &dst->d_off); 
-	ret |= __put_user(src->d_reclen, &dst->d_reclen); 
-	if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen))
-		ret |= -EFAULT;
-	return ret;
-} 
+struct mtrr_sentry32
+{
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
 
-static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
+struct mtrr_gentry32
 {
-	int ret;
-	mm_segment_t oldfs = get_fs();
-	struct dirent d[2]; 
+    unsigned int regnum;   /*  Register number  */
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
 
-	set_fs(KERNEL_DS); 
-	ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
-	set_fs(oldfs); 
-	if (!ret) { 
-		ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); 
-		ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); 
-	} 
-	return ret;
-}
+#define	MTRR_IOCTL_BASE	'M'
 
-#define RTC_IRQP_READ32	_IOR('p', 0x0b, unsigned int)	 /* Read IRQ rate   */
-#define RTC_IRQP_SET32	_IOW('p', 0x0c, unsigned int)	 /* Set IRQ rate    */
-#define RTC_EPOCH_READ32	_IOR('p', 0x0d, unsigned)	 /* Read epoch      */
-#define RTC_EPOCH_SET32		_IOW('p', 0x0e, unsigned)	 /* Set epoch       */
+#define MTRRIOC32_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry32)
+#define MTRRIOC32_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry32)
+#define MTRRIOC32_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry32)
+#define MTRRIOC32_ADD_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  5, struct mtrr_sentry32)
+#define MTRRIOC32_SET_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  6, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  7, struct mtrr_sentry32)
+#define MTRRIOC32_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry32)
 
-static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) 
-{
-	unsigned long val;
+
+static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{ 
+	struct mtrr_gentry g;
+	struct mtrr_sentry s;
+	int get = 0, err = 0; 
+	struct mtrr_gentry32 *g32 = (struct mtrr_gentry32 *)arg; 
 	mm_segment_t oldfs = get_fs(); 
-	int ret; 
-	
-	switch (cmd) { 
-	case RTC_IRQP_READ32: 
-	set_fs(KERNEL_DS);
-		ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); 
-		set_fs(oldfs); 
-		if (!ret)
-			ret = put_user(val, (unsigned int*) arg); 
-	return ret; 
 
-	case RTC_IRQP_SET32: 
-		cmd = RTC_EPOCH_SET; 
-		break; 
+	switch (cmd) { 
+#define SET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; break 
+#define GET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; get=1; break
+		SET(ADD);
+		SET(SET); 
+		SET(DEL);
+		GET(GET); 
+		SET(KILL);
+		SET(ADD_PAGE); 
+		SET(SET_PAGE); 
+		SET(DEL_PAGE); 
+		GET(GET_PAGE); 
+		SET(KILL_PAGE); 
+	} 
+	
+	if (get) { 
+		err = get_user(g.regnum, &g32->regnum);
+		err |= get_user(g.base, &g32->base);
+		err |= get_user(g.size, &g32->size);
+		err |= get_user(g.type, &g32->type); 
 
-	case RTC_EPOCH_READ32:
-		set_fs(KERNEL_DS); 
-		ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); 
-		set_fs(oldfs); 
-		if (!ret)
-			ret = put_user(val, (unsigned int*) arg); 
-		return ret; 
+		arg = (unsigned long)&g; 
+	} else { 
+		struct mtrr_sentry32 *s32 = (struct mtrr_sentry32 *)arg;
+		err = get_user(s.base, &s32->base);
+		err |= get_user(s.size, &s32->size);
+		err |= get_user(s.type, &s32->type);
 
-	case RTC_EPOCH_SET32:
-		cmd = RTC_EPOCH_SET; 
-		break; 
+		arg = (unsigned long)&s; 
 	} 
-	return sys_ioctl(fd,cmd,arg); 
+	if (err) return err;
+	
+	set_fs(KERNEL_DS); 
+	err = sys_ioctl(fd, cmd, arg); 
+	set_fs(oldfs); 
+		
+	if (!err && get) { 
+		err = put_user(g.base, &g32->base);
+		err |= put_user(g.size, &g32->size);
+		err |= put_user(g.regnum, &g32->regnum);
+		err |= put_user(g.type, &g32->type); 
+	} 
+	return err;
 } 
 
 struct ioctl_trans {
@@ -3237,7 +3608,7 @@
 };
 
 #define REF_SYMBOL(handler) if (0) (void)handler;
-#define HANDLE_IOCTL2(cmd,handler) REF_SYMBOL(handler);  asm volatile(".quad %c0, " #handler ",0"::"i" (cmd)); 
+#define HANDLE_IOCTL2(cmd,handler) REF_SYMBOL(handler);  asm volatile(".quad %P0, " #handler ",0"::"i" (cmd)); 
 #define HANDLE_IOCTL(cmd,handler) HANDLE_IOCTL2(cmd,handler)
 #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
 #define IOCTL_TABLE_START void ioctl_dummy(void) { asm volatile("\nioctl_start:\n\t" );
@@ -3260,7 +3631,6 @@
 COMPATIBLE_IOCTL(TCSETSW)
 COMPATIBLE_IOCTL(TCSETSF)
 COMPATIBLE_IOCTL(TIOCLINUX)
-HANDLE_IOCTL(TIOCGDEV, tiocgdev)
 /* Little t */
 COMPATIBLE_IOCTL(TIOCGETD)
 COMPATIBLE_IOCTL(TIOCSETD)
@@ -3285,6 +3655,7 @@
 COMPATIBLE_IOCTL(TIOCGPTN)
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
@@ -3344,7 +3715,6 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -3365,7 +3735,6 @@
 COMPATIBLE_IOCTL(STOP_ARRAY)
 COMPATIBLE_IOCTL(STOP_ARRAY_RO)
 COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
@@ -3387,6 +3756,7 @@
 COMPATIBLE_IOCTL(KDSKBSENT)
 COMPATIBLE_IOCTL(KDGKBDIACR)
 COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDKBDREP)
 COMPATIBLE_IOCTL(KDGKBLED)
 COMPATIBLE_IOCTL(KDSKBLED)
 COMPATIBLE_IOCTL(KDGETLED)
@@ -3406,6 +3776,14 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM)
+COMPATIBLE_IOCTL(TUNSETDEBUG)
+COMPATIBLE_IOCTL(TUNSETIFF)
+COMPATIBLE_IOCTL(TUNSETPERSIST)
+COMPATIBLE_IOCTL(TUNSETOWNER)
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE)
 COMPATIBLE_IOCTL(VT_GETMODE)
@@ -3419,7 +3797,8 @@
 COMPATIBLE_IOCTL(VT_RESIZEX)
 COMPATIBLE_IOCTL(VT_LOCKSWITCH)
 COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v, the video4linux ioctls */
+/* Little v */
+/* Little v, the video4linux ioctls (conflict?) */
 COMPATIBLE_IOCTL(VIDIOCGCAP)
 COMPATIBLE_IOCTL(VIDIOCGCHAN)
 COMPATIBLE_IOCTL(VIDIOCSCHAN)
@@ -3459,11 +3838,6 @@
 COMPATIBLE_IOCTL(RTC_SET_TIME)
 COMPATIBLE_IOCTL(RTC_WKALM_SET)
 COMPATIBLE_IOCTL(RTC_WKALM_RD)
-HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
@@ -3485,6 +3859,11 @@
 COMPATIBLE_IOCTL(SIOCDRARP)
 COMPATIBLE_IOCTL(SIOCADDDLCI)
 COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@ -3506,7 +3885,6 @@
 COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
 COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
 COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_IO)
 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
 COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
@@ -3524,10 +3902,14 @@
 COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
 COMPATIBLE_IOCTL(PPPIOCGNPMODE)
 COMPATIBLE_IOCTL(PPPIOCSNPMODE)
 COMPATIBLE_IOCTL(PPPIOCGDEBUG)
 COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
+/* PPPIOCGIDLE is translated */
 COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
 COMPATIBLE_IOCTL(PPPIOCATTACH)
 COMPATIBLE_IOCTL(PPPIOCDETACH)
@@ -3537,8 +3919,10 @@
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 /* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD);
-COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
 /* CDROM stuff */
 COMPATIBLE_IOCTL(CDROMPAUSE)
 COMPATIBLE_IOCTL(CDROMRESUME)
@@ -3570,9 +3954,15 @@
 COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
 COMPATIBLE_IOCTL(CDROM_DEBUG)
 COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
 /* Big L */
 COMPATIBLE_IOCTL(LOOP_SET_FD)
 COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big A */
+/* sparc only */
 /* Big Q for sound/OSS */
 COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
 COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
@@ -3731,6 +4121,7 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -3776,64 +4167,79 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
-COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
-#endif /* DRM */
 #ifdef CONFIG_AUTOFS_FS
-COMPATIBLE_IOCTL(AUTOFS_IOC_READY);
-COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL);
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC);
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER);
-COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT);
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE);
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 #endif
 #ifdef CONFIG_RTC
-COMPATIBLE_IOCTL(RTC_AIE_ON);
-COMPATIBLE_IOCTL(RTC_AIE_OFF);
-COMPATIBLE_IOCTL(RTC_UIE_ON);
-COMPATIBLE_IOCTL(RTC_UIE_OFF);
-COMPATIBLE_IOCTL(RTC_PIE_ON);
-COMPATIBLE_IOCTL(RTC_PIE_OFF);
-COMPATIBLE_IOCTL(RTC_WIE_ON);
-COMPATIBLE_IOCTL(RTC_WIE_OFF);
-COMPATIBLE_IOCTL(RTC_ALM_SET);
-COMPATIBLE_IOCTL(RTC_ALM_READ);
-COMPATIBLE_IOCTL(RTC_RD_TIME);
-COMPATIBLE_IOCTL(RTC_SET_TIME);
-COMPATIBLE_IOCTL(RTC_IRQP_READ);
-COMPATIBLE_IOCTL(RTC_IRQP_SET);
-COMPATIBLE_IOCTL(RTC_EPOCH_READ);
-COMPATIBLE_IOCTL(RTC_EPOCH_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_RD);
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
 #endif
-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
-/* serial driver */ 
-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl);
-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl);
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
+/* Big W */
+/* WIOC_GETSUPPORT not yet implemented -E */
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETTEMP)
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
+#if 0 /* sparc only ? */
+COMPATIBLE_IOCTL(WIOCSTART)
+COMPATIBLE_IOCTL(WIOCSTOP)
+COMPATIBLE_IOCTL(WIOCGSTAT)
+#endif
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT)
+COMPATIBLE_IOCTL(RNDADDTOENTCNT)
+COMPATIBLE_IOCTL(RNDGETPOOL)
+COMPATIBLE_IOCTL(RNDADDENTROPY)
+COMPATIBLE_IOCTL(RNDZAPENTCNT)
+COMPATIBLE_IOCTL(RNDCLEARPOOL)
+/* Bluetooth ioctls */
+COMPATIBLE_IOCTL(HCIDEVUP)
+COMPATIBLE_IOCTL(HCIDEVDOWN)
+COMPATIBLE_IOCTL(HCIDEVRESET)
+COMPATIBLE_IOCTL(HCIDEVRESTAT)
+COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
@@ -3841,8 +4247,46 @@
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
 COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+COMPATIBLE_IOCTL(0x4B50);   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51);   /* KDSHWCLK - not in the kernel, but don't complain */
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
+/* NBD */
+COMPATIBLE_IOCTL(NBD_SET_SOCK)
+COMPATIBLE_IOCTL(NBD_SET_BLKSIZE)
+COMPATIBLE_IOCTL(NBD_SET_SIZE)
+COMPATIBLE_IOCTL(NBD_DO_IT)
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
+COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
+COMPATIBLE_IOCTL(NBD_DISCONNECT)
 /* And these ioctls need translation */
+HANDLE_IOCTL(TIOCGDEV, tiocgdev)
+HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
+HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
+#ifdef CONFIG_NET
 HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+#endif
 HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
 HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
@@ -3869,14 +4313,26 @@
 HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
+HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl)
 HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
 HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* realtime device */
+HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
+HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
 /* Raw devices */
 HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
@@ -3888,6 +4344,7 @@
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
 HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
 HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
@@ -3907,8 +4364,11 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
@@ -3982,20 +4442,37 @@
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
-HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
-HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
-HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
-#endif /* DRM */
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
+/* VFAT */
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
+/* mtrr */
+HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_ADD_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_PAGE_ENTRY, mtrr_ioctl32)
 IOCTL_TABLE_END
 
 #define IOCTL_HASHSIZE 256
@@ -4099,7 +4576,7 @@
 /* Problem: 
    This function cannot unregister duplicate ioctls, because they are not
    unique.
-   When they happen we need to extend the prototype to pass handler too. */
+   When they happen we need to extend the prototype to pass the handler too. */
 
 int unregister_ioctl32_conversion(unsigned int cmd)
 {
@@ -4150,10 +4627,10 @@
 EXPORT_SYMBOL(register_ioctl32_conversion); 
 EXPORT_SYMBOL(unregister_ioctl32_conversion); 
 
-asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct file * filp;
-	int error = -EBADF;
+	long error = -EBADF;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
 	struct ioctl_trans *t;
 
@@ -4173,13 +4650,35 @@
 	if (t) {
 		handler = t->handler;
 		error = handler(fd, cmd, arg, filp);
+	} else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
+		error = siocdevprivate_ioctl(fd, cmd, arg);
 	} else {
-		static int count = 0;
-		if (++count <= 50)
-			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
-			       "cmd(%08x) arg(%08x)\n",
+		static int count;
+		if (++count <= 50) { 
+			char buf[10];
+			char *path = (char *)__get_free_page(GFP_KERNEL), *fn = "?"; 
+
+			/* find the name of the device. */
+			if (path) {
+				struct file *f = fget(fd); 
+				if (f) {
+					fn = d_path(f->f_dentry, f->f_vfsmnt, 
+						    path, PAGE_SIZE);
+					fput(f);
+				}
+			}
+
+			sprintf(buf,"'%c'", (cmd>>24) & 0x3f); 
+			if (!isprint(buf[1]))
+			    sprintf(buf, "%02x", buf[1]);
+			printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+			       "cmd(%08x){%s} arg(%08x) on %s\n",
 			       current->comm, current->pid,
-			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+			       (int)fd, (unsigned int)cmd, buf, (unsigned int)arg,
+			       fn);
+			if (path) 
+				free_page((unsigned long)path); 
+		}
 		error = -EINVAL;
 	}
 out:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_signal.c linux-2.4.21-rc3/arch/x86_64/ia32/ia32_signal.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_signal.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ia32_signal.c	2003-05-22 22:06:42.000000000 +0000
@@ -7,7 +7,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
  * 
- *  $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
+ *  $Id: ia32_signal.c,v 1.31 2003/03/12 08:22:12 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -33,6 +33,7 @@
 #include <asm/fpu32.h>
 
 #define ptr_to_u32(x) ((u32)(u64)(x))	/* avoid gcc warning */ 
+#define u32_to_ptr(x) ((void *)(u64)(x))
 
 #define DEBUG_SIG 0
 
@@ -45,9 +46,16 @@
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
+	if (from->si_code < 0) { 
+		/* the only field that's different is the alignment
+		   of the pointer in sigval_t. Move that 4 bytes down including
+		   padding. */
+		memmove(&((siginfo_t32 *)&from)->si_int,
+			&from->si_int, 
+			sizeof(siginfo_t) - offsetof(siginfo_t, si_int));
+		/* last 4 bytes stay the same */
+		return __copy_to_user(to, from, sizeof(siginfo_t32));
+	} else {
 		int err;
 
 		/* If you change siginfo_t structure, please be sure
@@ -57,7 +65,7 @@
 		   3 ints plus the relevant union member.  */
 		err = __put_user(from->si_signo, &to->si_signo);
 		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
+		err |= __put_user(from->si_code, &to->si_code);
 		/* First 32bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		switch (from->si_code >> 16) {
@@ -76,7 +84,7 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
 {
 	sigset_t saveset;
@@ -97,27 +105,32 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
 				  struct pt_regs regs)
 {
 	stack_t uss,uoss; 
 	int ret;
 	mm_segment_t seg; 
+	if (uss_ptr) {
+		u32 val32;
+		memset(&uss, 0, sizeof(stack_t));
 	if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
-	    __get_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
-	    __get_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
-	    __get_user((u32)uss.ss_size, &uss_ptr->ss_size))
+		    __get_user(val32, &uss_ptr->ss_sp) ||
+		    __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
+		    __get_user(uss.ss_size, &uss_ptr->ss_size))
 		return -EFAULT;
+		uss.ss_sp = u32_to_ptr(val32);	
+	}
 	seg = get_fs(); 
 	set_fs(KERNEL_DS); 
-	ret = do_sigaltstack(&uss, &uoss, regs.rsp);
+	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
 	set_fs(seg); 
 	if (ret >= 0 && uoss_ptr)  {
-		if (!access_ok(VERIFY_WRITE,uss_ptr,sizeof(stack_ia32_t)) ||
-		    __put_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
-		    __put_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
-		    __put_user((u32)uss.ss_size, &uss_ptr->ss_size))
+		if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
+		    __put_user(ptr_to_u32(uoss.ss_sp), &uoss_ptr->ss_sp) ||
+		    __put_user((u32)uoss.ss_flags, &uoss_ptr->ss_flags) ||
+		    __put_user((u32)uoss.ss_size, &uoss_ptr->ss_size))
 			ret = -EFAULT;
 	} 	
 	return ret;	
@@ -173,31 +186,29 @@
 	  if (pre != cur) loadsegment(seg,pre); }
 
 	/* Reload fs and gs if they have changed in the signal handler.
-	   This does not handle long fs/gs base changes in the handler, but 
-	   does not clobber them at least in the normal case. */ 
+	   This does not handle long gs base changes in the handler, but 
+	   does not clobber it at least in the normal case. */ 
 	
 	{
 		unsigned short gs; 
+		unsigned int curgs;
 		err |= __get_user(gs, &sc->gs);
-		load_gs_index(gs); 
+		asm volatile("movl %%gs,%0" : "=r" (curgs)); 		
+		if (gs != curgs) 
+			load_gs_index(gs | 3); 
 	} 
-	RELOAD_SEG(fs,0);
-	RELOAD_SEG(ds,0);
-	RELOAD_SEG(es,0);
+	RELOAD_SEG(fs,3);
+	RELOAD_SEG(ds,3);
+	RELOAD_SEG(es,3);
 
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	/* Don't touch extended registers */ 
 
-#if 1	/* not ready for this yet */ 
 	err |= __get_user(regs->cs, &sc->cs); 
-	regs->cs |= 2; 	
+	regs->cs |= 3; 	
 	err |= __get_user(regs->ss, &sc->ss); 
-	regs->ss |= 2; 
-#else
-	regs->cs = __USER32_CS;
-	regs->ss = __USER32_DS; 
-#endif
+	regs->ss |= 3; 
 	
 	{
 		unsigned int tmpflags;
@@ -213,7 +224,7 @@
 		buf = (struct _fpstate_ia32 *) (u64)tmp;
 		if (buf) {
 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
+				return 1;
 			err |= restore_i387_ia32(current, buf, 0);
 		}
 	}
@@ -224,12 +235,9 @@
 		*peax = tmp;
 	}
 	return err;
-
-badframe:
-	return 1;
 }
 
-asmlinkage int sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs regs)
 {
 	struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
 	sigset_t set;
@@ -258,7 +266,7 @@
 	return 0;
 }	
 
-asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
 	sigset_t set;
@@ -336,8 +344,12 @@
 	tmp = save_i387_ia32(current, fpstate, regs, 0);
 	if (tmp < 0)
 	  err = -EFAULT;
-	else
+	else { 
+		/* trigger finit in signal handler */
+		current->used_math = 0;
+		stts();
 	  err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
+	} 
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32entry.S linux-2.4.21-rc3/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.20/arch/x86_64/ia32/ia32entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ia32entry.S	2003-05-22 22:06:38.000000000 +0000
@@ -3,7 +3,7 @@
  * 		
  * Copyright 2000,2001 Andi Kleen, SuSE Labs.
  * 
- * $Id: ia32entry.S,v 1.36 2002/09/12 12:55:05 ak Exp $ 		
+ * $Id: ia32entry.S,v 1.40 2003/04/03 09:46:54 ak Exp $ 		
  */		 
 
 #include <asm/calling.h>
@@ -86,6 +86,7 @@
 		
 ia32_badsys:
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	jmp int_ret_from_sys_call
 
 ni_syscall:
@@ -133,7 +134,7 @@
 	.quad stub32_fork
 	.quad sys_read
 	.quad sys_write
-	.quad sys_open		/* 5 */
+	.quad sys32_open		/* 5 */
 	.quad sys_close
 	.quad sys32_waitpid
 	.quad sys_creat
@@ -176,7 +177,7 @@
 	.quad sys_brk		/* 45 */
 	.quad sys_setgid16
 	.quad sys_getgid16
-	.quad ni_syscall	/* signal */
+	.quad sys_signal
 	.quad sys_geteuid16
 	.quad sys_getegid16	/* 50 */
 	.quad sys_acct
@@ -241,7 +242,7 @@
 	.quad stub32_iopl		/* 110 */
 	.quad sys_vhangup
 	.quad ni_syscall	/* old "idle" system call */
-	.quad ni_syscall	/* vm86old */ 
+	.quad sys32_vm86_warning	/* vm86old */ 
 	.quad sys32_wait4
 	.quad sys_swapoff		/* 115 */
 	.quad sys32_sysinfo
@@ -251,7 +252,7 @@
 	.quad stub32_clone		/* 120 */
 	.quad sys_setdomainname
 	.quad sys_uname
-	.quad sys_modify_ldt
+	.quad sys32_modify_ldt
 	.quad sys32_adjtimex
 	.quad sys32_mprotect		/* 125 */
 	.quad sys32_sigprocmask
@@ -294,7 +295,7 @@
 	.quad sys_mremap
 	.quad sys_setresuid16
 	.quad sys_getresuid16	/* 165 */
-	.quad ni_syscall	/* vm86 */ 
+	.quad sys32_vm86_warning	/* vm86 */ 
 	.quad quiet_ni_syscall	/* query_module */
 	.quad sys_poll
 	.quad sys32_nfsservctl
@@ -354,34 +355,23 @@
 	.quad sys_ni_syscall    /* security */
 	.quad sys_gettid	
 	.quad sys_readahead	/* 225 */ 
-	.quad sys_setxattr
-	.quad sys_lsetxattr
-	.quad sys_fsetxattr
-	.quad sys_getxattr
-	.quad sys_lgetxattr	/* 230 */
-	.quad sys_fgetxattr
-	.quad sys_listxattr
-	.quad sys_llistxattr
-	.quad sys_flistxattr
-	.quad sys_removexattr	/* 235 */
-	.quad sys_lremovexattr
-	.quad sys_fremovexattr
-	.quad sys_tkill		/* 238 */ 
-	.quad sys_ni_syscall	/* sendfile64 */
-	.quad sys_ni_syscall	/* futex */
-	.quad sys_ni_syscall	/* sched_setaffinity */
-	.quad sys_ni_syscall	/* sched_getaffinity */
-	.quad sys_ni_syscall	/* set_threadarea */
-	.quad sys_ni_syscall	/* get_threadarea */
-	.quad sys_ni_syscall	/* io_setup */
-	.quad sys_ni_syscall	/* io_destroy */
-	.quad sys_ni_syscall	/* io_getevents */
-	.quad sys_ni_syscall	/* io_submit */
-	.quad sys_ni_syscall	/* io_cancel */
-	.quad sys_ni_syscall	/* alloc_hugepages */
-	.quad sys_ni_syscall	/* free_hugepages */
-	.quad sys_ni_syscall	/* exit_group */
-
+	.quad quiet_ni_syscall  /* xattr syscalls 226-237 */
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall  /* 230 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* 235 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* fremovexattr - 237 */
+	.quad sys_tkill
+	.quad sys_sendfile64
+	.quad quiet_ni_syscall  /* futex */
+	.quad quiet_ni_syscall  /* sched_setaffinity */
+	.quad quiet_ni_syscall  /* sched_getaffinity */	
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
 		.quad ni_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ipc32.c linux-2.4.21-rc3/arch/x86_64/ia32/ipc32.c
--- linux-2.4.20/arch/x86_64/ia32/ipc32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ipc32.c	2003-05-22 22:06:47.000000000 +0000
@@ -185,12 +185,58 @@
 	}
 }
 
+static int put_semid(void *user_semid, struct semid64_ds *s, int version)
+{
+	int err2;
+	switch (version) { 
+	case IPC_64: { 
+		struct semid64_ds32 *usp64 = (struct semid64_ds32 *) user_semid;
+		
+		if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
+			err2 = -EFAULT;
+			break;
+		} 
+		err2 = __put_user(s->sem_perm.key, &usp64->sem_perm.key);
+		err2 |= __put_user(s->sem_perm.uid, &usp64->sem_perm.uid);
+		err2 |= __put_user(s->sem_perm.gid, &usp64->sem_perm.gid);
+		err2 |= __put_user(s->sem_perm.cuid, &usp64->sem_perm.cuid);
+		err2 |= __put_user(s->sem_perm.cgid, &usp64->sem_perm.cgid);
+		err2 |= __put_user(s->sem_perm.mode, &usp64->sem_perm.mode);
+		err2 |= __put_user(s->sem_perm.seq, &usp64->sem_perm.seq);
+		err2 |= __put_user(s->sem_otime, &usp64->sem_otime);
+		err2 |= __put_user(s->sem_ctime, &usp64->sem_ctime);
+		err2 |= __put_user(s->sem_nsems, &usp64->sem_nsems);
+		break;
+	}
+	default: {
+		struct semid_ds32 *usp32 = (struct semid_ds32 *) user_semid;
+		
+		if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
+			err2 = -EFAULT;
+			break;
+		} 
+		err2 = __put_user(s->sem_perm.key, &usp32->sem_perm.key);
+		err2 |= __put_user(s->sem_perm.uid, &usp32->sem_perm.uid);
+		err2 |= __put_user(s->sem_perm.gid, &usp32->sem_perm.gid);
+		err2 |= __put_user(s->sem_perm.cuid, &usp32->sem_perm.cuid);
+		err2 |= __put_user(s->sem_perm.cgid, &usp32->sem_perm.cgid);
+		err2 |= __put_user(s->sem_perm.mode, &usp32->sem_perm.mode);
+		err2 |= __put_user(s->sem_perm.seq, &usp32->sem_perm.seq);
+		err2 |= __put_user(s->sem_otime, &usp32->sem_otime);
+		err2 |= __put_user(s->sem_ctime, &usp32->sem_ctime);
+		err2 |= __put_user(s->sem_nsems, &usp32->sem_nsems);
+		break;
+	}
+	}
+	return err2;
+}
+
 static int
 semctl32 (int first, int second, int third, void *uptr)
 {
 	union semun fourth;
 	u32 pad;
-	int err = 0, err2;
+	int err = 0;
 	struct semid64_ds s;
 	mm_segment_t old_fs;
 	int version = ipc_parse_version32(&third);
@@ -223,46 +269,15 @@
 		fourth.__pad = &s;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_semctl(first, second|IPC_64, third, fourth);
+		err = sys_semctl(first, second, third|IPC_64, fourth);
 		set_fs(old_fs);
 
-		if (version == IPC_64) {
-			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
-
-			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
-		} else {
-			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+		if (!err) 
+			err = put_semid((void *)A(pad), &s, version);
 
-			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
-		}
-		if (err2)
-		    err = -EFAULT;
+		break;
+	default:
+		err = -EINVAL;
 		break;
 	}
 	return err;
@@ -284,7 +299,7 @@
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= copy_from_user(p->mtext, &up->mtext, second);
+	err |= (copy_from_user(p->mtext, &up->mtext, second) ? -EFAULT : 0);
 	if (err)
 		goto out;
 	old_fs = get_fs();
@@ -604,6 +619,10 @@
 			err = -EFAULT;
 		break;
 
+	default:
+		err = -EINVAL;
+		break;
+
 	}
 	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ptrace32.c linux-2.4.21-rc3/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.20/arch/x86_64/ia32/ptrace32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/ptrace32.c	2003-05-22 22:06:52.000000000 +0000
@@ -8,7 +8,7 @@
  * This allows to access 64bit processes too; but there is no way to see the extended 
  * register contents.
  *
- * $Id: ptrace32.c,v 1.13 2002/07/18 13:44:12 ak Exp $
+ * $Id: ptrace32.c,v 1.17 2003/03/24 09:25:15 ak Exp $
  */ 
 
 #include <linux/kernel.h>
@@ -73,8 +73,16 @@
 		stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; 
 		break;
 
-	case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[6]):
-		child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4] = val; 
+	case offsetof(struct user32, u_debugreg[4]): 
+	case offsetof(struct user32, u_debugreg[5]):
+		return -EIO;
+
+	case offsetof(struct user32, u_debugreg[0]) ...
+	     offsetof(struct user32, u_debugreg[3]):
+	case offsetof(struct user32, u_debugreg[6]):
+		child->thread.debugreg
+			[(regno-offsetof(struct user32, u_debugreg[0]))/4] 
+			= val; 
 		break; 
 
 	case offsetof(struct user32, u_debugreg[7]):
@@ -165,18 +173,15 @@
 		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (child) { 
-		*err = -ESRCH;
-		if (!(child->ptrace & PT_PTRACED))
+		*err = -EPERM;
+		if (pid == 1) 
 			goto out;
-		if (child->state != TASK_STOPPED) {
-			if (request != PTRACE_KILL)
+		*err = ptrace_check_attach(child, request == PTRACE_KILL); 
+		if (*err < 0) 
 				goto out;
-		}
-		if (child->p_pptr != current)
-			goto out;
-
 		return child; 
 	} 
+
  out:
 	free_task_struct(child);
 	return NULL; 
@@ -277,7 +282,6 @@
 			ret = -EIO;
 			break;
 		}
-		empty_fpu(child); 
 		ret = 0; 
 		for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
 			ret |= __get_user(tmp, (u32 *) (unsigned long) data);
@@ -287,33 +291,47 @@
 		break;
 	}
 
-	case PTRACE_SETFPREGS:
-		empty_fpu(child); 
+	case PTRACE_GETFPREGS:
+		ret = -EIO; 
+		if (!access_ok(VERIFY_READ, (void *)(u64)data, 
+			       sizeof(struct user_i387_struct)))
+			break;
 		save_i387_ia32(child, (void *)(u64)data, childregs, 1);
 		ret = 0; 
 		break;
 
-	case PTRACE_GETFPREGS:
-		empty_fpu(child); 
-		restore_i387_ia32(child, (void *)(u64)data, 1);
+	case PTRACE_SETFPREGS:
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, (void *)(u64)data, 
+			       sizeof(struct user_i387_struct)))
+			break;
 		ret = 0;
+		/* don't check EFAULT to be bug-to-bug compatible to i386 */
+		restore_i387_ia32(child, (void *)(u64)data, 1);
 		break;
 
 	case PTRACE_GETFPXREGS: { 
 		struct user32_fxsr_struct *u = (void *)(u64)data; 
-		empty_fpu(child); 
-		ret = copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u));
-		ret |= __put_user(childregs->cs, &u->fcs);
-		ret |= __put_user(child->thread.ds, &u->fos); 
-		if (ret) 
+		init_fpu(child); 
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+			break;
 			ret = -EFAULT;
+		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
+			break;
+		ret = __put_user(childregs->cs, &u->fcs);
+		ret |= __put_user(child->thread.ds, &u->fos); 
 		break; 
 	} 
 	case PTRACE_SETFPXREGS: { 
 		struct user32_fxsr_struct *u = (void *)(u64)data; 
-		empty_fpu(child); 
-		/* no error checking to be bug to bug compatible with i386 */ 
-		copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
+		unlazy_fpu(child);
+		ret = -EIO;
+		if (!access_ok(VERIFY_READ, u, sizeof(*u)))
+			break;
+		/* no checking to be bug-to-bug compatible with i386 */
+		__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
+		child->used_math = 1;
 	        child->thread.i387.fxsave.mxcsr &= 0xffbf;
 		ret = 0; 
 		break; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/socket32.c linux-2.4.21-rc3/arch/x86_64/ia32/socket32.c
--- linux-2.4.20/arch/x86_64/ia32/socket32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/socket32.c	2003-05-22 22:06:28.000000000 +0000
@@ -362,7 +362,7 @@
 	kmsg->msg_control = (void *) orig_cmsg_uptr;
 }
 
-asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -407,7 +407,7 @@
 	return err;
 }
 
-asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
 {
 	struct iovec iovstack[UIO_FASTIOV];
 	struct msghdr kern_msg;
@@ -561,7 +561,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+asmlinkage long sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
 	if (optname == SO_ATTACH_FILTER)
@@ -664,7 +664,7 @@
 			ret = sys_shutdown(a0,a1);
 			break;
 		case SYS_SETSOCKOPT:
-			ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]),
+			ret = sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]),
 					      a[4]);
 			break;
 		case SYS_GETSOCKOPT:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/sys_ia32.c linux-2.4.21-rc3/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.20/arch/x86_64/ia32/sys_ia32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/ia32/sys_ia32.c	2003-05-22 22:06:51.000000000 +0000
@@ -9,13 +9,14 @@
  * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 2000		Hewlett-Packard Co.
  * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs (x86-64 port) 
+ * Copyright (C) 2000,2001,2002	Andi Kleen, SuSE Labs (x86-64 port) 
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment. In 2.5 most of this should be moved to a generic directory. 
  *
  * This file assumes that there is a hole at the end of user address space.
- * $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $
+ *
+ * $Id: sys_ia32.c,v 1.54 2003/03/24 09:28:26 ak Exp $
  */
 
 #include <linux/config.h>
@@ -61,6 +62,7 @@
 #include <asm/semaphore.h>
 #include <asm/ipc.h>
 #include <asm/atomic.h>
+#include <asm/ldt.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
@@ -225,7 +227,33 @@
 	return ret;
 }
 
+/* Don't set O_LARGEFILE implicitely. */
+asmlinkage long sys32_open(const char * filename, int flags, int mode)
+{
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file *f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 /*
  * Linux/i386 didn't use to be able to handle more than
@@ -242,7 +270,7 @@
 	unsigned int offset;
 };
 
-asmlinkage __u32
+asmlinkage long
 sys32_mmap(struct mmap_arg_struct *arg)
 {
 	struct mmap_arg_struct a;
@@ -261,22 +289,16 @@
 		if (!file)
 			return -EBADF;
 	}
+	
 	if (a.prot & PROT_READ) 
 		a.prot |= PROT_EXEC; 
 
-	a.flags |= MAP_32BIT;
-
 	mm = current->mm; 
 	down_write(&mm->mmap_sem); 
 	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
 	if (file)
 		fput(file);
 
-	/* Should not happen */
-	if (retval >= 0xFFFFFFFF && (long)retval > 0) { 
-		do_munmap(mm, retval, a.len); 
-		retval = -ENOMEM; 
-	} 
 	up_write(&mm->mmap_sem); 
 
 	return retval;
@@ -284,7 +306,7 @@
 
 extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
 
-asmlinkage int sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+asmlinkage long sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
 	if (prot & PROT_READ) 
 		prot |= PROT_EXEC; 
@@ -503,7 +525,7 @@
     struct timeval32 it_value;
 };
 
-static inline long
+static long
 get_tv32(struct timeval *o, struct timeval32 *i)
 {
 	int err = -EFAULT; 
@@ -514,7 +536,7 @@
 	return err; 
 }
 
-static inline long
+static long
 put_tv32(struct timeval32 *o, struct timeval *i)
 {
 	int err = -EFAULT;
@@ -525,7 +547,7 @@
 	return err; 
 }
 
-static inline long
+static long
 get_it32(struct itimerval *o, struct itimerval32 *i)
 {
 	int err = -EFAULT; 
@@ -538,7 +560,7 @@
 	return err;
 }
 
-static inline long
+static long
 put_it32(struct itimerval32 *o, struct itimerval *i)
 {
 	int err = -EFAULT;
@@ -589,7 +611,8 @@
 	return 0;
 
 }
-asmlinkage unsigned long 
+
+asmlinkage long 
 sys32_alarm(unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
@@ -912,21 +935,23 @@
 asmlinkage long
 sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
 {
-	struct timespec t;
+	struct timespec t, tout;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 	
+	if (rqtp) { 
 	if (verify_area(VERIFY_READ, rqtp, sizeof(struct timespec32)) ||
 	    __get_user (t.tv_sec, &rqtp->tv_sec) ||
 	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
+	}
 	set_fs (KERNEL_DS);
-	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+	ret = sys_nanosleep(rqtp ? &t : NULL, rmtp ? &tout : NULL);
 	set_fs (old_fs);
 	if (rmtp && ret == -EINTR) {
 		if (verify_area(VERIFY_WRITE, rmtp, sizeof(struct timespec32)) ||
-		    __put_user (t.tv_sec, &rmtp->tv_sec) ||
-	    	    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+		    __put_user (tout.tv_sec, &rmtp->tv_sec) ||
+	    	    __put_user (tout.tv_nsec, &rmtp->tv_nsec))
 			return -EFAULT;
 	}
 	return ret;
@@ -935,47 +960,66 @@
 asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
 asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
 
-struct iovec *
-get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
+static struct iovec *
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 *count, int type, int *errp)
 {
 	int i;
 	u32 buf, len;
 	struct iovec *ivp, *iov;
+	unsigned long totlen; 
 
 	/* Get the "struct iovec" from user memory */
 
-	if (!count)
+	*errp = 0; 
+	if (!*count)
 		return 0;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+	*errp = -EINVAL;
+	if (*count > UIO_MAXIOV)
 		return(struct iovec *)0;
-	if (count > UIO_MAXIOV)
+	*errp = -EFAULT;
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)**count))
 		return(struct iovec *)0;
-	if (count > UIO_FASTIOV) {
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+	if (*count > UIO_FASTIOV) {
+		*errp = -ENOMEM; 
+		iov = kmalloc(*count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
 			return((struct iovec *)0);
 	} else
 		iov = iov_buf;
 
 	ivp = iov;
-	for (i = 0; i < count; i++) {
-		if (__get_user(len, &iov32->iov_len) ||
-		    __get_user(buf, &iov32->iov_base)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
-		if (verify_area(type, (void *)A(buf), len)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
+	totlen = 0;
+	for (i = 0; i < *count; i++) {
+		*errp = __get_user(len, &iov32->iov_len) |
+		  	__get_user(buf, &iov32->iov_base);	
+		if (*errp)
+			goto error;
+		*errp = verify_area(type, (void *)A(buf), len);
+		if (*errp) { 
+			if (i > 0) { 
+				*count = i;
+				break;
+			}	
+			goto error;
 		}
+		/* SuS checks: */
+		*errp = -EINVAL; 
+		if ((int)len < 0)
+			goto error;
+		if ((totlen += len) >= 0x7fffffff)
+			goto error;			
 		ivp->iov_base = (void *)A(buf);
 		ivp->iov_len = (__kernel_size_t)len;
 		iov32++;
 		ivp++;
 	}
+	*errp = 0;
 	return(iov);
+
+error:
+	if (iov != iov_buf)
+		kfree(iov);
+	return NULL;
 }
 
 asmlinkage long
@@ -986,8 +1030,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, &count, VERIFY_WRITE, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_readv(fd, iov, count);
 	set_fs(old_fs);
@@ -1004,8 +1048,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, &count, VERIFY_READ, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_writev(fd, iov, count);
 	set_fs(old_fs);
@@ -1092,7 +1136,7 @@
 
 /*
  * sys_time() can be implemented in user-level using
- * sys_gettimeofday().  IA64 did this but i386 Linux did not
+ * sys_gettimeofday().  x86-64 did this but i386 Linux did not
  * so we have to implement this system call here.
  */
 asmlinkage long sys32_time(int * tloc)
@@ -1354,7 +1398,7 @@
 	return ret; 
 }
 
-int sys32_ni_syscall(int call)
+asmlinkage long sys32_ni_syscall(int call)
 { 
 	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,
 	       current->comm);
@@ -1572,8 +1616,8 @@
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
+		memcpy(&d->si_int, &s->si_int, 
+		       sizeof(siginfo_t) - offsetof(siginfo_t,si_int));
 	} else switch (s->si_signo) {
 	/* XXX: What about POSIX1.b timers */
 	case SIGCHLD:
@@ -1610,8 +1654,9 @@
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
+		memcpy(&d->si_int,
+		       &s->si_int,
+		       sizeof(siginfo_t) - offsetof(siginfo_t, si_int)); 
 	} else switch (s->si_signo) {
 	/* XXX: What about POSIX1.b timers */
 	case SIGCHLD:
@@ -1812,7 +1857,7 @@
 
 
 /* warning: next two assume little endian */ 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	    u32 poslo, u32 poshi)
 {
@@ -1820,7 +1865,7 @@
 			 ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	     u32 poslo, u32 poshi)
 {
@@ -1867,6 +1912,30 @@
 	return ret;
 }
 
+extern long sys_modify_ldt(int,void*,unsigned long);
+
+asmlinkage long sys32_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+        long ret;
+        if (func == 0x1 || func == 0x11) { 
+				struct modify_ldt_ldt_s info;
+                mm_segment_t old_fs = get_fs();
+                if (bytecount != sizeof(struct modify_ldt_ldt_s))
+                        return -EINVAL;
+                if (copy_from_user(&info, ptr, sizeof(struct modify_ldt_ldt_s)))
+                        return -EFAULT;
+                /* lm bit was undefined in the 32bit ABI and programs
+                   give it random values. Force it to zero here. */
+                info.lm = 0; 
+                set_fs(KERNEL_DS);
+                ret = sys_modify_ldt(func, &info, bytecount);
+                set_fs(old_fs);
+        }  else { 
+                ret = sys_modify_ldt(func, ptr, bytecount); 
+        }
+        return ret;
+}
+
 /* Handle adjtimex compatability. */
 
 struct timex32 {
@@ -1943,41 +2012,33 @@
 	return ret;
 }
 
-
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-	unsigned long addr, unsigned long len,
+asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	int error = -EBADF;
+	struct mm_struct *mm = current->mm;
+	unsigned long error;
 	struct file * file = NULL;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
-			goto out;
+			return -EBADF;
 	}
 
-	down_write(&current->mm->mmap_sem);
-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up_write(&current->mm->mmap_sem);
+	if (prot & PROT_READ)
+		prot |= PROT_EXEC;
+
+	down_write(&mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags|MAP_32BIT, pgoff);
+	up_write(&mm->mmap_sem);
 
 	if (file)
 		fput(file);
-out:
 	return error;
 }
 
-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long pgoff)
-{
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
-
 asmlinkage long sys32_olduname(struct oldold_utsname * name)
 {
 	int error;
@@ -2024,7 +2085,7 @@
 
 extern int sys_ustat(dev_t, struct ustat *);
 
-int sys32_ustat(dev_t dev, struct ustat32 *u32p)
+asmlinkage long sys32_ustat(dev_t dev, struct ustat32 *u32p)
 {
 	struct ustat u;
 	mm_segment_t seg;
@@ -2067,21 +2128,26 @@
 	return cnt; 
 } 
 
-int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
+asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
 { 
 	mm_segment_t oldseg; 
-	char **buf; 
-	int na,ne;
+	char **buf = NULL; 
+	int na = 0,ne = 0;
 	int ret;
-	unsigned sz; 
+	unsigned sz = 0; 
 	
+	if (argv) {
 	na = nargs(argv, NULL); 
 	if (na < 0) 
 		return -EFAULT; 
+	} 	
+	if (envp) { 
 	ne = nargs(envp, NULL); 
 	if (ne < 0) 
 		return -EFAULT; 
+	}
 
+	if (argv || envp) { 
 	sz = (na+ne)*sizeof(void *); 
 	if (sz > PAGE_SIZE) 
 		buf = vmalloc(sz); 
@@ -2089,14 +2155,19 @@
 		buf = kmalloc(sz, GFP_KERNEL); 
 	if (!buf)
 		return -ENOMEM; 
+	} 
 	
+	if (argv) { 
 	ret = nargs(argv, buf);
 	if (ret < 0)
 		goto free;
+	}
 
+	if (envp) { 
 	ret = nargs(envp, buf + na); 
 	if (ret < 0)
 		goto free; 
+	}
 
 	name = getname(name); 
 	ret = PTR_ERR(name); 
@@ -2105,7 +2176,7 @@
 
 	oldseg = get_fs(); 
 	set_fs(KERNEL_DS);
-	ret = do_execve(name, buf, buf+na, &regs);  
+	ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, &regs);  
 	set_fs(oldseg); 
 
 	if (ret == 0)
@@ -2114,19 +2185,21 @@
 	putname(name);
  
 free:
+	if (argv || envp) { 
 	if (sz > PAGE_SIZE)
 		vfree(buf); 
 	else
 		kfree(buf);
+	}
 	return ret; 
 } 
 
-asmlinkage int sys32_fork(struct pt_regs regs)
+asmlinkage long sys32_fork(struct pt_regs regs)
 {
 	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
 }
 
-asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
 {
 	if (!newsp)
 		newsp = regs.rsp;
@@ -2143,7 +2216,7 @@
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage int sys32_vfork(struct pt_regs regs)
+asmlinkage long sys32_vfork(struct pt_regs regs)
 {
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
 }
@@ -2154,14 +2227,14 @@
 
 extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
 
-int sys32_lseek (unsigned int fd, int offset, unsigned int whence)
+asmlinkage long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
 	return sys_lseek(fd, offset, whence);
 }
 
 extern int sys_kill(pid_t pid, int sig); 
 
-int sys32_kill(int pid, int sig)
+asmlinkage long sys32_kill(int pid, int sig)
 {
 	return sys_kill(pid, sig);
 }
@@ -2306,54 +2379,6 @@
 	return err;
 }
 
-static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	u32 uaddr;
-	int i;
-	int err;
-
-	memset(karg, 0, sizeof(*karg));
-	if(get_user(karg->ca_version, &arg32->ca32_version))
-		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
-	if(!karg->ca_umap.ug_ident)
-		return -ENOMEM;
-	err = get_user(uaddr, &arg32->ca32_umap.ug32_ident);
-	if(strncpy_from_user(karg->ca_umap.ug_ident,
-			     (char *)A(uaddr), PAGE_SIZE) <= 0)
-		return -EFAULT;
-	err |= __get_user(karg->ca_umap.ug_uidbase,
-		      &arg32->ca32_umap.ug32_uidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_uidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_udimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_udimap[i],
-			      &(((__kernel_uid_t32 *)A(uaddr))[i]));
-	err |= __get_user(karg->ca_umap.ug_gidbase,
-		      &arg32->ca32_umap.ug32_gidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_gidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_gdimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_gdimap[i],
-			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
-
-	return err;
-}
-
 static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
 	int err;
@@ -2411,7 +2436,7 @@
 	return copy_to_user(res32, kres, sizeof(*res32));
 }
 
-int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
 	struct nfsctl_arg *karg = NULL;
 	union nfsctl_res *kres = NULL;
@@ -2442,10 +2467,6 @@
 	case NFSCTL_UNEXPORT:
 		err = nfs_exp32_trans(karg, arg32);
 		break;
-	/* This one is unimplemented, be we're ready for it. */
-	case NFSCTL_UGIDUPDATE:
-		err = nfs_uud32_trans(karg, arg32);
-		break;
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
@@ -2492,13 +2513,13 @@
 }
 #else /* !NFSD */
 extern asmlinkage long sys_ni_syscall(void);
-int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
+long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
 {
 	return sys_ni_syscall();
 }
 #endif
 
-int sys32_module_warning(void)
+long sys32_module_warning(void)
 { 
 	static long warn_time = -(60*HZ); 
 	if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { 
@@ -2509,15 +2530,27 @@
 	return -ENOSYS ;
 } 
 
+long sys32_vm86_warning(void)
+{ 
+	static long warn_time = -(60*HZ); 
+	if (time_before(warn_time + 60*HZ,jiffies)) { 
+		printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
+		       current->comm);
+		warn_time = jiffies;
+	} 
+	return -ENOSYS ;
+} 
+
+/* This only triggers an i686 uname */
 struct exec_domain ia32_exec_domain = { 
-	name: "linux/x86",
+	name: "linux/uname-i686",
 	pers_low: PER_LINUX32,
 	pers_high: PER_LINUX32,
 };      
 
 static int __init ia32_init (void)
 {
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $\n");  
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.54 2003/03/24 09:28:26 ak Exp $\n");  
 	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
 	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
 	register_exec_domain(&ia32_exec_domain);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/acpitable.c linux-2.4.21-rc3/arch/x86_64/kernel/acpitable.c
--- linux-2.4.20/arch/x86_64/kernel/acpitable.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/acpitable.c	2003-05-22 22:06:49.000000000 +0000
@@ -282,9 +282,9 @@
 		return -1;
 	}
 
-	hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
+	hpet_address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
 
-	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address);
+	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet_address);
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/aperture.c linux-2.4.21-rc3/arch/x86_64/kernel/aperture.c
--- linux-2.4.20/arch/x86_64/kernel/aperture.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/aperture.c	2003-05-22 22:06:52.000000000 +0000
@@ -8,7 +8,7 @@
  * the bootmem allocator can allocate 32+MB. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $
+ * $Id: aperture.c,v 1.4 2002/11/28 06:05:58 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -47,10 +47,9 @@
 	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
 
 	/* 
-         * Aperture has to be naturally aligned it seems. This means an
-	 * 2GB aperture won't have much changes to succeed in the lower 4GB of 
-	 * memory. Unfortunately we cannot move it up because that would make
-	 * the IOMMU useless.
+         * Aperture has to be naturally aligned. This means an 2GB aperture won't 
+         * have much chances to find a place in the lower 4GB of memory. Unfortunately 
+         * we cannot move it up because that would make the IOMMU useless.
 	 */
 	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
 	if (!p || __pa(p)+aper_size > 0xffffffff) {
@@ -105,7 +104,8 @@
 	if (!fix && !fallback_aper_force) 
 		return; 
 
-	printk("Your BIOS is broken and doesn't leave a aperture memory hole\n");
+	printk("Your BIOS doesn't leave a aperture memory hole\n");
+	printk("Please enable the IOMMU option in the BIOS setup\n"); 
 	aper_alloc = allocate_aperture(); 
 	if (!aper_alloc) 
 		return; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/apic.c linux-2.4.21-rc3/arch/x86_64/kernel/apic.c
--- linux-2.4.20/arch/x86_64/kernel/apic.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/apic.c	2003-05-22 22:06:24.000000000 +0000
@@ -31,6 +31,10 @@
 #include <asm/pgalloc.h>
 #include <asm/timex.h>
 
+int apic_disabled;
+
+extern spinlock_t i8253_lock;
+
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
 
@@ -373,10 +377,10 @@
 	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
 	if (!smp_processor_id() && (pic_mode || !value)) {
 		value = APIC_DM_EXTINT;
-		printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
+		Dprintk("enabled ExtINT on CPU#%d\n", smp_processor_id());
 	} else {
 		value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-		printk("masked ExtINT on CPU#%d\n", smp_processor_id());
+		Dprintk("masked ExtINT on CPU#%d\n", smp_processor_id());
 	}
 	apic_write_around(APIC_LVT0, value);
 
@@ -396,7 +400,7 @@
 		if (maxlvt > 3)			/* Due to the Pentium erratum 3AP. */
 			apic_write(APIC_ESR, 0);
 		value = apic_read(APIC_ESR);
-		printk("ESR value before enabling vector: %08x\n", value);
+		Dprintk("ESR value before enabling vector: %08x\n", value);
 
 		value = ERROR_APIC_VECTOR;	/* enables sending errors */
 		apic_write_around(APIC_LVTERR, value);
@@ -406,7 +410,7 @@
 		if (maxlvt > 3)
 			apic_write(APIC_ESR, 0);
 		value = apic_read(APIC_ESR);
-		printk("ESR value after enabling vector: %08x\n", value);
+		Dprintk("ESR value after enabling vector: %08x\n", value);
 	} else {
 		if (esr_disable)
 			/*
@@ -415,9 +419,9 @@
 			 * ESR disabled - we can't do anything useful with the
 			 * errors anyway - mbligh
 			 */
-			printk("Leaving ESR disabled.\n");
+			Dprintk("Leaving ESR disabled.\n");
 		else
-			printk("No ESR for 82489DX.\n");
+			Dprintk("No ESR for 82489DX.\n");
 	}
 
 	if (nmi_watchdog == NMI_LOCAL_APIC)
@@ -766,12 +770,13 @@
 	 * Wait for timer IRQ slice:
 	 */
 
-	if (hpet.address) {
+	if (hpet_address) {
 		int trigger = hpet_readl(HPET_T0_CMP);
 		while (hpet_readl(HPET_COUNTER) >= trigger);
 		while (hpet_readl(HPET_COUNTER) <  trigger);
 	} else {
 		int c1, c2;
+		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);
 		c2 = inb_p(0x40);
 		c2 |= inb_p(0x40) << 8;
@@ -781,6 +786,7 @@
 			c2 = inb_p(0x40);
 			c2 |= inb_p(0x40) << 8;
 		} while (c2 - c1 < 300);
+		spin_unlock(&i8253_lock);
 	}
 
 	__setup_APIC_LVTT(clocks);
@@ -1018,6 +1024,7 @@
 		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
 		       smp_processor_id(), skipped);
 		last_warning = jiffies;
+		skipped = 0;
 	} else {
 		skipped++;
 	}
@@ -1058,8 +1065,10 @@
  */
 int __init APIC_init_uniprocessor (void)
 {
-	if (!smp_found_config && !cpu_has_apic)
+	if (!smp_found_config && !cpu_has_apic) { 
+		apic_disabled = 1;
 		return -1;
+	} 
 
 	/*
 	 * Complain if the BIOS pretends there is one.
@@ -1067,6 +1076,7 @@
 	if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
 		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
 			boot_cpu_id);
+		apic_disabled = 1;
 		return -1;
 	}
 
@@ -1084,9 +1094,10 @@
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		check_nmi_watchdog();
 #ifdef CONFIG_X86_IO_APIC
-	if (smp_found_config)
-		if (!skip_ioapic_setup && nr_ioapics)
+	if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
 			setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 #endif
 	setup_APIC_clocks();
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/bluesmoke.c linux-2.4.21-rc3/arch/x86_64/kernel/bluesmoke.c
--- linux-2.4.20/arch/x86_64/kernel/bluesmoke.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/bluesmoke.c	2003-05-22 22:06:51.000000000 +0000
@@ -1,6 +1,6 @@
 /* 
  * Machine check handler.
- * K8 parts Copyright 2002 Andi Kleen, SuSE Labs.
+ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
  * Rest from unknown author(s). 
  */
 #include <linux/init.h>
@@ -15,14 +15,23 @@
 #include <linux/pci.h>
 #include <linux/timer.h>
 
-static int mce_disabled __initdata = 1;
+static int mce_disabled __initdata;
+static unsigned long mce_cpus; 
 
 /*
  *	Machine Check Handler For PII/PIII/K7
  */
 
 static int banks;
-static unsigned long ignored_banks, disabled_banks =  (1UL << 4); 
+static unsigned long ignored_banks, disabled_banks;
+
+/* Machine Check on everything dubious. This is a good setting
+   for device driver testing. */
+#define K8_DRIVER_DEBUG ((1<<13)-1)
+/* Report RAM errors and Hyper Transport Problems, but ignore Device
+   aborts and GART errors. */
+#define K8_NORMAL_OP    0xff
+static u32 k8_nb_flags __initdata = K8_NORMAL_OP;
 
 static void generic_machine_check(struct pt_regs * regs, long error_code)
 {
@@ -96,7 +105,7 @@
 
 void do_machine_check(struct pt_regs * regs, long error_code)
 {
-	notify_die(DIE_NMI, "machine check", regs, error_code);
+	notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
 	machine_check_vector(regs, error_code);
 }
 
@@ -116,14 +125,48 @@
 	return NULL;
 }
 
+static void check_k8_nb(void)
+{
+	struct pci_dev *nb;
+	nb = find_k8_nb(); 
+	if (nb == NULL)
+		return;
+
+	u32 statuslow, statushigh;
+	pci_read_config_dword(nb, 0x48, &statuslow);
+	pci_read_config_dword(nb, 0x4c, &statushigh);
+	if (!(statushigh & (1<<31)))
+		return;
+	printk(KERN_ERR "Northbridge status %08x%08x\n",
+	       statushigh,statuslow); 
+	if (statuslow & 0x10) 
+		printk(KERN_ERR "GART error %d\n", statuslow & 0xf); 
+	if (statushigh & (1<<31))
+		printk(KERN_ERR "Lost an northbridge error\n"); 
+	if (statushigh & (1<<25))
+		printk(KERN_EMERG "NB status: unrecoverable\n"); 
+	if (statushigh & (1<<26)) { 
+		u32 addrhigh, addrlow; 
+		pci_read_config_dword(nb, 0x54, &addrhigh); 
+		pci_read_config_dword(nb, 0x50, &addrlow); 
+		printk(KERN_ERR "NB error address %08x%08x\n", addrhigh,addrlow); 
+	}
+	if (statushigh & (1<<29))
+		printk(KERN_EMERG "Error uncorrected\n"); 
+	statushigh &= ~(1<<31); 
+	pci_write_config_dword(nb, 0x4c, statushigh); 		
+}
+
 static void k8_machine_check(struct pt_regs * regs, long error_code)
 { 
 	u64 status, nbstatus;
-	struct pci_dev *nb;
 
 	rdmsrl(MSR_IA32_MCG_STATUS, status); 
-	if ((status & (1<<2)) == 0) 
+	if ((status & (1<<2)) == 0) { 
+		if (!regs) 
+			check_k8_nb();
 		return; 
+	}
 	if (status & 1)
 		printk(KERN_EMERG "MCG_STATUS: unrecoverable\n"); 
 
@@ -141,28 +184,7 @@
 	if (nbstatus & (1UL<57))
 		printk(KERN_EMERG "Unrecoverable condition\n"); 
 		
-	nb = find_k8_nb(); 
-	if (nb != NULL) { 
-		u32 statuslow, statushigh;
-		pci_read_config_dword(nb, 0x48, &statuslow);
-		pci_read_config_dword(nb, 0x4c, &statushigh);
-		printk(KERN_EMERG "Northbridge status %08x%08x\n",
-		       statushigh,statuslow); 
-		if (statuslow & 0x10) 
-			printk(KERN_EMERG "GART error %d\n", statuslow & 0xf); 
-		if (statushigh & (1<<31))
-			printk(KERN_EMERG "Lost an northbridge error\n"); 
-		if (statushigh & (1<<25))
-			printk(KERN_EMERG "NB status: unrecoverable\n"); 
-		if (statushigh & (1<<26)) { 
-			u32 addrhigh, addrlow; 
-			pci_read_config_dword(nb, 0x54, &addrhigh); 
-			pci_read_config_dword(nb, 0x50, &addrlow); 
-			printk(KERN_EMERG "NB error address %08x%08x\n", addrhigh,addrlow); 
-		}
-		statushigh &= ~(1<<31); 
-		pci_write_config_dword(nb, 0x4c, statushigh); 		
-	} 
+	check_k8_nb();
 
 	if (nbstatus & (1UL<<58)) { 
 		u64 adr;
@@ -183,33 +205,38 @@
 static struct timer_list mcheck_timer;
 int mcheck_interval = 30*HZ; 
 
+#ifndef CONFIG_SMP 
 static void mcheck_timer_handler(unsigned long data)
 {
 	k8_machine_check(NULL,0);
-	BUG_ON(timer_pending(&mcheck_timer));
 	mcheck_timer.expires = jiffies + mcheck_interval;
 	add_timer(&mcheck_timer);
 }
+#else
 
-#ifdef CONFIG_SMP 
 /* SMP needs a process context trampoline because smp_call_function cannot be 
-   called from interrupt context */
+   called from interrupt context. */
+
+static void mcheck_timer_other(void *data)
+{ 
+	k8_machine_check(NULL, 0); 
+} 
+
 static void mcheck_timer_dist(void *data)
 { 
-	/* preempt disabled on preemptive kernel */	
-	if (!data) 
-		smp_call_function((void (*)(void *))mcheck_timer_handler,(void*)1,0,0);
-	mcheck_timer_handler(0); 	
+	smp_call_function(mcheck_timer_other,0,0,0);
+	k8_machine_check(NULL, 0); 
+	mcheck_timer.expires = jiffies + mcheck_interval;
+	add_timer(&mcheck_timer);
 } 
 
-static void mcheck_timer_trampoline(unsigned long data)
+static void mcheck_timer_handler(unsigned long data)
 { 
 	static struct tq_struct mcheck_task = { 
 		routine: mcheck_timer_dist
 	}; 
 	schedule_task(&mcheck_task); 
 } 
-#define mcheck_timer_handler mcheck_timer_trampoline
 #endif 
 
 static int nok8 __initdata; 
@@ -235,17 +262,19 @@
 
 	nb = find_k8_nb(); 
 	if (nb != NULL) {
-		u32 reg;
+		u32 reg, reg2;
 		pci_read_config_dword(nb, 0x40, &reg); 
-		pci_write_config_dword(nb, 0x40, reg|(1<<11)|(1<<10)|(1<<9)|(1<<8)); 
-		printk(KERN_INFO "Machine Check Reporting for K8 Northbridge %d enabled\n",
-		       nb->devfn);
+		pci_write_config_dword(nb, 0x40, k8_nb_flags);
+		pci_read_config_dword(nb, 0x44, &reg2);
+		pci_write_config_dword(nb, 0x44, reg2); 
+		printk(KERN_INFO "Machine Check for K8 Northbridge %d enabled (%x,%x)\n",
+		       nb->devfn, reg, reg2);
 		ignored_banks |= (1UL<<4); 
 	} 
 
 	set_in_cr4(X86_CR4_MCE);	   	
 
-	if (mcheck_interval) { 
+	if (mcheck_interval && (smp_processor_id() == 0)) { 
 		init_timer(&mcheck_timer); 
 		mcheck_timer.function = (void (*)(unsigned long))mcheck_timer_handler; 
 		mcheck_timer.expires = jiffies + mcheck_interval; 
@@ -308,6 +337,9 @@
 
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
+	if (test_and_set_bit(smp_processor_id(), &mce_cpus))
+		return; 
+
 	if(mce_disabled==1)
 		return;
 		
@@ -333,9 +365,10 @@
 
 
 /* mce=off disable machine check
-   mcenok8 disable k8 specific features
+   mce=nok8 disable k8 specific features
    mce=disable<NUMBER> disable bank NUMBER
    mce=enable<NUMBER> enable bank number
+   mce=device	Enable device driver test reporting in NB
    mce=NUMBER mcheck timer interval number seconds. 
    Can be also comma separated in a single mce= */
 static int __init mcheck_enable(char *str)
@@ -352,8 +385,8 @@
 			disabled_banks |= ~(1<<simple_strtol(p+7,NULL,0));
 		else if (!strcmp(p,"nok8"))
 			nok8 = 1;
-		else
-			return -1;			
+		else if (!strcmp(p,"device"))
+			k8_nb_flags = K8_DRIVER_DEBUG;
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/e820.c linux-2.4.21-rc3/arch/x86_64/kernel/e820.c
--- linux-2.4.20/arch/x86_64/kernel/e820.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/e820.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,7 +1,7 @@
 /* 
  * Handle the memory map.
  * The functions here do the job until bootmem takes over.
- * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+ * $Id: e820.c,v 1.6 2002/10/15 09:35:16 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -122,27 +122,51 @@
 }
 
 /*
+ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
+ * The direct mapping extends to end_pfn_map, so that we can directly access
+ * ACPI and other tables without having to play with fixmaps.
+ */ 
+unsigned long end_pfn_map; 
+
+/* 
+ * Last pfn which the user wants to use.
+ */
+unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
+
+/*
  * Find the highest page frame number we have available
  */
+
 void __init e820_end_of_ram(void)
 {
 	int i;
 	end_pfn = 0;
+	
 	for (i = 0; i < e820.nr_map; i++) {
 		struct e820entry *ei = &e820.map[i]; 
 		unsigned long start, end;
 
-		/* count all types of areas for now to map ACPI easily */
 		start = round_up(ei->addr, PAGE_SIZE); 
 		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
 		if (start >= end)
 			continue;
+		if (ei->type == E820_RAM) { 
 		if (end > end_pfn<<PAGE_SHIFT)
 			end_pfn = end>>PAGE_SHIFT;
+		} else { 
+			if (end > end_pfn_map<<PAGE_SHIFT) 
+				end_pfn_map = end>>PAGE_SHIFT;
+		} 
 	}
 
-	if (end_pfn > MAXMEM >> PAGE_SHIFT)
-		end_pfn = MAXMEM >> PAGE_SHIFT;
+	if (end_pfn > end_pfn_map) 
+		end_pfn_map = end_pfn;
+	if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
+		end_pfn_map = MAXMEM>>PAGE_SHIFT;
+	if (end_pfn > end_user_pfn)
+		end_pfn = end_user_pfn;
+	if (end_pfn > end_pfn_map) 
+		end_pfn = end_pfn_map; 
 }
 
 /* 
@@ -481,7 +505,6 @@
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -492,44 +515,23 @@
 			goto next;
 
 		/*
-		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
-		 * to <mem>, overriding the bios size.
-		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
-		 * <start> to <start>+<mem>, overriding the bios size.
+		 * mem=XXX[kKmM] limits kernel memory to XXX+1MB
+		 *
+		 * It would be more logical to count from 0 instead of from
+		 * HIGH_MEMORY, but we keep that for now for i386 compatibility. -AK
 		 */
 		if (!memcmp(from, "mem=", 4)) {
-			if (to != command_line)
-				to--;
-			else if (!memcmp(from+4, "exactmap", 8)) {
-				from += 8+4;
-				e820.nr_map = 0;
-				usermem = 1;
-			} else {
-				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
-				 */
-				unsigned long long start_at, mem_size;
- 
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
+			/* 
+			 * No support for custom mapping like i386.
+			 * The reason is that we need to read the e820 map
+			 * anyways to handle the ACPI mappings in the 
+			 * direct map.
+			 * Also on x86-64 there should be always a good e820
+			 * map. This is only an upper limit, you cannot force
+			 * usage of memory not in e820.
 					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
-				mem_size = memparse(from+4, &from);
-				if (*from == '@')
-					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
-				}
-				add_memory_region(start_at, mem_size, E820_RAM);
-			}
+			end_user_pfn = memparse(from+4, &from) + HIGH_MEMORY;
+			end_user_pfn >>= PAGE_SHIFT;
 		}
 #ifdef CONFIG_GART_IOMMU 
 		else if (!memcmp(from,"iommu=",6)) { 
@@ -547,8 +549,4 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
-		printk(KERN_INFO "user-defined physical RAM map:\n");
-		e820_print_map("user");
-	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/entry.S linux-2.4.21-rc3/arch/x86_64/kernel/entry.S
--- linux-2.4.20/arch/x86_64/kernel/entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/entry.S	2003-05-22 22:06:51.000000000 +0000
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
  * 
- *  $Id: entry.S,v 1.81 2002/09/12 12:55:25 ak Exp $		
+ *  $Id: entry.S,v 1.95 2003/04/03 09:46:54 ak Exp $		
  */
 
 /*
@@ -34,6 +34,7 @@
 #include <asm/offset.h>
 #include <asm/msr.h>
 #include <asm/unistd.h>
+#include <asm/hw_irq.h>
 
 	.code64
 
@@ -85,6 +86,7 @@
 2:
 	movq %rsp,%rdi	
 	call syscall_trace
+	GET_CURRENT(%rcx)
 	jmp 1b
 
 /*
@@ -187,6 +189,7 @@
 	jmp ret_from_sys_call
 		
 badsys:
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
 	jmp ret_from_sys_call
 
@@ -227,6 +230,7 @@
 	je   retint_restore_args_swapgs
 	sti
 	call schedule
+	# RED-PEN: can we lose signals here?
 	jmp  intret_signal_test
 	
 /* 
@@ -307,8 +311,13 @@
 	je   1f
 	swapgs
 1:	cld
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	SAVE_ALL
+	movq %rsp,%rdi
+#else			
 	SAVE_ARGS
 	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
+#endif	
 	addl $1,PDAREF(pda_irqcount)	# XXX: should be merged with irq.c irqcount
 	movq PDAREF(pda_irqstackptr),%rax
 	cmoveq %rax,%rsp
@@ -369,6 +378,48 @@
 	cli
 	jmp retint_with_reschedule
 		
+/* IF:off, stack contains irq number on origrax */ 	
+	.macro IRQ_ENTER	
+	cld
+	pushq %rdi
+	pushq %rsi
+	pushq %rdx
+	pushq %rcx
+	pushq %rax
+	pushq %r8
+	pushq %r9
+	pushq %r10
+	pushq %r11
+	leaq -48(%rsp),%rdi
+	testl $3,136(%rdi)
+	je 1f
+	swapgs
+1:	addl $1,%gs:pda_irqcount
+	movq %gs:pda_irqstackptr,%rax
+	cmoveq %rax,%rsp
+	pushq %rdi
+	.endm	
+
+	.macro BUILD_SMP_INTERRUPT x,v
+ENTRY(\x)
+	push $\v-256
+	IRQ_ENTER
+	call smp_\x
+	jmp ret_from_intr
+	.endm
+
+#ifdef CONFIG_SMP				
+	BUILD_SMP_INTERRUPT reschedule_interrupt,RESCHEDULE_VECTOR
+	BUILD_SMP_INTERRUPT invalidate_interrupt,INVALIDATE_TLB_VECTOR
+	BUILD_SMP_INTERRUPT call_function_interrupt,CALL_FUNCTION_VECTOR
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+	BUILD_SMP_INTERRUPT apic_timer_interrupt,LOCAL_TIMER_VECTOR
+	BUILD_SMP_INTERRUPT error_interrupt,ERROR_APIC_VECTOR
+	BUILD_SMP_INTERRUPT spurious_interrupt,SPURIOUS_APIC_VECTOR
+#endif
+		
+		
 /*
  * Exception entry points.
  */ 		
@@ -407,8 +458,7 @@
 	je error_kernelspace
 	swapgs	
 	movl $1,%r15d	
-error_action:		
-	sti	
+error_action:
 	movq  %rdi,RDI(%rsp) 	
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
@@ -432,11 +482,15 @@
 	jmp retint_restore_args
 	
 error_reschedule:
+	cmpl $2,%r15d
+	je  error_restore_swapgs
 	sti
 	call schedule
 	jmp  error_test
 
 error_signal:	
+	cmpl $2,%r15d
+	je  error_restore_swapgs	
 	sti
 	xorq %rsi,%rsi
 	movq %rsp,%rdi
@@ -452,22 +506,48 @@
 	
 error_kernelspace:	
 	xorl %r15d,%r15d
+	/* There are two places in the kernel that can potentially fault with
+	   usergs. Handle them here. */	   
 	cmpq $iret_label,RIP(%rsp)
+	je   1f
+	cmpq $gs_change,RIP(%rsp)
 	jne  error_action
-	movl $1,%r15d
+1:	movl $2,%r15d
 	swapgs
 	jmp error_action
 
+	/* Reload gs selector with exception handling */
+	/* edi:	 new selector */ 
+ENTRY(load_gs_index)
+	pushf
+	cli
+	swapgs
+gs_change:	
+	movl %edi,%gs	
+2:	mfence
+	swapgs
+	popf
+	ret
+	
+	.section __ex_table,"a"
+	.align 8
+	.quad gs_change,bad_gs
+	.previous
+
+bad_gs:
+	xorl %eax,%eax
+	movl %eax,%gs
+	jmp 2b
 /*
  * Create a kernel thread.
  *
  * C extern interface:
- *	extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ *	extern long arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  *
  * asm input arguments:
  *	rdi: fn, rsi: arg, rdx: flags
  */
-ENTRY(kernel_thread)
+ENTRY(arch_kernel_thread)
 	FAKE_STACK_FRAME $child_rip
 	SAVE_ALL
 
@@ -535,18 +615,6 @@
 	ret
 
 ENTRY(page_fault)
-#ifdef CONFIG_KDB
-	pushq %rcx
-	pushq %rdx
-	pushq %rax
-	movl  $473,%ecx
-	rdmsr
-	andl  $0xfffffffe,%eax		/* Disable last branch recording */
-	wrmsr
-	popq  %rax
-	popq  %rdx
-	popq  %rcx
-#endif	
 	errorentry do_page_fault
 
 ENTRY(coprocessor_error)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/head.S linux-2.4.21-rc3/arch/x86_64/kernel/head.S
--- linux-2.4.20/arch/x86_64/kernel/head.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/head.S	2003-05-22 22:06:48.000000000 +0000
@@ -6,7 +6,7 @@
  *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
  *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
  *
- *  $Id: head.S,v 1.53 2002/07/18 09:49:42 ak Exp $
+ *  $Id: head.S,v 1.55 2003/02/11 12:29:15 ak Exp $
  */
 
 
@@ -76,13 +76,11 @@
 	/* Enable System Call */
 	btsl	$_EFER_SCE, %eax
 
-#if 0
 	/* No Execute supported? */	
 	btl	$20,%edi
 	jnc     1f
 	btsl	$_EFER_NX, %eax
 1:
-#endif
 	
 	/* Make changes effective */
 	wrmsr
@@ -118,7 +116,6 @@
 	jnz   second	
 	
 	/* Load new GDT with the 64bit segment using 32bit descriptor */
-	/* to avoid 32bit relocations we use fixed adresses here */
 	movl	$0x100F00, %eax
 	lgdt	(%eax)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/head64.c linux-2.4.21-rc3/arch/x86_64/kernel/head64.c
--- linux-2.4.20/arch/x86_64/kernel/head64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/head64.c	2003-05-22 22:06:52.000000000 +0000
@@ -3,9 +3,10 @@
  *
  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
  *
- *  $Id: head64.c,v 1.25 2002/07/01 08:01:19 ak Exp $
+ *  $Id: head64.c,v 1.27 2003/03/31 15:12:07 ak Exp $
  */
 
+#include <asm/bootsetup.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -50,7 +51,7 @@
 		printk("old bootloader convention, maybe loadlin?\n");
 	}
 	command_line = (char *) ((u64)(new_data));
-	memcpy(saved_command_line, command_line, 2048);
+	memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
 	printk("Bootdata ok (command line is %s)\n", saved_command_line);	
 }
 
@@ -81,6 +82,12 @@
 	s = strstr(saved_command_line, "earlyprintk="); 
 	if (s != NULL)
 		setup_early_printk(s+12); 
+#ifdef CONFIG_DISCONTIGMEM
+	extern int numa_setup(char *);
+	s = strstr(saved_command_line, "numa=");
+	if (s != NULL)
+		numa_setup(s+5);
+#endif		
 	early_printk("booting x86_64 kernel... ");
 	setup_boot_cpu_data();
 	start_kernel();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/i387.c linux-2.4.21-rc3/arch/x86_64/kernel/i387.c
--- linux-2.4.20/arch/x86_64/kernel/i387.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/i387.c	2003-05-22 22:06:42.000000000 +0000
@@ -25,19 +25,16 @@
 
 extern int exception_trace;
 
-/*
- * The _current_ task is using the FPU for the first time
- * so initialize it and set the mxcsr to its default
- * value at reset if we support XMM instructions and then
- * remeber the current task has used the FPU.
- */
-void init_fpu(void)
+void init_fpu(struct task_struct *child)
 {
-	struct task_struct *me = current;
-	memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
-	me->thread.i387.fxsave.cwd = 0x37f;
-	me->thread.i387.fxsave.mxcsr = 0x1f80;
-	me->used_math = 1;
+	if (child->used_math) { 
+		unlazy_fpu(child);
+		return;
+	}
+	memset(&child->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
+	child->thread.i387.fxsave.cwd = 0x37f;
+	child->thread.i387.fxsave.mxcsr = 0x1f80;
+	child->used_math = 1;
 }
 
 /*
@@ -81,7 +78,7 @@
 
 int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk)
 {
-	empty_fpu(tsk);
+	init_fpu(tsk);
 	return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave,
 			       sizeof(struct user_i387_struct)) ? -EFAULT : 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/i8259.c linux-2.4.21-rc3/arch/x86_64/kernel/i8259.c
--- linux-2.4.20/arch/x86_64/kernel/i8259.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/i8259.c	2003-05-22 22:06:24.000000000 +0000
@@ -40,8 +40,6 @@
  * interrupt-controller happy.
  */
 
-BUILD_COMMON_IRQ()
-
 #define BI(x,y) \
 	BUILD_IRQ(x##y)
 
@@ -77,24 +75,6 @@
 #undef BUILD_16_IRQS
 #undef BI
 
-
-/*
- * The following vectors are part of the Linux architecture, there
- * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs)
- */
-#ifdef CONFIG_SMP
-BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR);
-BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR);
-BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR);
-BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR);
-BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR);
-#endif
-
 #define IRQ(x,y) \
 	IRQ##x##y##_interrupt
 
@@ -424,7 +404,7 @@
 	 */
 	for (i = 0; i < NR_IRQS; i++) {
 		int vector = FIRST_EXTERNAL_VECTOR + i;
-		if (vector != IA32_SYSCALL_VECTOR && vector != KDBENTER_VECTOR) {
+		if (vector != IA32_SYSCALL_VECTOR) {
 			set_intr_gate(vector, interrupt[i]);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/io_apic.c linux-2.4.21-rc3/arch/x86_64/kernel/io_apic.c
--- linux-2.4.20/arch/x86_64/kernel/io_apic.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/io_apic.c	2003-05-22 22:06:40.000000000 +0000
@@ -728,8 +728,10 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
+#if 0
 	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
 	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+#endif
 }
 
 void __init print_IO_APIC(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ioport.c linux-2.4.21-rc3/arch/x86_64/kernel/ioport.c
--- linux-2.4.20/arch/x86_64/kernel/ioport.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/ioport.c	2003-05-22 22:06:42.000000000 +0000
@@ -53,7 +53,7 @@
 /*
  * this changes the io permissions bitmap in the current task.
  */
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
 	struct thread_struct * t = &current->thread;
 	struct tss_struct * tss = init_tss + smp_processor_id();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ldt.c linux-2.4.21-rc3/arch/x86_64/kernel/ldt.c
--- linux-2.4.20/arch/x86_64/kernel/ldt.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/ldt.c	2003-05-22 22:06:51.000000000 +0000
@@ -85,11 +85,6 @@
 			goto out;
 	}
 
-	me->thread.fsindex = 0; 
-	me->thread.gsindex = 0; 
-	me->thread.gs = 0; 
-	me->thread.fs = 0; 
-
 	/*
 	 * the GDT index of the LDT is allocated dynamically, and is
 	 * limited by MAX_LDT_DESCRIPTORS.
@@ -142,10 +137,8 @@
 
 	/* Install the new entry ...  */
 install:
-	write_lock(&mm->context.ldtlock);
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
-	write_unlock(&mm->context.ldtlock);
 	error = 0;
 
 out_unlock:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/msr.c linux-2.4.21-rc3/arch/x86_64/kernel/msr.c
--- linux-2.4.20/arch/x86_64/kernel/msr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/msr.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,4 +1,4 @@
-#ident "$Id: msr.c,v 1.7 2002/02/14 10:20:47 ak Exp $"
+#ident "$Id: msr.c,v 1.8 2003/01/10 15:17:43 ak Exp $"
 /* ----------------------------------------------------------------------- *
  *   
  *   Copyright 2000 H. Peter Anvin - All Rights Reserved
@@ -55,7 +55,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err)
@@ -76,7 +76,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/nmi.c linux-2.4.21-rc3/arch/x86_64/kernel/nmi.c
--- linux-2.4.20/arch/x86_64/kernel/nmi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/nmi.c	2003-05-22 22:06:39.000000000 +0000
@@ -31,6 +31,8 @@
 static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 
+int nmi_watchdog_disabled; 
+
 #define K7_EVNTSEL_ENABLE	(1 << 22)
 #define K7_EVNTSEL_INT		(1 << 20)
 #define K7_EVNTSEL_OS		(1 << 17)
@@ -223,6 +225,7 @@
 	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
 }
 
+#ifndef CONFIG_MK8
 static void __pminit setup_p6_watchdog(void)
 {
 	unsigned int evntsel;
@@ -274,6 +277,7 @@
 	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
 	return 1;
 }
+#endif
 
 void __pminit setup_apic_nmi_watchdog (void)
 {
@@ -285,6 +289,7 @@
 			return;	    
 		setup_k7_watchdog();
 		break;
+#ifndef CONFIG_MK8
 	case X86_VENDOR_INTEL:
 		switch (boot_cpu_data.x86) {
 		case 6:
@@ -298,6 +303,7 @@
 			return;
 		}
 		break;
+#endif
 	default:
 		return;
 	}
@@ -337,14 +343,17 @@
 		alert_counter[i] = 0;
 }
 
-void nmi_watchdog_tick (struct pt_regs * regs)
+void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
 {
 
 	/*
 	 * Since current-> is always on the stack, and we always switch
 	 * the stack NMI-atomically, it's safe to use smp_processor_id().
 	 */
-	int sum, cpu = smp_processor_id();
+	int sum, cpu = safe_smp_processor_id();
+
+	if (nmi_watchdog_disabled)
+		return;
 
 	sum = apic_timer_irqs[cpu];
 
@@ -355,6 +364,14 @@
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+
+
+			if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { 
+				alert_counter[cpu] = 0; 
+				return;
+			} 
+
+
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
@@ -374,6 +391,7 @@
 		alert_counter[cpu] = 0;
 	}
 	if (nmi_perfctr_msr) {
+#ifndef CONFIG_MK8
 		if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
 			/*
 			 * P4 quirks:
@@ -385,6 +403,7 @@
 			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
 			apic_write(APIC_LVTPC, APIC_DM_NMI);
 		}
+#endif
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-dma.c linux-2.4.21-rc3/arch/x86_64/kernel/pci-dma.c
--- linux-2.4.20/arch/x86_64/kernel/pci-dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/pci-dma.c	2003-05-22 22:06:43.000000000 +0000
@@ -37,16 +37,16 @@
  	 */
  	for (i = 0; i < nents; i++ ) {
 		struct scatterlist *s = &sg[i];
- 		if (s->address) {
+		int flush = (i == nents-1);
+		void *addr = s->address; 
+		if (addr) 
 			BUG_ON(s->page || s->offset); 
- 			s->dma_address = pci_map_single(hwdev, s->address, s->length, 
-							direction); 
- 		} else if (s->page) { 
-			s->dma_address = pci_map_page(hwdev, s->page, s->offset,
-						      s->length, direction); 
-		} else
+		else if (s->page)
+			addr = page_address(s->page) + s->offset; 
+		else
 			BUG(); 
-
+		s->dma_address = __pci_map_single(hwdev, addr, s->length,
+						  direction, flush); 
 		if (unlikely(s->dma_address == bad_dma_address))
 			goto error; 
  	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-gart.c linux-2.4.21-rc3/arch/x86_64/kernel/pci-gart.c
--- linux-2.4.20/arch/x86_64/kernel/pci-gart.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/pci-gart.c	2003-05-22 22:06:26.000000000 +0000
@@ -8,7 +8,7 @@
  * See Documentation/DMA-mapping.txt for the interface specification.
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $
+ * $Id: pci-gart.c,v 1.20 2003/03/12 08:23:29 ak Exp $
  */
 
 /* 
@@ -19,9 +19,12 @@
 
 possible future tuning: 
  fast path for sg streaming mappings 
- more intelligent flush strategy - flush only a single NB?
+ more intelligent flush strategy - flush only a single NB? flush only when
+ gart area fills up and alloc_iommu wraps. 
+ don't flush on allocation - need to unmap the gart area first to avoid prefetches
+ by the CPU
  move boundary between IOMMU and AGP in GART dynamically
- could use exact fit in the gart in alloc_consistent, not order of two.
+  
 */ 
 
 #include <linux/config.h>
@@ -49,7 +52,11 @@
 
 int no_iommu; 
 static int no_agp; 
+#ifdef CONFIG_IOMMU_DEBUG
 int force_mmu = 1;
+#else
+int force_mmu = 0;
+#endif
 
 extern int fallback_aper_order;
 extern int fallback_aper_force;
@@ -58,11 +65,10 @@
 static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
 
-#define GPTE_MASK 0xfffffff000
 #define GPTE_VALID    1
 #define GPTE_COHERENT 2
-#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag))
-#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28))
+#define GPTE_ENCODE(x) (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
+#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
 
 #define for_all_nb(dev) \
 	pci_for_each_dev(dev) \
@@ -129,7 +135,7 @@
 {
 	void *memory;
 	int gfp = GFP_ATOMIC;
-	int order, i;
+	int i;
 	unsigned long iommu_page;
 
 	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
@@ -139,15 +145,15 @@
 	 * First try to allocate continuous and use directly if already 
 	 * in lowmem. 
 	 */ 
-	order = get_order(size);
-	memory = (void *)__get_free_pages(gfp, order);
+	size = round_up(size, PAGE_SIZE); 
+	memory = (void *)__get_free_pages(gfp, get_order(size));
 	if (memory == NULL) {
 		return NULL; 
 	} else {
 		int high = (unsigned long)virt_to_bus(memory) + size
 			>= 0xffffffff;
 		int mmu = high;
-		if (force_mmu) 
+		if (force_mmu && !(gfp & GFP_DMA)) 
 			mmu = 1;
 		if (no_iommu) { 
 			if (high) goto error;
@@ -160,19 +166,21 @@
 		}
 	} 
 
-	iommu_page = alloc_iommu(1<<order);
+	size >>= PAGE_SHIFT;
+
+	iommu_page = alloc_iommu(size);
 	if (iommu_page == -1)
 		goto error; 
 
    	/* Fill in the GATT, allocating pages as needed. */
-	for (i = 0; i < 1<<order; i++) { 
+	for (i = 0; i < size; i++) { 
 		unsigned long phys_mem; 
 		void *mem = memory + i*PAGE_SIZE;
 		if (i > 0) 
 			atomic_inc(&virt_to_page(mem)->count); 
 		phys_mem = virt_to_phys(mem); 
-		BUG_ON(phys_mem & ~PTE_MASK); 
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); 
 	} 
 
 	flush_gart();
@@ -180,7 +188,7 @@
 	return memory; 
 	
  error:
-	free_pages((unsigned long)memory, order); 
+	free_pages((unsigned long)memory, get_order(size)); 
 	return NULL; 
 }
 
@@ -192,30 +200,32 @@
 			 void *vaddr, dma_addr_t bus)
 {
 	u64 pte;
-	int order = get_order(size);
 	unsigned long iommu_page;
 	int i;
 
+	size = round_up(size, PAGE_SIZE); 
 	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 
-		free_pages((unsigned long)vaddr, order); 		
+		free_pages((unsigned long)vaddr, get_order(size)); 		
 		return;
 	} 
+	size >>= PAGE_SHIFT;
 	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;
-	for (i = 0; i < 1<<order; i++) {
+	for (i = 0; i < size; i++) {
 		pte = iommu_gatt_base[iommu_page + i];
 		BUG_ON((pte & GPTE_VALID) == 0); 
 		iommu_gatt_base[iommu_page + i] = 0; 		
 		free_page((unsigned long) __va(GPTE_DECODE(pte)));
 	} 
 	flush_gart(); 
-	free_iommu(iommu_page, 1<<order);
+	free_iommu(iommu_page, size);
 }
 
 #ifdef CONFIG_IOMMU_LEAK
 /* Debugging aid for drivers that don't free their IOMMU tables */
 static void **iommu_leak_tab; 
 static int leak_trace;
-int iommu_leak_dumppages = 20; 
+int iommu_leak_pages = 20; 
+extern unsigned long printk_address(unsigned long);
 void dump_leak(void)
 {
 	int i;
@@ -223,10 +233,13 @@
 	if (dump || !iommu_leak_tab) return;
 	dump = 1;
 	show_stack(NULL);
-	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_dumppages); 
-	for (i = 0; i < iommu_leak_dumppages; i++) 
-		printk("[%lu: %lx] ",
-		       iommu_pages-i,(unsigned long) iommu_leak_tab[iommu_pages-i]); 
+	/* Very crude. dump some from the end of the table too */ 
+	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_pages); 
+	for (i = 0; i < iommu_leak_pages; i+=2) {
+		printk("%lu: ", iommu_pages-i);
+		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);
+		printk("%c", (i+1)%2 == 0 ? '\n' : ' '); 
+	} 
 	printk("\n");
 }
 #endif
@@ -274,7 +287,8 @@
 	return mmu; 
 }
 
-dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
+dma_addr_t __pci_map_single(struct pci_dev *dev, void *addr, size_t size,
+			    int dir, int flush)
 { 
 	unsigned long iommu_page;
 	unsigned long phys_mem, bus;
@@ -286,7 +300,7 @@
 	if (!need_iommu(dev, phys_mem, size))
 		return phys_mem; 
 
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + ((u64)addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 
 	iommu_page = alloc_iommu(npages); 
 	if (iommu_page == -1) {
@@ -296,13 +310,18 @@
 
 	phys_mem &= PAGE_MASK;
 	for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) {
-		BUG_ON(phys_mem & ~PTE_MASK); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
 		
 		/* 
 		 * Set coherent mapping here to avoid needing to flush
 		 * the caches on mapping.
 		 */
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT);
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem);
+
+#ifdef CONFIG_IOMMU_DEBUG
+		/* paranoia check */
+		BUG_ON(GPTE_DECODE(iommu_gatt_base[iommu_page+i]) != phys_mem); 
+#endif
 
 #ifdef CONFIG_IOMMU_LEAK
 		/* XXX need eventually caller of pci_map_sg */
@@ -310,6 +329,7 @@
 			iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); 
 #endif
 	}
+	if (flush)
 	flush_gart(); 
 
 	bus = iommu_bus_base + iommu_page*PAGE_SIZE; 
@@ -328,7 +348,7 @@
 	    dma_addr > iommu_bus_base + iommu_size)
 		return;
 	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + (dma_addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 	for (i = 0; i < npages; i++) { 
 		iommu_gatt_base[iommu_page + i] = 0; 
 #ifdef CONFIG_IOMMU_LEAK
@@ -340,7 +360,7 @@
 	free_iommu(iommu_page, npages);
 }
 
-EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(__pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -523,6 +543,8 @@
    off   don't use the IOMMU
    leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
    memaper[=order] allocate an own aperture over RAM with size 32MB^order.
+   noforce don't force IOMMU usage. Should be fastest.
+   force  Force IOMMU and turn on unmap debugging.
 */
 __init int iommu_setup(char *opt) 
 { 
@@ -545,8 +567,13 @@
 			    fallback_aper_order = arg;
 	    } 
 #ifdef CONFIG_IOMMU_LEAK
-	    if (!memcmp(p,"leak", 4))
+	    if (!memcmp(p,"leak", 4)) { 
 		    leak_trace = 1;
+		    p += 4; 
+		    if (*p == '=') ++p;
+		    if (isdigit(*p) && get_option(&p, &arg))
+			    iommu_leak_pages = arg;
+	    } else
 #endif
 	    if (isdigit(*p) && get_option(&p, &arg)) 
 		    iommu_size = arg;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-irq.c linux-2.4.21-rc3/arch/x86_64/kernel/pci-irq.c
--- linux-2.4.20/arch/x86_64/kernel/pci-irq.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/pci-irq.c	2003-05-22 22:06:27.000000000 +0000
@@ -742,9 +742,15 @@
 void pcibios_enable_irq(struct pci_dev *dev)
 {
 		u8 pin;
+	extern int interrupt_line_quirk;
+
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
 			char *msg;
+		/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
+		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
+			return;
+
 			if (io_apic_assign_pci_irqs)
 				msg = " Probably buggy MP table.";
 			else if (pci_probe & PCI_BIOS_IRQ_SCAN)
@@ -754,4 +760,8 @@
 			printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
 			       'A' + pin - 1, dev->slot_name, msg);
 	}
+	/* VIA bridges use interrupt line for apic/pci steering across
+	   the V-Link */
+	else if (interrupt_line_quirk)
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c linux-2.4.21-rc3/arch/x86_64/kernel/pci-x86_64.c
--- linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/pci-x86_64.c	2003-05-22 22:06:49.000000000 +0000
@@ -136,8 +136,7 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-		       unsigned long align)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
@@ -313,9 +312,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
 		if (!(mask & (1<<idx)))
 			continue;
-		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h linux-2.4.21-rc3/arch/x86_64/kernel/pci-x86_64.h
--- linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/pci-x86_64.h	2003-05-22 22:06:25.000000000 +0000
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *, int);
+int pcibios_enable_resources(struct pci_dev *, int mask);
 
 /* pci-pc.c */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/process.c linux-2.4.21-rc3/arch/x86_64/kernel/process.c
--- linux-2.4.20/arch/x86_64/kernel/process.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/process.c	2003-05-22 22:06:41.000000000 +0000
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.57 2002/09/12 12:56:36 ak Exp $
+ *  $Id: process.c,v 1.64 2003/03/31 15:11:26 ak Exp $
  */
 
 /*
@@ -242,10 +242,9 @@
 	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
 	 * other OSs see a clean IRQ state.
 	 */
-	if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD)
 		smp_send_stop();
-	disable_IO_APIC();
 #endif
+	disable_IO_APIC();
 	/* Could do reset through the northbridge of the Hammer here. */
 
 	/* rebooting needs to touch the page at absolute addr 0 */
@@ -275,6 +274,8 @@
 		pm_power_off();
 }
 
+extern int printk_address(unsigned long); 
+
 /* Prints also some state that isn't saved in the pt_regs */ 
 void show_regs(struct pt_regs * regs)
 {
@@ -284,8 +285,9 @@
 
 	printk("\n");
 	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
-	printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip);
-	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
+	printk("RIP: %04lx:", regs->cs & 0xffff);
+	printk_address(regs->rip); 
+	printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
 	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
 	       regs->rax, regs->rbx, regs->rcx);
 	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
@@ -316,6 +318,8 @@
 	       fs,fsindex,gs,gsindex,shadowgs); 
 	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
 	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+	show_trace(&regs->rsp);
 }
 
 /*
@@ -336,37 +340,6 @@
 }
 
 /* 
- * Reloading %gs is a bit complicated because the kernel relies on it 
- * This includes the exception handlers, so we cannot take any exceptions
- * while doing this. Check the new gs value manually for validity and only
- * then load it. This needs locking again parallel CPUs that share the same
- * LDT. This has to be done in the context switch iff %gs changes.
- */
-void load_gs_index(unsigned gs)
-{
-	struct mm_struct *mm = current->mm;
-	int access; 
-	/* paranoia: */
-	if ((gs & 3) != 2) gs = 0;
-	if (mm) 
-		read_lock(&mm->context.ldtlock); 
-	asm volatile("pushf\n\t" 
-		     "cli\n\t"
-		     "swapgs\n\t"
-		     /* cannot take any exception until the next swapgs */
-		     "lar %1,%0\n\t"
-		     "jnz 1f\n\t"
-		     "movl %1,%%eax\n\t"
-		     "movl %%eax,%%gs\n\t"
-		     "jmp 2f\n\t"
-		     "1: movl %2,%%gs\n\t"
-		     "2: swapgs\n\t"
-		     "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); 
-	if (mm)
-		read_unlock(&mm->context.ldtlock);
-}
-	
-/*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
@@ -486,10 +459,6 @@
 /*
  *	switch_to(x,y) should switch tasks from x to y.
  *
- * We fsave/fwait so that an exception goes off at the right time
- * (as a call from the fsave or fwait in effect) rather than to
- * the wrong process. 
- * 
  * This could still be optimized: 
  * - fold all the options into a flag word and test it with a single test.
  * - could test fs/gs bitsliced
@@ -520,29 +489,37 @@
 
 	/* 
 	 * Switch FS and GS.
-	 * XXX Check if this is safe on SMP (!= -> |)
 	 */
 	{ 
-		unsigned int fsindex;
-
+		unsigned fsindex;
 		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
-		if (unlikely(fsindex != next->fsindex)) /* or likely? */
+		/* segment register != 0 always requires a reload. 
+		   also reload when it has changed. 
+		   when prev process used 64bit base always reload
+		   to avoid an information leak. */
+		if (unlikely((fsindex | next->fsindex) || prev->fs)) {
 			loadsegment(fs, next->fsindex);
-		if (unlikely(fsindex != prev->fsindex))
+			/* check if the user use a selector != 0
+			 * if yes clear 64bit base, since overloaded base
+			 * is allways mapped to the Null selector
+			 */
+			if (fsindex)
 			prev->fs = 0; 
-		if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
+		}
+		/* when next process has a 64bit base use it */
+		if (next->fs) 
 			wrmsrl(MSR_FS_BASE, next->fs); 
 		prev->fsindex = fsindex;
 	}
 	{
-		unsigned int gsindex;
-
+		unsigned gsindex;
 		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
-		if (unlikely(gsindex != next->gsindex))
-			load_gs_index(next->gs); 
-		if (unlikely(gsindex != prev->gsindex)) 
+		if (unlikely((gsindex | next->gsindex) || prev->gs)) {
+			load_gs_index(next->gsindex);
+			if (gsindex)
 			prev->gs = 0;				
-		if (gsindex != prev->gsindex || prev->gs != next->gs)
+		}
+		if (next->gs)
 			wrmsrl(MSR_KERNEL_GS_BASE, next->gs); 
 		prev->gsindex = gsindex;
 	}
@@ -695,16 +672,18 @@
 	case ARCH_SET_GS:
 		if (addr >= TASK_SIZE) 
 			return -EPERM; 
-		asm volatile("movw %%gs,%0" : "=g" (current->thread.gsindex)); 
+		asm volatile("movl %0,%%gs" :: "r" (0)); 
+		current->thread.gsindex = 0;
 		current->thread.gs = addr;
 		ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); 
 		break;
 	case ARCH_SET_FS:
 		/* Not strictly needed for fs, but do it for symmetry
-		   with gs */
+		   with gs. */
 		if (addr >= TASK_SIZE)
 			return -EPERM; 
-		asm volatile("movw %%fs,%0" : "=g" (current->thread.fsindex)); 
+		asm volatile("movl %0,%%fs" :: "r" (0)); 
+		current->thread.fsindex = 0;
 		current->thread.fs = addr;
 		ret = checking_wrmsrl(MSR_FS_BASE, addr); 
 		break;
@@ -726,4 +705,3 @@
 	} 
 	return ret;	
 } 
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ptrace.c linux-2.4.21-rc3/arch/x86_64/kernel/ptrace.c
--- linux-2.4.20/arch/x86_64/kernel/ptrace.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/ptrace.c	2003-05-22 22:06:39.000000000 +0000
@@ -90,6 +90,8 @@
 	unsigned long regno, unsigned long value)
 {
 	unsigned long tmp; 
+	if (child->thread.flags & THREAD_IA32)
+		value &= 0xffffffff;
 	switch (regno) {
 		case offsetof(struct user_regs_struct,fs):
 			if (value && (value & 3) != 3)
@@ -144,6 +146,7 @@
 
 static unsigned long getreg(struct task_struct *child, unsigned long regno)
 {
+	unsigned long val; 
 	switch (regno) {
 		case offsetof(struct user_regs_struct, fs):
 			return child->thread.fsindex;
@@ -159,7 +162,10 @@
 			return child->thread.gs;
 		default:
 			regno = regno - sizeof(struct pt_regs);
-			return get_stack_long(child, regno);
+			val = get_stack_long(child, regno);
+			if (child->thread.flags & THREAD_IA32) 
+				val &= 0xffffffff;
+			return val;
 	}
 
 }
@@ -199,15 +205,10 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0) 
 		goto out_tsk;
+
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -228,8 +229,8 @@
 		unsigned long tmp;
 
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 || 
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 7) || addr < 0 || 
+		    addr > sizeof(struct user) - 7)
 			break;
 
 		tmp = 0;  /* Default return condition */
@@ -238,7 +239,7 @@
 		if(addr >= (long) &dummy->u_debugreg[0] &&
 		   addr <= (long) &dummy->u_debugreg[7]){
 			addr -= (long) &dummy->u_debugreg[0];
-			addr = addr >> 2;
+			addr = addr >> 3;
 			tmp = child->thread.debugreg[addr];
 		}
 		ret = put_user(tmp,(unsigned long *) data);
@@ -256,8 +257,8 @@
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 || 
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 7) || addr < 0 || 
+		    addr > sizeof(struct user) - 7)
 			break;
 
 		if (addr < sizeof(struct user_regs_struct)) {
@@ -278,6 +279,11 @@
 			  if(addr < (long) &dummy->u_debugreg[4] &&
 			     ((unsigned long) data) >= TASK_SIZE-3) break;
 			  
+			  if (addr == (long) &dummy->u_debugreg[6]) { 
+				  if (data >> 32) 
+					  goto out_tsk;
+			  }
+
 			  if(addr == (long) &dummy->u_debugreg[7]) {
 				  data &= ~DR_CONTROL_RESERVED;
 				  for(i=0; i<4; i++)
@@ -286,7 +292,7 @@
 			  }
 
 			  addr -= (long) &dummy->u_debugreg;
-			  addr = addr >> 2;
+			  addr = addr >> 3;
 			  child->thread.debugreg[addr] = data;
 			  ret = 0;
 		  }
@@ -401,8 +407,10 @@
 			ret = -EIO;
 			break;
 		}
-		child->used_math = 1;
+		unlazy_fpu(child);
 		ret = set_fpregs(child, (struct user_i387_struct *)data);
+		if (!ret) 
+			child->used_math = 1;
 		break;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/setup.c linux-2.4.21-rc3/arch/x86_64/kernel/setup.c
--- linux-2.4.20/arch/x86_64/kernel/setup.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/setup.c	2003-05-22 22:06:28.000000000 +0000
@@ -76,8 +76,6 @@
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
-static int disable_x86_fxsr __initdata = 0;
-
 char command_line[COMMAND_LINE_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
 
@@ -328,18 +326,6 @@
 	num_mappedpages = end_pfn;
 }
 
-#ifndef CONFIG_X86_TSC
-static int tsc_disable __initdata = 0;
-
-static int __init tsc_setup(char *str)
-{
-	tsc_disable = 1;
-	return 1;
-}
-
-__setup("notsc", tsc_setup);
-#endif
-
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
@@ -362,7 +348,6 @@
 
 	n = cpuid_eax(0x80000000);
 
-
 	if (n >= 0x80000005) {
 		if (n >= 0x80000006) 
 			cpuid(0x80000006, &eax_2, &ebx_2, &ecx_2, &dummy); 
@@ -376,16 +361,17 @@
 			printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line/%d way)\n",
 			       ecx_2>>16, ecx_2&0xFF, (ecx_2>>12)&0xf);
 			c->x86_cache_size = ecx_2 >> 16;
-		}		
-		printk(KERN_INFO "CPU: DTLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
-		       (ebx>>16)&0xff, (eax>>16)&0xff, 
-		       (ebx_2>>16)&0xfff, (eax_2>>16)&0xfff);
-		printk(KERN_INFO "CPU: ITLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
-		       ebx&0xff, (eax)&0xff, 
-		       (ebx_2)&0xfff, (eax_2)&0xfff);		
 		c->x86_tlbsize = ((ebx>>16)&0xff) + ((ebx_2>>16)&0xfff) + 
 			(ebx&0xff) + ((ebx_2)&0xfff);
 	}
+		if (n >= 0x80000007)
+			cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power); 
+		if (n >= 0x80000008) {
+			cpuid(0x80000008, &eax, &dummy, &dummy, &dummy); 
+			c->x86_virt_bits = (eax >> 8) & 0xff;
+			c->x86_phys_bits = eax & 0xff;
+		}
+	}
 }
 
 static int __init init_amd(struct cpuinfo_x86 *c)
@@ -427,15 +413,6 @@
 	char *model_names[16];
 };
 
-int __init x86_fxsr_setup(char * s)
-{
-	disable_x86_fxsr = 1;
-	return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
-
-
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
@@ -468,11 +445,11 @@
 		cpuid(0x00000001, &tfms, &misc, &junk,
 		      &c->x86_capability[0]);
 		c->x86 = (tfms >> 8) & 15;
-		if (c->x86 == 0xf)
-			c->x86 += (tfms >> 20) & 0xff;
 		c->x86_model = (tfms >> 4) & 15;
-		if (c->x86_model == 0xf)
+		if (c->x86 == 0xf) { /* extended */
+			c->x86 += (tfms >> 20) & 0xff;
 			c->x86_model += ((tfms >> 16) & 0xF) << 4; 
+		}
 		c->x86_mask = tfms & 15;
 		if (c->x86_capability[0] & (1<<19)) 
 			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
@@ -525,18 +502,6 @@
 	 * we do "generic changes."
 	 */
 
-	/* TSC disabled? */
-#ifndef CONFIG_X86_TSC
-	if ( tsc_disable )
-		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
-#endif
-
-	/* FXSR disabled? */
-	if (disable_x86_fxsr) {
-		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
-		clear_bit(X86_FEATURE_XMM, &c->x86_capability);
-	}
-
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
 	 * all CPUs; so make sure that we indicate which features are
@@ -606,6 +571,12 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	};
+	static char *x86_power_flags[] = { 
+		"ts",	/* temperature sensor */
+		"fid",  /* frequency id control */
+		"vid",  /* voltage id control */
+		"ttp",  /* thermal trip */
+	};
 
 #ifdef CONFIG_SMP
 	if (!(cpu_online_map & (1<<(c-cpu_data))))
@@ -659,7 +630,22 @@
 		seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
 	seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
 
-	seq_printf(m, "\n"); 
+	seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", 
+		   c->x86_phys_bits, c->x86_virt_bits);
+
+	seq_printf(m, "power management:");
+	{
+		int i;
+		for (i = 0; i < 32; i++) 
+			if (c->x86_power & (1 << i)) {
+				if (i < ARRAY_SIZE(x86_power_flags))
+					seq_printf(m, " %s", x86_power_flags[i]);
+				else
+					seq_printf(m, " [%d]", i);
+			}
+	}
+
+	seq_printf(m, "\n\n"); 
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/setup64.c linux-2.4.21-rc3/arch/x86_64/kernel/setup64.c
--- linux-2.4.20/arch/x86_64/kernel/setup64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/setup64.c	2003-05-22 22:06:52.000000000 +0000
@@ -3,7 +3,7 @@
  * Copyright (C) 1995  Linus Torvalds
  * Copyright 2001, 2002 SuSE Labs / Andi Kleen.
  * See setup.c for older changelog.
- * $Id: setup64.c,v 1.15 2002/09/05 15:25:43 ak Exp $
+ * $Id: setup64.c,v 1.19 2003/02/21 19:37:21 ak Exp $
  */ 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -31,18 +31,17 @@
 struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; 
 struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
 
-unsigned long __supported_pte_mask = ~_PAGE_NX; 
+unsigned long __supported_pte_mask = ~0UL; 
 static int do_not_nx = 1; 
 
 char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
 
-
 static int __init nonx_setup(char *str)
 {
-	if (strstr(str,"off")) { 
+	if (!strncmp(str,"off",3)) { 
 		__supported_pte_mask &= ~_PAGE_NX; 
 		do_not_nx = 1; 
-	} else if (strstr(str, "on")) { 
+	} else if (!strncmp(str, "on",3)) { 
 		do_not_nx = 0; 
 		__supported_pte_mask |= _PAGE_NX; 
 	} 
@@ -108,10 +107,10 @@
 
 	/* CPU 0 is initialised in head64.c */
 	if (nr != 0) {
-		estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); 
+		pda_init(nr);
+		estacks = (char *)__get_free_pages(GFP_ATOMIC, EXCEPTION_STK_ORDER); 
 		if (!estacks)
 			panic("Can't allocate exception stacks for CPU %d\n",nr);
-		pda_init(nr);  
 	} else 
 		estacks = boot_exception_stacks; 
 
@@ -145,12 +144,10 @@
 	wrmsrl(MSR_CSTAR, ia32_cstar_target); 
 #endif
 
-	if (!do_not_nx) { 
 		rdmsrl(MSR_EFER, efer); 
-		if (!(efer & EFER_NX)) { 
+	if (!(efer & EFER_NX) || do_not_nx) { 
 			__supported_pte_mask &= ~_PAGE_NX; 
 		} 
-	}
 
 	t->io_map_base = INVALID_IO_BITMAP_OFFSET;	
 	memset(t->io_bitmap, 0xff, sizeof(t->io_bitmap));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/signal.c linux-2.4.21-rc3/arch/x86_64/kernel/signal.c
--- linux-2.4.20/arch/x86_64/kernel/signal.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/signal.c	2003-05-22 22:06:27.000000000 +0000
@@ -8,7 +8,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2001   x86-64 support by Andi Kleen
  * 
- *  $Id: signal.c,v 1.35 2002/07/29 10:34:03 ak Exp $
+ *  $Id: signal.c,v 1.42 2003/02/24 21:06:02 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -29,6 +29,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/proto.h>
 
 #define DEBUG_SIG 0
 
@@ -63,8 +64,6 @@
 		/* First 32bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
 		case __SI_CHLD >> 16:
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
@@ -139,13 +138,7 @@
 	if ((regs->x >> 48)  != 0 && (regs->x >> 48) != 0xffff) \
 				regs->x = 0; 
 
-	{ 
-		unsigned int seg; 
-		err |= __get_user(seg, &sc->gs); 
-		load_gs_index(seg); 
-		err |= __get_user(seg, &sc->fs);
-		loadsegment(fs,seg);
-	}
+	/* fs and gs are ignored because we cannot handle the 64bit base easily */ 
 
 	COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx);
 	COPY(rdx); COPY(rcx); COPY_CANON(rip);
@@ -232,10 +225,8 @@
 	struct task_struct *me = current;
 
 	tmp = 0;
-	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->gs);
-	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->fs);
+	err |= __put_user(0, &sc->gs);
+	err |= __put_user(0, &sc->fs);
 
 	err |= __put_user(regs->rdi, &sc->rdi);
 	err |= __put_user(regs->rsi, &sc->rsi);
@@ -264,12 +255,6 @@
 	return err;
 }
 
-/*
- * Determine which stack to use..
- */
-#define round_down(p, r) ((void *)  ((unsigned long)((p) - (r) + 1) & ~((r)-1)))
-
-
 static void * 
 get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
 {
@@ -279,34 +264,35 @@
 	rsp = regs->rsp - 128;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
+	/* may need to subtract redzone there too */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (! sas_ss_flags(rsp) == 0)
+		if (sas_ss_flags(rsp) == 0)
 			rsp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
-	return round_down(rsp - size, 16); 	
+	return (void *)round_down(rsp - size, 16); 	
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	struct rt_sigframe *frame = NULL;
-	struct _fpstate *fp = NULL; 
+	struct rt_sigframe *frame;
+	struct _fpstate *fp; 
 	int err = 0;
 
 	if (current->used_math) {
 		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
-		frame = round_down((char *)fp - sizeof(struct rt_sigframe), 16) - 8;
+		frame = (void *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
 		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
 			goto give_sigsegv;
 		}
 		if (save_i387(fp) < 0) 
 			err |= -1; 
-	}
-
-	if (!frame)
+	} else {
 		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
+		fp = NULL;
+	}
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
 		goto give_sigsegv;
@@ -400,7 +386,7 @@
 #endif
 
 	/* Are we from a system call? */
-	if (regs->orig_rax >= 0) {
+	if ((long)regs->orig_rax >= 0) {
 		/* If so, check system call restarting.. */
 		switch (regs->rax) {
 			case -ERESTARTNOHAND:
@@ -563,8 +549,8 @@
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		__asm__("movq %0,%%db7"	: : "r" (current->thread.debugreg[7]));
-
+		if (current->thread.debugreg[7])
+			asm volatile("movq %0,%%db7" :: "r" (current->thread.debugreg[7]));
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/smp.c linux-2.4.21-rc3/arch/x86_64/kernel/smp.c
--- linux-2.4.20/arch/x86_64/kernel/smp.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/smp.c	2003-05-22 22:06:40.000000000 +0000
@@ -3,6 +3,7 @@
  *
  *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
  *	(c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ *	(c) 2002,2003 Andi Kleen, SuSE Labs.
  *
  *	This code is released under the GNU General Public License version 2 or
  *	later.
@@ -114,8 +115,6 @@
 static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector)
 {
 	unsigned int icr =  APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
-	if (vector == KDB_VECTOR) 
-		icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI; 		
 	return icr;
 }
 
@@ -411,11 +410,6 @@
 	do_flush_tlb_all_local();
 }
 
-void smp_kdb_stop(void)
-{
-	send_IPI_allbutself(KDB_VECTOR);
-} 
-
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -553,3 +547,25 @@
 	}
 }
 
+/* Slow. Should be only used for debugging. */
+int slow_smp_processor_id(void)
+{ 
+	int stack_location;
+	unsigned long sp = (unsigned long)&stack_location; 
+	int offset = 0, cpu;
+
+	for (offset = 0; (cpu_online_map >> offset); offset = cpu + 1) { 
+		cpu = ffz(~(cpu_online_map >> offset));
+
+		if (sp >= (u64)cpu_pda[cpu].irqstackptr - IRQSTACKSIZE && 
+		    sp <= (u64)cpu_pda[cpu].irqstackptr)
+			return cpu;
+
+		unsigned long estack = init_tss[cpu].ist[0] - EXCEPTION_STKSZ;
+		if (sp >= estack && sp <= estack+(1<<(PAGE_SHIFT+EXCEPTION_STK_ORDER)))
+			return cpu;			
+	}
+
+	return stack_smp_processor_id();
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/smpboot.c linux-2.4.21-rc3/arch/x86_64/kernel/smpboot.c
--- linux-2.4.20/arch/x86_64/kernel/smpboot.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/smpboot.c	2003-05-22 22:06:51.000000000 +0000
@@ -76,6 +76,8 @@
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
+extern void time_init_smp(void);
+
 /*
  * Setup routine for controlling SMP activation
  *
@@ -236,12 +238,16 @@
 		 */
 		atomic_inc(&tsc_count_start);
 
+		sync_core();
 		rdtscll(tsc_values[smp_processor_id()]);
+
 		/*
 		 * We clear the TSC in the last loop:
 		 */
-		if (i == NR_LOOPS-1)
+
+		if (i == NR_LOOPS-1) {
 			write_tsc(0, 0);
+		}
 
 		/*
 		 * Wait for all APs to leave the synchronization point:
@@ -302,6 +308,7 @@
 		atomic_inc(&tsc_count_start);
 		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
 
+		sync_core();
 		rdtscll(tsc_values[smp_processor_id()]);
 		if (i == NR_LOOPS-1)
 			write_tsc(0, 0);
@@ -403,8 +410,6 @@
 	 */
  	smp_store_cpu_info(cpuid);
 
-	notify_die(DIE_CPUINIT, "cpuinit", NULL, 0);
-
 	/*
 	 * Allow the master to continue.
 	 */
@@ -772,7 +777,7 @@
 static __init void smp_tune_scheduling (void)
 {
 	unsigned long cachesize;       /* kB   */
-	unsigned long bandwidth = 350; /* MB/s */
+	unsigned long bandwidth = 2000; /* MB/s */
 	/*
 	 * Rough estimation for SMP scheduling, this is the number of
 	 * cycles it takes for a fully memory-limited process to flush
@@ -801,6 +806,8 @@
 		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
 
+	cacheflush_time *= 10;  /* Add an NUMA factor */
+
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
 		(long)cacheflush_time/(cpu_khz/1000),
 		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
@@ -888,6 +895,7 @@
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
 		smp_num_cpus = 1;
+		apic_disabled = 1;
 		goto smp_done;
 	}
 
@@ -902,6 +910,7 @@
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
 		smp_num_cpus = 1;
+		apic_disabled = 1;
 		goto smp_done;
 	}
 
@@ -989,6 +998,8 @@
 	 */
 	if (!skip_ioapic_setup && nr_ioapics)
 		setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 
 	/*
 	 * Set up all local APIC timers in the system:
@@ -1003,4 +1014,5 @@
 
 smp_done:
 	zap_low_mappings();
+	time_init_smp();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c linux-2.4.21-rc3/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/sys_x86_64.c	2003-05-22 22:06:25.000000000 +0000
@@ -65,23 +65,34 @@
 	return error;
 }
 
+
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct *vma;
 	unsigned long end = TASK_SIZE;
 
-	if (current->thread.flags & THREAD_IA32)
-		flags |= MAP_32BIT; 
-	if (flags & MAP_32BIT)
-		end = 0xffffffff-1;
-	if (len > end)
-		return -ENOMEM;
-	if (!addr) { 
-		addr = TASK_UNMAPPED_64;
-		if (flags & MAP_32BIT) {
+	if (current->thread.flags & THREAD_IA32) {
+		if (!addr) 
 			addr = TASK_UNMAPPED_32;
+		end = 0xffff0000;
+	} else if (flags & MAP_32BIT) { 
+		/* This is usually used needed to map code in small
+		   model: it needs to be in the first 31bit. Limit it
+		   to that.  This means we need to move the unmapped
+		   base down for this case.  This may give conflicts
+		   with the heap, but we assume that malloc falls back
+		   to mmap. Give it 1GB of playground for now. -AK */ 
+		if (!addr) 
+			addr = 0x40000000; 
+		end = 0x80000000;		
+	} else { 
+		if (!addr) 
+			addr = TASK_UNMAPPED_64; 
+		end = TASK_SIZE; 
 		}
-	} 
+
+	if (len > end)
+		return -ENOMEM;
 	addr = PAGE_ALIGN(addr);
 
 	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/syscall.c linux-2.4.21-rc3/arch/x86_64/kernel/syscall.c
--- linux-2.4.20/arch/x86_64/kernel/syscall.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/syscall.c	2003-05-22 22:06:40.000000000 +0000
@@ -3,6 +3,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <linux/config.h>
 
 #define __NO_STUBS
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/time.c linux-2.4.21-rc3/arch/x86_64/kernel/time.c
--- linux-2.4.20/arch/x86_64/kernel/time.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/time.c	2003-05-22 22:06:52.000000000 +0000
@@ -12,8 +12,6 @@
  *
  */
 
-#define HPET_BIOS_SUPPORT_WORKING
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -26,39 +24,47 @@
 
 extern rwlock_t xtime_lock;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+unsigned long hpet_address;
 unsigned long hpet_period;				/* fsecs / HPET clock */
-unsigned long hpet_tick;				/* HPET clocks / interrupt */
-int hpet_report_lost_ticks;				/* command line option */
+unsigned int hpet_tick;					/* HPET clocks / interrupt */
+unsigned long vxtime_hz = 1193182;
+int report_lost_ticks;					/* command line option */
 
-struct hpet_data __hpet __section_hpet;			/* address, quotient, trigger, hz */
+struct vxtime_data __vxtime __section_vxtime;		/* data for vsyscall */
 
 volatile unsigned long __jiffies __section_jiffies;
 unsigned long __wall_jiffies __section_wall_jiffies;
 struct timeval __xtime __section_xtime;
 struct timezone __sys_tz __section_sys_tz;
 
+static inline void rdtscll_sync(unsigned long *tsc)
+{
+	sync_core();
+	rdtscll(*tsc);
+}
+
 /*
  * do_gettimeoffset() returns microseconds since last timer interrupt was
- * triggered by hardware. A memory read of HPET is slower than a register read
- * of TSC, but much more reliable. It's also synchronized to the timer
- * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
- * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
- * This is not a problem, because jiffies hasn't updated either. They are bound
- * together by xtime_lock.
+ * triggered by hardware. 
  */
 
-static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long timeoffset = 0;
-
-inline unsigned int do_gettimeoffset(void)
+static unsigned int do_gettimeoffset_tsc(void)
 {
 	unsigned long t;
-	rdtscll(t);	
-	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
+	rdtscll_sync(&t);	
+	return ((t  - vxtime.last_tsc) * vxtime.tsc_quot) >> 32;
 }
 
+static unsigned int do_gettimeoffset_hpet(void)
+{
+	return ((hpet_readl(HPET_COUNTER) - vxtime.last) * vxtime.quot) >> 32;
+}
+
+unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc;
+
 /*
  * This version of gettimeofday() has microsecond resolution and better than
  * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
@@ -67,21 +73,20 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags, t;
+	unsigned long sequence;
  	unsigned int sec, usec;
 
-	read_lock_irqsave(&xtime_lock, flags);
-	spin_lock(&time_offset_lock);
+	do { 
+		sequence = __vxtime_sequence[1];
+		rmb();
 
 	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
+	usec = xtime.tv_usec
+		+ (jiffies - wall_jiffies) * tick
+			+ do_gettimeoffset();
 
-	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
-	if (t > timeoffset) timeoffset = t;
-	usec += timeoffset;
-
-	spin_unlock(&time_offset_lock);
-	read_unlock_irqrestore(&xtime_lock, flags);
+		rmb(); 
+	} while (sequence != __vxtime_sequence[0]);
 
 	tv->tv_sec = sec + usec / 1000000;
 	tv->tv_usec = usec % 1000000;
@@ -98,8 +103,8 @@
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
 
-	tv->tv_usec -= do_gettimeoffset() +
-		(jiffies - wall_jiffies) * tick;
+	tv->tv_usec -= (jiffies - wall_jiffies) * tick
+			+ do_gettimeoffset();
 
 	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
@@ -201,15 +206,55 @@
 	vxtime_lock();
 
 	{
-		unsigned long t;
+		long tsc;
+		int delay, offset = 0;
+
+		if (hpet_address) {
+
+			offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			delay = hpet_readl(HPET_COUNTER) - offset;
+
+		} else {
+
+			spin_lock(&i8253_lock);
+			outb_p(0x00, 0x43);
+			delay = inb_p(0x40);
+			delay |= inb(0x40) << 8;
+			spin_unlock(&i8253_lock);
+			delay = LATCH - 1 - delay;
+		}
+
+		rdtscll_sync(&tsc);
+
+		if (vxtime.mode == VXTIME_HPET) {
+
+			if (offset - vxtime.last > hpet_tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: Lost %d timer tick(s)! (rip %016lx)\n",
+						(offset - vxtime.last) / hpet_tick - 1, regs->rip);
+				jiffies += (offset - vxtime.last) / hpet_tick - 1;
+			}
+
+			vxtime.last = offset;
+
+		} else {
+
+			offset = (((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) - tick;
+
+			if (offset > tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: lost %ld tick(s) (rip %016lx)\n",
+						 offset / tick, regs->rip);
+				jiffies += offset / tick;
+				offset %= tick;
+			}
 
-		rdtscll(t);
-		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
-		if (hpet.offset >= 1000000L / HZ)
-			hpet.offset = 0;
-		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
-				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
-		hpet.last_tsc = t;
+			vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot;
+
+			if ((((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) < offset)
+				vxtime.last_tsc = tsc - (((long)offset << 32) / vxtime.tsc_quot) - 1;
+
+		}
 	}
 
 /*
@@ -318,6 +363,7 @@
 	do {
 		__cli();
 		hpet_now = hpet_readl(HPET_COUNTER);
+		sync_core();
 		rdtscl(tsc_now);
 		__restore_flags(flags);
 	} while ((tsc_now - tsc_start) < TICK_COUNT && (hpet_now - hpet_start) < TICK_COUNT);
@@ -337,12 +383,10 @@
 static unsigned int __init pit_calibrate_tsc(void)
 {
 	unsigned long start, end;
-	unsigned long flags;
 
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
-	__save_flags(flags);
-	__cli();
+	spin_lock_irq(&i8253_lock);
 
 	outb(0xb0, 0x43);
 	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
@@ -352,7 +396,7 @@
 	while ((inb(0x61) & 0x20) == 0);
 	rdtscll(end);
 
-	__restore_flags(flags);
+	spin_unlock_irq(&i8253_lock);
 
 	return (end - start) / 50;
 }
@@ -361,9 +405,9 @@
 {
 	unsigned int cfg, id;
 
-	if (!hpet.address)
+	if (!hpet_address)
 		return -1;
-	set_fixmap_nocache(FIX_HPET_BASE, hpet.address);
+	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
 
 /*
  * Read the period, compute tick and quotient.
@@ -411,35 +455,106 @@
 
 void __init pit_init(void)
 {
+	spin_lock_irq(&i8253_lock);
 	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff, 0x40);	/* LSB */
 	outb_p(LATCH >> 8, 0x40);	/* MSB */
+	spin_unlock_irq(&i8253_lock);
 }
 
-int __init time_setup(char *str)
+static int __init time_setup(char *str)
 {
-	hpet_report_lost_ticks = 1;
+	report_lost_ticks = 1;
 	return 1;
 }
 
+/* Only used on SMP */
+static int notsc __initdata = 0; 
+
+static int __init notsc_setup(char *str)
+{ 
+#ifdef CONFIG_SMP
+	printk(KERN_INFO "notsc ignored on non SMP kernel\n"); 
+#endif
+	notsc = 1;
+	return 1;
+} 
+
 static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
 
 extern void __init config_acpi_tables(void);
 
 void __init time_init(void)
 {
+	char *timename;
+
+	config_acpi_tables();
+
+#ifdef HPET_HACK_ENABLE_DANGEROUS
+        if (!hpet_address) {
+		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base manually!\n");
+                outl(0x800038a0, 0xcf8);
+                outl(0xff000001, 0xcfc);
+                outl(0x800038a0, 0xcf8);
+                hpet_address = inl(0xcfc) & 0xfffffffe;
+		printk(KERN_WARNING "time.c: WARNING: Enabled HPET at at %#lx.\n", hpet_address);
+        }
+#endif
+
+#ifndef CONFIG_HPET_TIMER
+        hpet_address = 0;
+#endif
+
+	write_lock(&xtime_lock);
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
+	write_unlock(&xtime_lock);
 
-		printk(KERN_WARNING "time.c: HPET timer not found, precise timing unavailable.\n");
+	if (!hpet_init()) {
+                vxtime_hz = (1000000000000000L + hpet_period / 2) / hpet_period;
+                cpu_khz = hpet_calibrate_tsc();
+		timename = "HPET";
+	} else {
 		pit_init();
-		printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
-		setup_irq(0, &irq0);
 		cpu_khz = pit_calibrate_tsc();
-		printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+		timename = "PIT";
+	}
+
+	vxtime.mode = VXTIME_TSC;
+	vxtime.quot = (1000000L << 32) / vxtime_hz;
+	vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+	rdtscll_sync(&vxtime.last_tsc);
+
+	setup_irq(0, &irq0);
+
+        printk(KERN_INFO "time.c: Detected %ld.%06ld MHz %s timer.\n",
+		vxtime_hz / 1000000, vxtime_hz % 1000000, timename);
+	printk(KERN_INFO "time.c: Detected %d.%03d MHz TSC timer.\n",
 			cpu_khz / 1000, cpu_khz % 1000);
-	hpet.ticks = cpu_khz * (1000 / HZ);
-	rdtscll(hpet.last_tsc);
 }
 
+void __init time_init_smp(void)
+{
+	char *timetype;
+
+	if (hpet_address) {
+		if (notsc) { 
+			timetype = "HPET";
+			vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			vxtime.mode = VXTIME_HPET;
+			do_gettimeoffset = do_gettimeoffset_hpet;
+		} else {
+			timetype = "HPET/TSC";
+			vxtime.mode = VXTIME_TSC;
+			do_gettimeoffset = do_gettimeoffset_tsc;
+		}		
+	} else {
+			timetype = "PIT/TSC";
+			vxtime.mode = VXTIME_TSC;
+	}
+	printk(KERN_INFO "time.c: Using %s based timekeeping.\n", timetype);
+}
+
+__setup("notsc", notsc_setup);
 __setup("report_lost_ticks", time_setup);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/traps.c linux-2.4.21-rc3/arch/x86_64/kernel/traps.c
--- linux-2.4.20/arch/x86_64/kernel/traps.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/traps.c	2003-05-22 22:06:27.000000000 +0000
@@ -7,7 +7,7 @@
  *  Pentium III FXSR, SSE support
  *	Gareth Hughes <gareth@valinux.com>, May 2000
  *
- *  $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
+ *  $Id: traps.c,v 1.62 2003/03/14 16:06:35 ak Exp $
  */
 
 /*
@@ -71,6 +71,12 @@
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void call_debug(void);
 
+static inline void conditional_sti(struct pt_regs *regs)
+{
+	if (regs->eflags & X86_EFLAGS_IF)
+		__sti();
+}
+
 extern char iret_address[];
 
 struct notifier_block *die_chain;
@@ -95,7 +101,7 @@
 	} 
 	if (!strcmp(modname, "kernel"))
 		modname = delim = ""; 		
-        return printk("[%016lx%s%s%s%s%+ld]",
+        return printk("[<%016lx>]{%s%s%s%s%+ld}",
 		      address,delim,modname,delim,symname,address-symstart); 
 } 
 #else
@@ -143,7 +149,7 @@
 
 #endif
 
-static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) 
+unsigned long *in_exception_stack(int cpu, unsigned long stack) 
 { 
 	int k;
 	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
@@ -159,13 +165,12 @@
 {
 	unsigned long addr;
 	unsigned long *irqstack, *irqstack_end, *estack_end;
-	/* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
-	const int cpu = smp_processor_id();
+	const int cpu = safe_smp_processor_id();
 	int i;
 
 	printk("\nCall Trace: ");
 
-	i = 1;
+	i = 12;
 	estack_end = in_exception_stack(cpu, (unsigned long)stack); 
 	if (estack_end) { 
 		while (stack < estack_end) { 
@@ -243,7 +248,7 @@
 {
 	unsigned long *stack;
 	int i;
-	const int cpu = smp_processor_id();
+	const int cpu = safe_smp_processor_id();
 	unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
 	unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);    
 
@@ -271,22 +276,12 @@
 	show_trace((unsigned long *)rsp);
 }
 
-void dump_stack(void)
-{
-	show_stack(0);
-} 
-
 void show_registers(struct pt_regs *regs)
 {
 	int i;
 	int in_kernel = 1;
 	unsigned long rsp;
-#ifdef CONFIG_SMP
-	/* For SMP should get the APIC id here, just to protect against corrupted GS */ 
-	const int cpu = smp_processor_id(); 
-#else
-	const int cpu = 0;
-#endif	
+	const int cpu = safe_smp_processor_id(); 
 	struct task_struct *cur = cpu_pda[cpu].pcurrent; 
 
 	rsp = (unsigned long) (&regs->rsp);
@@ -350,13 +345,12 @@
 void die(const char * str, struct pt_regs * regs, long err)
 {
 	int cpu;
-	struct die_args args = { regs, str, err };
 	console_verbose();
-	notifier_call_chain(&die_chain,  DIE_DIE, &args); 
 	bust_spinlocks(1);
 	handle_BUG(regs);		
 	printk(KERN_EMERG "%s: %04lx\n", str, err & 0xffff);
-	cpu = smp_processor_id(); 
+ 	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+	cpu = safe_smp_processor_id(); 
 	/* racy, but better than risking deadlock. */ 
 	__cli();
 	if (!spin_trylock(&die_lock)) { 
@@ -369,7 +363,6 @@
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
-	notify_die(DIE_OOPS, (char *)str, regs, err);
 	do_exit(SIGSEGV);
 }
 
@@ -391,10 +384,12 @@
 static void do_trap(int trapnr, int signr, char *str, 
 		    struct pt_regs * regs, long error_code, siginfo_t *info)
 {
+	conditional_sti(regs);
+
 #if defined(CONFIG_CHECKING) && defined(CONFIG_LOCAL_APIC)
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + hard_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -407,7 +402,7 @@
 		struct task_struct *tsk = current;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = trapnr;
-		if (exception_trace)
+		if (exception_trace && trapnr != 3)
 			printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
 			       tsk->comm, tsk->pid, str,
 			       regs->rip,regs->rsp,error_code); 
@@ -424,11 +419,6 @@
 		unsigned long fixup = search_exception_table(regs->rip);
 		if (fixup) {
 			extern int exception_trace; 
-			if (0 && exception_trace)
-	       printk(KERN_ERR
-	             "%s: fixed kernel exception at %lx err:%ld\n",
-	             current->comm, regs->rip, error_code);
-		
 			regs->rip = fixup;
 		} else	
 			die(str, regs, error_code);
@@ -439,6 +429,8 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+		return; \
 	do_trap(trapnr, signr, str, regs, error_code, NULL); \
 }
 
@@ -450,10 +442,13 @@
 	info.si_errno = 0; \
 	info.si_code = sicode; \
 	info.si_addr = (void *)siaddr; \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)==NOTIFY_BAD) \
+		return; \
 	do_trap(trapnr, signr, str, regs, error_code, &info); \
 }
 
 DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->rip)
+DO_ERROR( 3, SIGTRAP, "int3", int3); 
 DO_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
@@ -466,25 +461,25 @@
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
 DO_ERROR(18, SIGSEGV, "reserved", reserved)
 
-asmlinkage void do_int3(struct pt_regs * regs, long error_code)
-{
-	if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD)
-		return;
-	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-}
-
 extern void dump_pagetable(unsigned long);
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+	conditional_sti(regs);
+
 #ifdef CONFIG_CHECKING
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
+			/* Avoid wakeup in printk in case this was triggered
+			   by the segment reloads in __switch_to. Otherwise
+			   the wake_up could deadlock on scheduler locks. */
+			oops_in_progress++;
 			printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
+			oops_in_progress--; 
 		}
 	}
 #endif
@@ -505,15 +500,11 @@
 		unsigned long fixup;
 		fixup = search_exception_table(regs->rip);
 		if (fixup) {
-			extern int exception_trace; 
-			if (exception_trace)
-				printk(KERN_ERR
-			       "%s: fixed kernel exception at %lx err:%ld\n",
-				       current->comm, regs->rip, error_code);
-
 			regs->rip = fixup;
 			return;
 		}
+		notify_die(DIE_GPF, "general protection fault", regs, error_code,
+			   13, SIGSEGV); 
 		die("general protection fault", regs, error_code);
 	}
 }
@@ -552,7 +543,7 @@
 {
 	unsigned char reason = inb(0x61);
 
-	++nmi_count(smp_processor_id());
+	++nmi_count(safe_smp_processor_id());
 	
 	if (!(reason & 0xc0)) {
 #if CONFIG_X86_LOCAL_APIC
@@ -561,16 +552,14 @@
 		 * so it must be the NMI watchdog.
 		 */
 		if (nmi_watchdog) {
-			nmi_watchdog_tick(regs);
+			nmi_watchdog_tick(regs, reason);
 			return;
 		}
 #endif
-		if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
-			return;
 		unknown_nmi_error(reason, regs);
 		return;
 	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD)
 		return; 
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
@@ -593,10 +582,15 @@
 	struct task_struct *tsk = current;
 	siginfo_t info;
 
+	asm("movq %%db6,%0" : "=r" (condition));
+
+	conditional_sti(regs);
+
 #ifdef CONFIG_CHECKING
 	{ 
+		/* XXX: interaction with debugger - could destroy gs */
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -605,16 +599,6 @@
 	}
 #endif
 
-	asm("movq %%db6,%0" : "=r" (condition));
-
-	if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
-		return; 
-
-	/* If the user set TF, it's simplest to clear it right away. */
-	/* AK: dubious check, likely wrong */
-	if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
-		goto clear_TF;
-
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7]) { 
@@ -647,14 +631,19 @@
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
-	info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip : 
-	                                        (void *)regs->rip;
+	if ((regs->cs & 3) == 0) 
+		goto clear_dr7; 
+
+	info.si_addr = (void *)regs->rip;
 	force_sig_info(SIGTRAP, &info, tsk);	
 clear_dr7:
-	asm("movq %0,%%db7"::"r"(0UL));
+	asm volatile("movq %0,%%db7"::"r"(0UL));
+	notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP);
 	return;
 
 clear_TF:
+	/* XXX: could cause spurious errors */
+	if (notify_die(DIE_DEBUG, "debug2", regs, error_code, 1, SIGTRAP) != NOTIFY_BAD)
 	regs->eflags &= ~TF_MASK;
 	return;
 }
@@ -721,6 +710,7 @@
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
+	conditional_sti(regs);
 	math_error((void *)regs->rip);
 }
 
@@ -780,6 +770,7 @@
 asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
 					  long error_code)
 {
+	conditional_sti(regs);
 	simd_math_error((void *)regs->rip);
 }
 
@@ -800,7 +791,7 @@
 	clts();			/* Allow maths ops (or we recurse) */
 
 	if (!me->used_math)
-		init_fpu();        
+		init_fpu(me);
 	restore_fpu_checking(&me->thread.i387.fxsave);
 	me->flags |= PF_USEDFPU;	/* So we fxsave on switch_to() */
 }
@@ -812,7 +803,7 @@
 
 void do_call_debug(struct pt_regs *regs) 
 { 
-	notify_die(DIE_CALL, "debug call", regs, 0); 
+	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); 
 } 
 
 #ifndef CONFIG_MCE
@@ -849,10 +840,6 @@
 	set_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
 
-	set_intr_gate(KDB_VECTOR, call_debug);
-       
-	notify_die(DIE_TRAPINIT, "traps initialized", 0, 0); 
-	
 	/*
 	 * Should be a barrier for any external CPU state.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/vsyscall.c linux-2.4.21-rc3/arch/x86_64/kernel/vsyscall.c
--- linux-2.4.20/arch/x86_64/kernel/vsyscall.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/vsyscall.c	2003-05-22 22:06:44.000000000 +0000
@@ -12,7 +12,7 @@
  *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
  *  jumping out of line if necessary.
  *
- *  $Id: vsyscall.c,v 1.19 2002/07/19 02:24:08 vojtech Exp $
+ *  $Id: vsyscall.c,v 1.26 2003/02/18 11:55:47 ak Exp $
  */
 
 /*
@@ -45,16 +45,15 @@
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/msr.h>
+#include <asm/unistd.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 
-long __vxtime_sequence[2] __section_vxtime_sequence;
-
-#undef USE_VSYSCALL
+#define force_inline inline __attribute__((always_inline))
 
-#ifdef USE_VSYSCALL
+long __vxtime_sequence[2] __section_vxtime_sequence;
 
-static inline void do_vgettimeofday(struct timeval * tv)
+static force_inline void do_vgettimeofday(struct timeval * tv)
 {
 	long sequence, t;
 	unsigned long sec, usec;
@@ -63,11 +62,22 @@
 		sequence = __vxtime_sequence[1];
 		rmb();
 
-		rdtscll(t);
 		sec = __xtime.tv_sec;
-		usec = __xtime.tv_usec +
-			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
-			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
+		usec = __xtime.tv_usec + (__jiffies - __wall_jiffies) * (1000000 / HZ);
+
+		switch (__vxtime.mode) {
+
+			case VXTIME_TSC:
+				sync_core();
+				rdtscll(t);
+				usec += (((t  - __vxtime.last_tsc) * __vxtime.tsc_quot) >> 32);
+				break;
+
+			case VXTIME_HPET:
+				usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) - __vxtime.last) * __vxtime.quot) >> 32;
+				break;
+
+		}
 
 		rmb();
 	} while (sequence != __vxtime_sequence[0]);
@@ -76,7 +86,8 @@
 	tv->tv_usec = usec % 1000000;
 }
 
-static inline void do_get_tz(struct timezone * tz)
+
+static force_inline void do_get_tz(struct timezone * tz)
 {
 	long sequence;
 
@@ -92,27 +103,15 @@
 
 static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
-	if (tv) do_vgettimeofday(tv);
-	if (tz) do_get_tz(tz);
-	return 0;
-}
-
-#else
+	if (tv)
+			do_vgettimeofday(tv);
 
-#include <asm/unistd.h>
+	if (tz)
+		do_get_tz(tz);
 
-static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
-{
-	int r;
-	asm volatile("syscall"
-		     : "=a" (r)
-		     : "0" (__NR_gettimeofday), "D" (tv), "S" (tz)
-		     : "r11", "rcx","memory");
-	return r;
+	return 0;
 }
 
-#endif
-
 static time_t __vsyscall(1) vtime(time_t * tp)
 {
 	struct timeval tv;
@@ -131,19 +130,18 @@
 	return -ENOSYS;
 }
 
+extern char vsyscall_syscall[], __vsyscall_0[];
+
 static void __init map_vsyscall(void)
 {
-	extern char __vsyscall_0;
-	unsigned long physaddr_page0 = (unsigned long) &__vsyscall_0 - __START_KERNEL_map;
-
+	unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
 	__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
-	if (hpet.address)
-		__set_fixmap(VSYSCALL_HPET, hpet.address, PAGE_KERNEL_VSYSCALL);
+	if (hpet_address)
+		__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL);
 }
 
 static int __init vsyscall_init(void)
 {
-	printk("VSYSCALL: consistency checks...");
 	if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))
 		panic("vgettimeofday link addr broken");
 	if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime))
@@ -151,10 +149,7 @@
 	if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))
 		panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE),
 			VSYSCALL_ADDR(0));
-	printk("passed...mapping...");
 	map_vsyscall();
-	printk("done.\n");
-
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.21-rc3/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/kernel/x8664_ksyms.c	2003-05-22 22:06:48.000000000 +0000
@@ -220,3 +220,6 @@
 EXPORT_SYMBOL(plat_node_data);
 EXPORT_SYMBOL(fake_node);
 #endif
+
+extern void int_ret_from_sys_call(void);
+EXPORT_SYMBOL(int_ret_from_sys_call); 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/clear_page.S linux-2.4.21-rc3/arch/x86_64/lib/clear_page.S
--- linux-2.4.20/arch/x86_64/lib/clear_page.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/clear_page.S	2003-05-22 22:06:24.000000000 +0000
@@ -1,16 +1,18 @@
-	#include <linux/linkage.h>
 
 /*
  * Zero a page. 	
  * rdi	page
  */			
-ENTRY(clear_page)
+	.globl clear_page
+	.p2align 4
+clear_page:
 	xorl   %eax,%eax
-	movl   $4096/128,%ecx
-	movl   $128,%edx
-loop:
+	movl   $4096/64,%ecx
+	.p2align 4
+.Lloop:
+	decl	%ecx
 #define PUT(x) movq %rax,x*8(%rdi) 
-	PUT(0)
+	movq %rax,(%rdi)
 	PUT(1)
 	PUT(2)
 	PUT(3)
@@ -18,17 +20,8 @@
 	PUT(5)
 	PUT(6)
 	PUT(7)
-	PUT(8)
-	PUT(9)
-	PUT(10)
-	PUT(11)
-	PUT(12)
-	PUT(13)
-	PUT(14)
-	PUT(15)
-	addq    %rdx,%rdi
-	decl	%ecx
-	jnz	loop
-	sfence	
+	leaq	64(%rdi),%rdi
+	jnz	.Lloop
+	nop
 	ret
 	    	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/copy_page.S linux-2.4.21-rc3/arch/x86_64/lib/copy_page.S
--- linux-2.4.20/arch/x86_64/lib/copy_page.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/copy_page.S	2003-05-22 22:06:24.000000000 +0000
@@ -1,70 +1,91 @@
-	#include <linux/linkage.h>
-	#include <linux/config.h>
-	#ifdef CONFIG_PREEMPT
-	#warning "check your fpu context saving!"
-	#endif
-
-/*
- * Copy a page. 
- *		
- * rdi destination page
- * rsi source page
- *		
- * src/dst must be aligned to 16 bytes.
- * 
- * Warning: in case of super lazy FP save this needs to be preempt_stop	
- */
+/* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
 	
+/* Don't use streaming store because it's better when the target
+   ends up in cache. */
+	    
+/* Could vary the prefetch distance based on SMP/UP */
+
 	.globl copy_page
-	.p2align
+	.p2align 4
 copy_page:
-	prefetchnta (%rsi) 
-	prefetchnta 64(%rsi)
-	    
-	movq %rsp,%rax
-	subq $16*4,%rsp
-	andq $~15,%rsp		
-	movdqa %xmm0,(%rsp) 
-	movdqa %xmm1,16(%rsp) 
-	movdqa %xmm2,32(%rsp) 
-	movdqa %xmm3,48(%rsp)
-	
-	movl   $(4096/128)-2,%ecx
-	movl   $128,%edx
-loop:
-	prefetchnta (%rsi) 
-	prefetchnta 64(%rsi) 
-loop_no_prefetch:	
-	movdqa (%rsi),%xmm0 	 			 
-	movdqa 16(%rsi),%xmm1
-	movdqa 32(%rsi),%xmm2 	 			 
-	movdqa 48(%rsi),%xmm3 	 			 
-	movntdq %xmm0,(%rdi)	 
-	movntdq %xmm1,16(%rdi)	 
-	movntdq %xmm2,32(%rdi)	 
-	movntdq %xmm3,48(%rdi)
-	
-	movdqa 64(%rsi),%xmm0 	 			 
-	movdqa 80(%rsi),%xmm1
-	movdqa 96(%rsi),%xmm2 	 			 
-	movdqa 112(%rsi),%xmm3 	 			 
-	movntdq %xmm0,64(%rdi)	 
-	movntdq %xmm1,80(%rdi)	 
-	movntdq %xmm2,96(%rdi)	 
-	movntdq %xmm3,112(%rdi)
+	prefetch (%rsi) 
+	prefetch 1*64(%rsi)
+	prefetch 2*64(%rsi)
+	prefetch 3*64(%rsi)
+	prefetch 4*64(%rsi)
+	prefetchw (%rdi) 
+	prefetchw 1*64(%rdi) 
+	prefetchw 2*64(%rdi) 
+	prefetchw 3*64(%rdi)
+	prefetchw 4*64(%rdi)
+
+	subq	$3*8,%rsp
+	movq	%rbx,(%rsp)
+	movq	%r12,1*8(%rsp)
+	movq	%r13,2*8(%rsp)
+			
+	movl	$(4096/64)-5,%ecx
+	.p2align 4
+.Loop64:	
+  	dec     %rcx
+
+	movq        (%rsi), %rax
+	movq      8 (%rsi), %rbx
+	movq     16 (%rsi), %rdx
+	movq     24 (%rsi), %r8
+	movq     32 (%rsi), %r9
+	movq     40 (%rsi), %r10
+	movq     48 (%rsi), %r11
+	movq     56 (%rsi), %r12
+
+	prefetch 5*64(%rsi)
+
+	movq     %rax,    (%rdi)
+	movq     %rbx,  8 (%rdi)
+	movq     %rdx, 16 (%rdi)
+	movq     %r8,  24 (%rdi)
+	movq     %r9,  32 (%rdi)
+	movq     %r10, 40 (%rdi)
+	movq     %r11, 48 (%rdi)
+	movq     %r12, 56 (%rdi)
 
-	addq   %rdx,%rdi	
-	addq   %rdx,%rsi
+	prefetchw 5*64(%rdi)
+
+	leaq    64 (%rsi), %rsi
+	leaq    64 (%rdi), %rdi
+
+	jnz     .Loop64
+
+	movl	$5,%ecx
+	.p2align 4
+.Loop2:	
 	decl   %ecx
-	jns    loop
-	cmpl   $-1,%ecx
-	je     loop_no_prefetch
-	
-	sfence
 
-	movdqa (%rsp),%xmm0
-	movdqa 16(%rsp),%xmm1
-	movdqa 32(%rsp),%xmm2
-	movdqa 48(%rsp),%xmm3
-	movq   %rax,%rsp
+	movq        (%rsi), %rax
+	movq      8 (%rsi), %rbx
+	movq     16 (%rsi), %rdx
+	movq     24 (%rsi), %r8
+	movq     32 (%rsi), %r9
+	movq     40 (%rsi), %r10
+	movq     48 (%rsi), %r11
+	movq     56 (%rsi), %r12
+
+	movq     %rax,    (%rdi)
+	movq     %rbx,  8 (%rdi)
+	movq     %rdx, 16 (%rdi)
+	movq     %r8,  24 (%rdi)
+	movq     %r9,  32 (%rdi)
+	movq     %r10, 40 (%rdi)
+	movq     %r11, 48 (%rdi)
+	movq     %r12, 56 (%rdi)
+	
+	leaq	64(%rdi),%rdi			
+	leaq	64(%rsi),%rsi			
+	
+	jnz	.Loop2		
+	
+	movq	(%rsp),%rbx
+	movq	1*8(%rsp),%r12
+	movq	2*8(%rsp),%r13
+	addq	$3*8,%rsp
 	ret
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/copy_user.S linux-2.4.21-rc3/arch/x86_64/lib/copy_user.S
--- linux-2.4.20/arch/x86_64/lib/copy_user.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/copy_user.S	2003-05-22 22:06:41.000000000 +0000
@@ -6,15 +6,12 @@
 
 #define FIX_ALIGNMENT 1
 
-#define movnti movq  /* write to cache for now */
-#define prefetch prefetcht2
-		
 	#include <asm/current.h>
 	#include <asm/offset.h>
 
 /* Standard copy_to_user with segment limit checking */		
 	.globl copy_to_user
-	.p2align 	
+	.p2align 4	
 copy_to_user:
 	GET_CURRENT(%rax)
 	movq %rdi,%rcx
@@ -26,7 +23,7 @@
 
 /* Standard copy_from_user with segment limit checking */	
 	.globl copy_from_user
-	.p2align 	
+	.p2align 4	
 copy_from_user:
 	GET_CURRENT(%rax)
 	movq %rsi,%rcx
@@ -60,20 +57,20 @@
  * eax uncopied bytes or 0 if successfull. 
  */
 	.globl copy_user_generic	
+	.p2align 4
 copy_user_generic:	
 	/* Put the first cacheline into cache. This should handle
 	   the small movements in ioctls etc., but not penalize the bigger
 	   filesystem data copies too much. */
 	pushq %rbx
-	prefetch (%rsi)
 	xorl %eax,%eax		/*zero for the exception handler */
 
 #ifdef FIX_ALIGNMENT
 	/* check for bad alignment of destination */
 	movl %edi,%ecx
 	andl $7,%ecx
-	jnz  bad_alignment
-after_bad_alignment:
+	jnz  .Lbad_alignment
+.Lafter_bad_alignment:
 #endif
 
 	movq %rdx,%rcx
@@ -81,133 +78,133 @@
 	movl $64,%ebx	
 	shrq $6,%rdx
 	decq %rdx
-	js   handle_tail
-	jz   loop_no_prefetch
-	
-loop:
-	prefetch 64(%rsi)
+	js   .Lhandle_tail
 	
-loop_no_prefetch:	
-s1:	movq (%rsi),%r11
-s2:	movq 1*8(%rsi),%r8
-s3:	movq 2*8(%rsi),%r9
-s4:	movq 3*8(%rsi),%r10
-d1:	movnti %r11,(%rdi)
-d2:	movnti %r8,1*8(%rdi)
-d3:	movnti %r9,2*8(%rdi)
-d4:	movnti %r10,3*8(%rdi)
+	.p2align 4
+.Lloop:
+.Ls1:	movq (%rsi),%r11
+.Ls2:	movq 1*8(%rsi),%r8
+.Ls3:	movq 2*8(%rsi),%r9
+.Ls4:	movq 3*8(%rsi),%r10
+.Ld1:	movq %r11,(%rdi)
+.Ld2:	movq %r8,1*8(%rdi)
+.Ld3:	movq %r9,2*8(%rdi)
+.Ld4:	movq %r10,3*8(%rdi)
 		
-s5:	movq 4*8(%rsi),%r11
-s6:	movq 5*8(%rsi),%r8
-s7:	movq 6*8(%rsi),%r9
-s8:	movq 7*8(%rsi),%r10
-d5:	movnti %r11,4*8(%rdi)
-d6:	movnti %r8,5*8(%rdi)
-d7:	movnti %r9,6*8(%rdi)
-d8:	movnti %r10,7*8(%rdi)
-
-	addq %rbx,%rsi	
-	addq %rbx,%rdi
+.Ls5:	movq 4*8(%rsi),%r11
+.Ls6:	movq 5*8(%rsi),%r8
+.Ls7:	movq 6*8(%rsi),%r9
+.Ls8:	movq 7*8(%rsi),%r10
+.Ld5:	movq %r11,4*8(%rdi)
+.Ld6:	movq %r8,5*8(%rdi)
+.Ld7:	movq %r9,6*8(%rdi)
+.Ld8:	movq %r10,7*8(%rdi)
 	
 	decq %rdx
-	jz   loop_no_prefetch
-	jns  loop
 
-handle_tail:
+	leaq 64(%rsi),%rsi
+	leaq 64(%rdi),%rdi
+	
+	jns  .Lloop
+
+	.p2align 4
+.Lhandle_tail:
 	movl %ecx,%edx
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz   handle_7
+	jz   .Lhandle_7
 	movl $8,%ebx
-loop_8:
-s9:	movq (%rsi),%r8
-d9:	movq %r8,(%rdi)
-	addq %rbx,%rdi
-	addq %rbx,%rsi
+	.p2align 4
+.Lloop_8:
+.Ls9:	movq (%rsi),%r8
+.Ld9:	movq %r8,(%rdi)
 	decl %ecx
-	jnz loop_8
+	leaq 8(%rdi),%rdi
+	leaq 8(%rsi),%rsi
+	jnz .Lloop_8
 	
-handle_7:		
+.Lhandle_7:		
 	movl %edx,%ecx	
 	andl $7,%ecx
-	jz   ende
-loop_1:
-s10:	movb (%rsi),%bl
-d10:	movb %bl,(%rdi)
+	jz   .Lende
+	.p2align 4
+.Lloop_1:
+.Ls10:	movb (%rsi),%bl
+.Ld10:	movb %bl,(%rdi)
 	incq %rdi
 	incq %rsi
 	decl %ecx
-	jnz loop_1
+	jnz .Lloop_1
 			
-ende:
-	sfence
+.Lende:
 	popq %rbx
 	ret	
 
 #ifdef FIX_ALIGNMENT		  		
 	/* align destination */
-bad_alignment:
+	.p2align 4
+.Lbad_alignment:
 	movl $8,%r9d
 	subl %ecx,%r9d
 	movl %r9d,%ecx
 	subq %r9,%rdx
-	jz   small_align
-	js   small_align
-align_1:		
-s11:	movb (%rsi),%bl
-d11:	movb %bl,(%rdi)
+	jz   .Lsmall_align
+	js   .Lsmall_align
+.Lalign_1:		
+.Ls11:	movb (%rsi),%bl
+.Ld11:	movb %bl,(%rdi)
 	incq %rsi
 	incq %rdi
 	decl %ecx
-	jnz align_1
-	jmp after_bad_alignment
-small_align:
+	jnz .Lalign_1
+	jmp .Lafter_bad_alignment
+.Lsmall_align:
 	addq %r9,%rdx
-	jmp handle_7
+	jmp .Lhandle_7
 #endif
 	
 	/* table sorted by exception address */	
 	.section __ex_table,"a"
 	.align 8
-	.quad s1,s1e
-	.quad s2,s2e
-	.quad s3,s3e
-	.quad s4,s4e	
-	.quad d1,s1e
-	.quad d2,s2e
-	.quad d3,s3e
-	.quad d4,s4e
-	.quad s5,s5e
-	.quad s6,s6e
-	.quad s7,s7e
-	.quad s8,s8e	
-	.quad d5,s5e
-	.quad d6,s6e
-	.quad d7,s7e
-	.quad d8,s8e
-	.quad s9,e_quad
-	.quad d9,e_quad
-	.quad s10,e_byte
-	.quad d10,e_byte
+	.quad .Ls1,.Ls1e
+	.quad .Ls2,.Ls2e
+	.quad .Ls3,.Ls3e
+	.quad .Ls4,.Ls4e	
+	.quad .Ld1,.Ls1e
+	.quad .Ld2,.Ls2e
+	.quad .Ld3,.Ls3e
+	.quad .Ld4,.Ls4e
+	.quad .Ls5,.Ls5e
+	.quad .Ls6,.Ls6e
+	.quad .Ls7,.Ls7e
+	.quad .Ls8,.Ls8e	
+	.quad .Ld5,.Ls5e
+	.quad .Ld6,.Ls6e
+	.quad .Ld7,.Ls7e
+	.quad .Ld8,.Ls8e
+	.quad .Ls9,.Le_quad
+	.quad .Ld9,.Le_quad
+	.quad .Ls10,.Le_byte
+	.quad .Ld10,.Le_byte
 #ifdef FIX_ALIGNMENT	
-	.quad s11,e_byte
-	.quad d11,e_byte
+	.quad .Ls11,.Le_byte
+	.quad .Ld11,.Le_byte
 #endif
-	.quad e5,e_zero
+	.quad .Le5,.Le_zero
 	.previous
 
 	/* compute 64-offset for main loop. 8 bytes accuracy with error on the 
 	   pessimistic side. this is gross. it would be better to fix the 
 	   interface. */	
 	/* eax: zero, ebx: 64 */
-s1e: 	addl $8,%eax
-s2e: 	addl $8,%eax
-s3e: 	addl $8,%eax
-s4e: 	addl $8,%eax
-s5e: 	addl $8,%eax
-s6e: 	addl $8,%eax
-s7e: 	addl $8,%eax
-s8e: 	addl $8,%eax
+.Ls1e: 	addl $8,%eax
+.Ls2e: 	addl $8,%eax
+.Ls3e: 	addl $8,%eax
+.Ls4e: 	addl $8,%eax
+.Ls5e: 	addl $8,%eax
+.Ls6e: 	addl $8,%eax
+.Ls7e: 	addl $8,%eax
+.Ls8e: 	addl $8,%eax
 	addq %rbx,%rdi	/* +64 */
 	subq %rax,%rdi  /* correct destination with computed offset */
 
@@ -215,22 +212,22 @@
 	addq %rax,%rdx	/* add offset to loopcnt */
 	andl $63,%ecx	/* remaining bytes */
 	addq %rcx,%rdx	/* add them */
-	jmp zero_rest
+	jmp .Lzero_rest
 
 	/* exception on quad word loop in tail handling */
 	/* ecx:	loopcnt/8, %edx: length, rdi: correct */
-e_quad:
+.Le_quad:
 	shll $3,%ecx
 	andl $7,%edx
 	addl %ecx,%edx
 	/* edx: bytes to zero, rdi: dest, eax:zero */
-zero_rest:
+.Lzero_rest:
 	movq %rdx,%rcx
-e_byte:
+.Le_byte:
 	xorl %eax,%eax
-e5:	rep 
+.Le5:	rep 
 	stosb
 	/* when there is another exception while zeroing the rest just return */
-e_zero:		
+.Le_zero:		
 	movq %rdx,%rax
-	jmp ende
+	jmp .Lende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-copy.S linux-2.4.21-rc3/arch/x86_64/lib/csum-copy.S
--- linux-2.4.20/arch/x86_64/lib/csum-copy.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/csum-copy.S	2003-05-22 22:06:51.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002 Andi Kleen
+ * Copyright 2002,2003 Andi Kleen, SuSE Labs.
  *	
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
@@ -8,7 +8,6 @@
  	#include <linux/linkage.h>
 	#include <asm/errno.h>
 
-//	#define FIX_ALIGNMENT 1
 /*
  * Checksum copy with exception handling.
  * On exceptions src_err_ptr or dst_err_ptr is set to -EFAULT and the 
@@ -26,17 +25,14 @@
  * eax  64bit sum. undefined in case of exception.
  * 
  * Wrappers need to take care of valid exception sum and zeroing.		 
+ * They also should align source or destination to 8 bytes.
  */
 
-/* for now - should vary this based on direction */
- #define prefetch prefetcht2
- #define movnti   movq
-
 	.macro source
 10:
 	.section __ex_table,"a"
 	.align 8
-	.quad 10b,bad_source
+	.quad 10b,.Lbad_source
 	.previous
 	.endm
 		
@@ -44,57 +40,65 @@
 20:
 	.section __ex_table,"a"
 	.align 8
-	.quad 20b,bad_dest
+	.quad 20b,.Lbad_dest
 	.previous
 	.endm
 			
 	.globl csum_partial_copy_generic
-	.p2align
+	.p2align 4
 csum_partial_copy_generic:
-	prefetchnta (%rdi)
+	cmpl	 $3*64,%edx
+	jle	 1f
+
+	source
+	prefetch (%rdi)
+	source
+	prefetch 1*64(%rdi)
+	source
+	prefetch 2*64(%rdi)
+	source
+	prefetch 3*64(%rdi)
+	source
+	prefetch 4*64(%rdi)
+	dest
+	prefetchw (%rsi)
+	dest
+	prefetchw 1*64(%rsi)
+	dest
+	prefetchw 2*64(%rsi)
+	dest
+	prefetchw 3*64(%rsi)
+	dest
+	prefetchw 4*64(%rsi)
+
+1:			
+	subq  $7*8,%rsp
+	movq  %rbx,2*8(%rsp)
+	movq  %r12,3*8(%rsp)
+	movq  %r14,4*8(%rsp)
+	movq  %r13,5*8(%rsp)
+	movq  %rbp,6*8(%rsp)
+
+	movq  %r8,(%rsp)
+	movq  %r9,1*8(%rsp)
 	
-	pushq %rbx
-	pushq %r12
-	pushq %r14
-	pushq %r15
-	movq %r8,%r14
-	movq %r9,%r15
 	movl  %ecx,%eax
 	movl  %edx,%ecx
 
-#ifdef FIX_ALIGNMENT
-	/* align source to 8 bytes */	
-	movl %edi,%r8d
-	andl $7,%r8d
-	jnz  bad_alignment	
-after_bad_alignment:
-#endif
-
-	movl  $64,%r10d
 	xorl  %r9d,%r9d
 	movq  %rcx,%r12
 
 	shrq  $6,%r12
-	/* loopcounter is maintained as one less to test efficiently for the
-	   previous to last iteration. This is needed to stop the prefetching. */
-	decq  %r12
-	js    handle_tail       /* < 64 */
-	jz    loop_no_prefetch  /* = 64 + X */ 
+	jz    .Lhandle_tail       /* < 64 */
+
+	clc
 	
 	/* main loop. clear in 64 byte blocks */
-	/* tries hard not to prefetch over the boundary */
-	/* r10:	64, r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
+	/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
 	/* r11:	temp3, rdx: temp4, r12 loopcnt */
-	.p2align
-loop:
-	/* Could prefetch more than one loop, but then it would be even
-	   trickier to avoid prefetching over the boundary. The hardware prefetch
-	   should take care of this anyways. The reason for this prefetch is
-	   just the non temporal hint to avoid cache pollution. Hopefully this
-	   will be handled properly by the hardware. */
-	prefetchnta 64(%rdi) 
-	
-loop_no_prefetch:
+	/* r10:	temp5, rbp: temp6, r14 temp7, r13 temp8 */
+	.p2align 4
+.Lloop:
 	source
 	movq  (%rdi),%rbx
 	source
@@ -104,175 +108,135 @@
 	source
 	movq  24(%rdi),%rdx
 
-	dest
-	movnti %rbx,(%rsi)
-	dest
-	movnti %r8,8(%rsi)
-	dest
-	movnti %r11,16(%rsi)
-	dest
-	movnti %rdx,24(%rsi)
+	source
+	movq  32(%rdi),%r10
+	source
+	movq  40(%rdi),%rbp
+	source
+	movq  48(%rdi),%r14
+	source
+	movq  56(%rdi),%r13
 		
-	addq  %rbx,%rax
+	source
+	prefetch 5*64(%rdi)
+						
+	adcq  %rbx,%rax
 	adcq  %r8,%rax
 	adcq  %r11,%rax
 	adcq  %rdx,%rax
+	adcq  %r10,%rax
+	adcq  %rbp,%rax
+	adcq  %r14,%rax
+	adcq  %r13,%rax
 
-	source
-	movq  32(%rdi),%rbx
-	source
-	movq  40(%rdi),%r8
-	source
-	movq  48(%rdi),%r11
-	source
-	movq  56(%rdi),%rdx
+	decl %r12d
 	
 	dest
-	movnti %rbx,32(%rsi)
+	movq %rbx,(%rsi)
 	dest
-	movnti %r8,40(%rsi)
+	movq %r8,8(%rsi)
 	dest
-	movnti %r11,48(%rsi)
+	movq %r11,16(%rsi)
 	dest
-	movnti %rdx,56(%rsi)
+	movq %rdx,24(%rsi)
 
-	adcq %rbx,%rax
-	adcq %r8,%rax
-	adcq %r11,%rax
-	adcq %rdx,%rax
+	dest
+	movq %r10,32(%rsi)
+	dest
+	movq %rbp,40(%rsi)
+	dest
+	movq %r14,48(%rsi)
+	dest
+	movq %r13,56(%rsi)
 	
-	adcq %r9,%rax	/* add in carry */
+	dest
+	prefetchw 5*64(%rsi)
 	
-	addq %r10,%rdi		
-	addq %r10,%rsi
+	leaq 64(%rdi),%rdi
+	leaq 64(%rsi),%rsi
 
-	decq %r12
-	jz   loop_no_prefetch	/* previous to last iteration? */
-	jns  loop
+	jnz   .Lloop
+
+	adcq  %r9,%rax
 
 	/* do last upto 56 bytes */
-handle_tail:
+.Lhandle_tail:
 	/* ecx:	count */
 	movl %ecx,%r10d
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz 	 fold
+	jz 	 .Lfold
 	clc
-	movl $8,%edx
-loop_8:	
+	.p2align 4
+.Lloop_8:	
 	source
 	movq (%rdi),%rbx
 	adcq %rbx,%rax
-	dest
-	movnti %rbx,(%rsi)
-	leaq (%rsi,%rdx),%rsi /* preserve carry */
-	leaq (%rdi,%rdx),%rdi
 	decl %ecx
-	jnz	loop_8
+	dest
+	movq %rbx,(%rsi)
+	leaq 8(%rsi),%rsi /* preserve carry */
+	leaq 8(%rdi),%rdi
+	jnz	.Lloop_8
 	adcq %r9,%rax	/* add in carry */
 
-fold:
+.Lfold:
+	/* reduce checksum to 32bits */
 	movl %eax,%ebx
 	shrq $32,%rax
-	addq %rbx,%rax
+	addl %ebx,%eax
+	adcl %r9d,%eax
 
 	/* do last upto 6 bytes */	
-handle_7:
+.Lhandle_7:
 	movl %r10d,%ecx
 	andl $7,%ecx
 	shrl $1,%ecx
-	jz   handle_1
+	jz   .Lhandle_1
 	movl $2,%edx
 	xorl %ebx,%ebx
 	clc  
-loop_1:	
+	.p2align 4
+.Lloop_1:	
 	source
 	movw (%rdi),%bx
-	adcq %rbx,%rax
+	adcl %ebx,%eax
 	dest
-	movw %bx,(%rsi)
-	addq %rdx,%rdi
-	addq %rdx,%rsi
 	decl %ecx
-	jnz loop_1
-	adcw %r9w,%ax	/* add in carry */
+	movw %bx,(%rsi)
+	leaq 2(%rdi),%rdi
+	leaq 2(%rsi),%rsi
+	jnz .Lloop_1
+	adcl %r9d,%eax	/* add in carry */
 	
 	/* handle last odd byte */
-handle_1:	
+.Lhandle_1:
 	testl $1,%r10d
-	jz    ende
+	jz    .Lende
 	xorl  %ebx,%ebx
 	source
 	movb (%rdi),%bl
 	dest
 	movb %bl,(%rsi)
-	addw %bx,%ax
-	adcw %r9w,%ax		/* carry */
+	addl %ebx,%eax
+	adcl %r9d,%eax		/* carry */
 			
-ende:		
-	sfence
-	popq %r15
-	popq %r14
-	popq %r12
-	popq %rbx
+.Lende:
+	movq 2*8(%rsp),%rbx
+	movq 3*8(%rsp),%r12
+	movq 4*8(%rsp),%r14
+	movq 5*8(%rsp),%r13
+	movq 6*8(%rsp),%rbp
+	addq $7*8,%rsp
 	ret
 
-#ifdef FIX_ALIGNMENT
-	/* align source to 8 bytes. */
-	/* r8d:	unalignedness, ecx len */
-bad_alignment:
-	testl $1,%edi
-	jnz   odd_source
-
-	/* compute distance to next aligned position */
-	movl $8,%r8d
-	xchgl %r8d,%ecx
-	subl %r8d,%ecx
-
-	/* handle unaligned part */
-	shrl $1,%ecx
-	xorl %ebx,%ebx	
-	movl $2,%r10d
-align_loop:
-	source
-	movw (%rdi),%bx
-	addq %rbx,%rax	/* carry cannot happen */
-	dest
-	movw %bx,(%rsi)
-	addq %r10,%rdi
-	addq %r10,%rsi
-	decl %ecx
-	jnz align_loop
-	jmp after_bad_alignment
-
-	/* weird case. need to swap the sum at the end because the spec requires
-	   16 bit words of the sum to be always paired. 
-	   handle it recursively because it should be rather rare. */
-odd_source:
-	/* copy odd byte */
-	xorl %ebx,%ebx
-	source
-	movb (%rdi),%bl
-	addl %ebx,%eax       /* add to old checksum */
-	adcl $0,%ecx
-	dest
-	movb %al,(%rsi)
-	
-	/* fix arguments */
-	movl %eax,%ecx
-	incq %rsi
-	incq %rdi
-	decq %rdx 
-	call csum_partial_copy_generic
-	bswap %eax        /* this should work, but check */
-	jmp ende
-#endif
-
 	/* Exception handlers. Very simple, zeroing is done in the wrappers */
-bad_source:
-	movl $-EFAULT,(%r14)
-	jmp  ende
-	
-bad_dest:
-	movl $-EFAULT,(%r15)
-	jmp ende
+.Lbad_source:
+	movq (%rsp),%rax
+	movl $-EFAULT,(%rax)
+	jmp  .Lende
+	
+.Lbad_dest:
+	movq 8(%rsp),%rax
+	movl $-EFAULT,(%rax)
+	jmp .Lende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-partial.c linux-2.4.21-rc3/arch/x86_64/lib/csum-partial.c
--- linux-2.4.20/arch/x86_64/lib/csum-partial.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/csum-partial.c	2003-05-22 22:06:52.000000000 +0000
@@ -7,35 +7,39 @@
  
 #include <linux/compiler.h>
 #include <linux/module.h>
+#include <asm/checksum.h>
 
-/* Better way for this sought */
-static inline unsigned short from64to16(unsigned long x)
+#define __force_inline inline __attribute__((always_inline))
+
+static inline unsigned short from32to16(unsigned a) 
 {
-	/* add up 32-bit words for 33 bits */
-	x = (x & 0xffffffff) + (x >> 32);
-	/* add up 16-bit and 17-bit words for 17+c bits */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up 16-bit and 2-bit for 16+c bit */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up carry.. */
-	x = (x & 0xffff) + (x >> 16);
-	return x;
+	unsigned short b = a >> 16; 
+	asm("addw %w2,%w0\n\t"
+	    "adcw $0,%w0\n" 
+	    : "=r" (b)
+	    : "0" (b), "r" (a));
+	return b;
 }
 
 /*
  * Do a 64-bit checksum on an arbitrary memory area.
  * Returns a 32bit checksum.
  *
- * This isn't a great routine, but it's not _horrible_ either. 
- * We rely on the compiler to unroll.
+ * This isn't as time critical as it used to be because many NICs
+ * do hardware checksumming these days.
+ * 
+ * Things tried and found to not make it faster:
+ * Manual Prefetching
+ * Unrolling to an 128 bytes inner loop.
+ * Using interleaving with more registers to break the carry chains.
  */
-static inline unsigned do_csum(const unsigned char * buff, int len)
+static __force_inline unsigned do_csum(const unsigned char *buff, unsigned len)
 {
-	int odd, count;
+	unsigned odd, count;
 	unsigned long result = 0;
 
-	if (len <= 0)
-		goto out;
+	if (unlikely(len == 0))
+		return result; 
 	odd = 1 & (unsigned long) buff;
 	if (unlikely(odd)) {
 		result = *buff << 8;
@@ -45,7 +49,7 @@
 	count = len >> 1;		/* nr of 16-bit words.. */
 	if (count) {
 		if (2 & (unsigned long) buff) {
-			result += *(unsigned short *) buff;
+			result += *(unsigned short *)buff;
 			count--;
 			len -= 2;
 			buff += 2;
@@ -59,18 +63,41 @@
 				buff += 4;
 			}
 			count >>= 1;	/* nr of 64-bit words.. */
-			if (count) {
+
+			/* main loop using 64byte blocks */
 				unsigned long zero = 0; 
-				do {
-					asm("  addq %1,%0\n"
-					    "  adcq %2,%0\n" 
+			unsigned count64 = count >> 3; 
+			while (count64) { 
+				asm("addq 0*8(%[src]),%[res]\n\t"
+				    "adcq 1*8(%[src]),%[res]\n\t"
+				    "adcq 2*8(%[src]),%[res]\n\t"
+				    "adcq 3*8(%[src]),%[res]\n\t"
+				    "adcq 4*8(%[src]),%[res]\n\t"
+				    "adcq 5*8(%[src]),%[res]\n\t"
+				    "adcq 6*8(%[src]),%[res]\n\t"
+				    "adcq 7*8(%[src]),%[res]\n\t"
+				    "adcq %[zero],%[res]"
+				    : [res] "=r" (result)
+				    : [src] "r" (buff), [zero] "r" (zero),
+				    "[res]" (result));
+				buff += 64;
+				count64--;
+			}
+
+			/* last upto 7 8byte blocks */
+			count %= 8; 
+			while (count) { 
+				asm("addq %1,%0\n\t"
+				    "adcq %2,%0\n" 
 					    : "=r" (result)
-					    : "m"  (*buff), "r" (zero),  "0" (result));
-					count--;
+				    : "m" (*(unsigned long *)buff), 
+				    "r" (zero),  "0" (result));
+				--count; 
 					buff += 8;
-				} while (count);
-				result = (result & 0xffffffff) + (result >> 32);
 			}
+			result = add32_with_carry(result>>32,
+						  result&0xffffffff); 
+
 			if (len & 4) {
 				result += *(unsigned int *) buff;
 				buff += 4;
@@ -83,10 +110,11 @@
 	}
 	if (len & 1)
 		result += *buff;
-	result = from64to16(result);
-	if (unlikely(odd))
-		return ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
+	result = add32_with_carry(result>>32, result & 0xffffffff); 
+	if (unlikely(odd)) { 
+		result = from32to16(result);
+		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+	}
 	return result;
 }
 
@@ -102,14 +130,9 @@
  *
  * it's best to have buff aligned on a 64-bit boundary
  */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+unsigned csum_partial(const unsigned char *buff, unsigned len, unsigned sum)
 {
-	unsigned result = do_csum(buff, len);
-
-	/* add in old sum, and carry.. */
-	asm("addl %1,%0\n\t"
-	    "adcl $0,%0" : "=r" (result) : "r" (sum), "0" (result)); 
-	return result;
+	return add32_with_carry(do_csum(buff, len), sum); 
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-wrappers.c linux-2.4.21-rc3/arch/x86_64/lib/csum-wrappers.c
--- linux-2.4.20/arch/x86_64/lib/csum-wrappers.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/csum-wrappers.c	2003-05-22 22:06:40.000000000 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2002 Andi Kleen, SuSE Labs.
+/* Copyright 2002,2003 Andi Kleen, SuSE Labs.
  * Subject to the GNU Public License v.2
  * 
  * Wrappers of assembly checksum functions for x86-64.
@@ -7,18 +7,6 @@
 #include <asm/checksum.h>
 #include <linux/module.h>
 
-/* Better way for this sought */
-static inline unsigned from64to32(unsigned long x)
-{
-	/* add up 32-bit words for 33 bits */
-        x = (x & 0xffffffff) + (x >> 32);
-        /* add up 16-bit and 17-bit words for 17+c bits */
-        x = (x & 0xffff) + (x >> 16);
-        /* add up 16-bit and 2-bit for 16+c bit */
-        x = (x & 0xffff) + (x >> 16);
-        return x;
-}
-
 /** 
  * csum_partial_copy_from_user - Copy and checksum from user space. 
  * @src: source address (user space) 
@@ -36,14 +24,32 @@
 { 
 	*errp = 0;
 	if (likely(access_ok(VERIFY_READ,src, len))) { 
-		unsigned long sum; 
-		sum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL);
+		/* Why 6, not 7? To handle odd addresses aligned we
+		   would need to do considerable complications to fix the
+		   checksum which is defined as an 16bit accumulator. The
+		   fix alignment code is primarily for performance
+		   compatibility with 32bit and that will handle odd
+		   addresses slowly too. */
+		if (unlikely((unsigned long)src & 6)) {			
+			while (((unsigned long)src & 6) && len >= 2) { 
+				__u16 val16;			
+				*errp = __get_user(val16, (__u16 *)src); 
+				if (*errp)
+					return isum;
+				*(__u16 *)dst = val16;
+				isum = add32_with_carry(isum, val16); 
+				src += 2; 
+				dst += 2; 
+				len -= 2;
+			}
+		}
+		isum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL);
 		if (likely(*errp == 0)) 
-			return from64to32(sum); 
+			return isum;
 	} 
 	*errp = -EFAULT;
 	memset(dst,0,len); 
-	return 0;		
+	return isum;		
 } 
 
 EXPORT_SYMBOL(csum_partial_copy_from_user);
@@ -67,8 +73,22 @@
 		*errp = -EFAULT;
 		return 0; 
 	}
+
+	if (unlikely((unsigned long)dst & 6)) {
+		while (((unsigned long)dst & 6) && len >= 2) { 
+			__u16 val16 = *(__u16 *)src;
+			isum = add32_with_carry(isum, val16);
+			*errp = __put_user(val16, (__u16 *)dst);
+			if (*errp)
+				return isum;
+			src += 2; 
+			dst += 2; 
+			len -= 2;
+		}
+	}
+
 	*errp = 0;
-	return from64to32(csum_partial_copy_generic(src,dst,len,isum,NULL,errp)); 
+	return csum_partial_copy_generic(src,dst,len,isum,NULL,errp); 
 } 
 
 EXPORT_SYMBOL(csum_partial_copy_to_user);
@@ -85,11 +105,9 @@
 unsigned int 
 csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
 { 
-	return from64to32(csum_partial_copy_generic(src,dst,len,sum,NULL,NULL));
+	return csum_partial_copy_generic(src,dst,len,sum,NULL,NULL);
 } 
 
-//EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
 unsigned short csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
 			       __u32 len, unsigned short proto, unsigned int sum) 
 {
@@ -103,7 +121,7 @@
 	    "  adcq $0,%[sum]\n"
 	    : [sum] "=r" (sum64) 
 	    : "[sum]" (rest),[saddr] "r" (saddr), [daddr] "r" (daddr));
-	return csum_fold(from64to32(sum64)); 
+	return csum_fold(add32_with_carry(sum64 & 0xffffffff, sum64>>32));
 }
 
 EXPORT_SYMBOL(csum_ipv6_magic);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/delay.c linux-2.4.21-rc3/arch/x86_64/lib/delay.c
--- linux-2.4.20/arch/x86_64/lib/delay.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/delay.c	2003-05-22 22:06:26.000000000 +0000
@@ -19,7 +19,6 @@
 
 void __delay(unsigned long loops)
 {
-#ifndef CONFIG_SIMNOW
 	unsigned long bclock, now;
 	
 	rdtscl(bclock);
@@ -29,7 +28,6 @@
 		rdtscl(now);
 	}
 	while((now-bclock) < loops);
-#endif
 }
 
 inline void __const_udelay(unsigned long xloops)
@@ -41,3 +39,9 @@
 {
 	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
 }
+
+void __ndelay(unsigned long usecs)
+{
+       __const_udelay(usecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/memcpy.S linux-2.4.21-rc3/arch/x86_64/lib/memcpy.S
--- linux-2.4.20/arch/x86_64/lib/memcpy.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/memcpy.S	2003-05-22 22:06:24.000000000 +0000
@@ -12,103 +12,78 @@
  * rax original destination
  */	
 
- // #define FIX_ALIGNMENT
  	.globl __memcpy
 	.globl memcpy
-	.p2align
+	.p2align 4
 __memcpy:
 memcpy:		
 	pushq %rbx
 	movq %rdi,%rax
 
-#ifdef FIX_ALIGNMENT
-	movl %edi,%ecx
-	andl $7,%ecx
-	jnz  bad_alignment	
-after_bad_alignment:
-#endif
-
-	movq %rdx,%rcx
-	movl $64,%ebx
-	shrq $6,%rcx
-	jz handle_tail
+	movl %edx,%ecx
+	shrl $6,%ecx
+	jz .Lhandle_tail
 	
-loop_64:
+	.p2align 4
+.Lloop_64:
+	decl %ecx
+
 	movq (%rsi),%r11
 	movq 8(%rsi),%r8
-	movq 2*8(%rsi),%r9
-	movq 3*8(%rsi),%r10
+
 	movq %r11,(%rdi)
 	movq %r8,1*8(%rdi)
+
+	movq 2*8(%rsi),%r9
+	movq 3*8(%rsi),%r10
+
 	movq %r9,2*8(%rdi)
 	movq %r10,3*8(%rdi)
 		
 	movq 4*8(%rsi),%r11
 	movq 5*8(%rsi),%r8
-	movq 6*8(%rsi),%r9
-	movq 7*8(%rsi),%r10
+
 	movq %r11,4*8(%rdi)
 	movq %r8,5*8(%rdi)
+
+	movq 6*8(%rsi),%r9
+	movq 7*8(%rsi),%r10
+
 	movq %r9,6*8(%rdi)
 	movq %r10,7*8(%rdi)
 
-	addq %rbx,%rsi	
-	addq %rbx,%rdi
-	decl %ecx
-	jnz  loop_64
+	leaq 64(%rsi),%rsi
+	leaq 64(%rdi),%rdi
+	jnz  .Lloop_64
 
-handle_tail:
+.Lhandle_tail:
 	movl %edx,%ecx
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz   handle_7
-	movl $8,%ebx
-loop_8: 
+	jz   .Lhandle_7
+	.p2align 4
+.Lloop_8: 
+	decl %ecx
 	movq (%rsi),%r8
 	movq %r8,(%rdi) 
-	addq %rbx,%rdi
-	addq %rbx,%rsi
-	decl %ecx
-	jnz  loop_8
+	leaq 8(%rdi),%rdi
+	leaq 8(%rsi),%rsi
+	jnz  .Lloop_8
 
-handle_7:
+.Lhandle_7:
 	movl %edx,%ecx
 	andl $7,%ecx
-	jz ende
-loop_1:
+	jz .Lende
+	.p2align 4
+.Lloop_1:
 	movb (%rsi),%r8b
 	movb %r8b,(%rdi) 
 	incq %rdi
 	incq %rsi
 	decl %ecx
-	jnz loop_1
+	jnz .Lloop_1
 	
-ende: 	
-	sfence
+.Lende: 	
 	popq %rbx
 	ret
 
-
-#ifdef FIX_ALIGNMENT
-	/* align destination */
-	/* This is simpleminded. For bigger blocks it may make sense to align
-	   src and dst to their aligned subset and handle the rest separately */
-bad_alignment:
-	movl $8,%r9d
-	subl %ecx,%r9d
-	movl %r9d,%ecx
-	subq %r9,%rdx
-	js   small_alignment
-	jz   small_alignment
-align_1:
-	movb (%rsi),%r8b
-	movb %r8b,(%rdi) 
-	incq %rdi
-	incq %rsi
-	decl %ecx
-	jnz  align_1
-	jmp after_bad_alignment
-small_alignment:
-	addq %r9,%rdx
-	jmp handle_7
-#endif	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/memset.S linux-2.4.21-rc3/arch/x86_64/lib/memset.S
--- linux-2.4.20/arch/x86_64/lib/memset.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/memset.S	2003-05-22 22:06:50.000000000 +0000
@@ -11,7 +11,7 @@
  */	
  	.globl __memset
 	.globl memset
-	.p2align
+	.p2align 4
 memset:	
 __memset:
 	movq %rdi,%r10
@@ -25,15 +25,16 @@
 	/* align dst */
 	movl  %edi,%r9d
 	andl  $7,%r9d	
-	jnz  bad_alignment
-after_bad_alignment:
+	jnz  .Lbad_alignment
+.Lafter_bad_alignment:
 
-	movq %r11,%rcx
-	movl $64,%r8d
-	shrq $6,%rcx
-	jz	 handle_tail
+	movl %r11d,%ecx
+	shrl $6,%ecx
+	jz	 .Lhandle_tail
 
-loop_64:	
+	.p2align 4
+.Lloop_64:	
+	decl   %ecx
 	movq  %rax,(%rdi) 
 	movq  %rax,8(%rdi) 
 	movq  %rax,16(%rdi) 
@@ -42,43 +43,45 @@
 	movq  %rax,40(%rdi) 
 	movq  %rax,48(%rdi) 
 	movq  %rax,56(%rdi) 
-	addq    %r8,%rdi
-	decl   %ecx
-	jnz    loop_64
+	leaq  64(%rdi),%rdi
+	jnz    .Lloop_64
 
 	/* Handle tail in loops. The loops should be faster than hard
 	   to predict jump tables. */ 
-handle_tail:
+	.p2align 4	   
+.Lhandle_tail:
 	movl	%r11d,%ecx
 	andl    $63&(~7),%ecx
-	jz 		handle_7
+	jz 		.Lhandle_7
 	shrl	$3,%ecx
-loop_8:
-	movq  %rax,(%rdi) 
-	addq    $8,%rdi
+	.p2align 4
+.Lloop_8:
 	decl   %ecx
-	jnz    loop_8
+	movq  %rax,(%rdi)
+	leaq  8(%rdi),%rdi
+	jnz    .Lloop_8
 
-handle_7:
+.Lhandle_7:
 	movl	%r11d,%ecx
 	andl	$7,%ecx
-	jz      ende
-loop_1:
-	movb 	%al,(%rdi)
-	addq	$1,%rdi
+	jz      .Lende
+	.p2align 4
+.Lloop_1:
 	decl    %ecx
-	jnz     loop_1
+	movb 	%al,(%rdi)
+	leaq	1(%rdi),%rdi
+	jnz     .Lloop_1
 	
-ende:	
+.Lende:	
 	movq	%r10,%rax
 	ret
 
-bad_alignment:
+.Lbad_alignment:
 	cmpq $7,%r11
-	jbe	handle_7
+	jbe	.Lhandle_7
 	movq %rax,(%rdi)	/* unaligned store */
 	movq $8,%r8
 	subq %r9,%r8 
 	addq %r8,%rdi
 	subq %r8,%r11
-	jmp after_bad_alignment
+	jmp .Lafter_bad_alignment
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/usercopy.c linux-2.4.21-rc3/arch/x86_64/lib/usercopy.c
--- linux-2.4.20/arch/x86_64/lib/usercopy.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/lib/usercopy.c	2003-05-22 22:06:48.000000000 +0000
@@ -30,7 +30,7 @@
 		"	jmp 2b\n"					   \
 		".previous\n"						   \
 		".section __ex_table,\"a\"\n"				   \
-		"	.align 4\n"					   \
+		"	.align 8\n"					   \
 		"	.quad 0b,3b\n"					   \
 		".previous"						   \
 		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/fault.c linux-2.4.21-rc3/arch/x86_64/mm/fault.c
--- linux-2.4.20/arch/x86_64/mm/fault.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/fault.c	2003-05-22 22:06:53.000000000 +0000
@@ -30,9 +30,6 @@
 #include <asm/proto.h>
 #include <asm/kdebug.h>
 
-spinlock_t pcrash_lock; 
-int crashing_cpu;
-
 extern spinlock_t console_lock, timerlist_lock;
 
 void bust_spinlocks(int yes)
@@ -60,29 +57,41 @@
 	}
 }
 
+static int bad_address(void *p) 
+{ 
+	unsigned long dummy;
+	return __get_user(dummy, (unsigned long *)p);
+} 
+
 void dump_pagetable(unsigned long address)
 {
-	static char *name[] = { "PML4", "PGD", "PDE", "PTE" }; 
-	int i, shift;
-	unsigned long page;
-
-	shift = 9+9+9+12;
-	address &= ~0xFFFF000000000000UL;
-	asm("movq %%cr3,%0" : "=r" (page)); 
-	for (i = 0; i < 4; i++) { 	
-		unsigned long *padr = (unsigned long *) __va(page); 
-		padr += (address >> shift) & 0x1FFU;
-		if (__get_user(page, padr)) { 
-			printk("%s: bad %p\n", name[i], padr); 
-			break;
-		}
-		printk("%s: %016lx ", name[i], page); 
-		if ((page & (1 | (1<<7))) != 1) /* Not present or 2MB page */
-			break;
-		page &= ~0xFFFUL;
-		shift -= (i == 0) ? 12 : 9;
-	} 
+	pml4_t *pml4;
+	asm("movq %%cr3,%0" : "=r" (pml4));
+
+	pml4 = __va((unsigned long)pml4 & PHYSICAL_PAGE_MASK); 
+	pml4 += pml4_index(address);
+	printk("PML4 %lx ", pml4_val(*pml4));
+	if (bad_address(pml4)) goto bad;
+	if (!pml4_present(*pml4)) goto ret; 
+
+	pgd_t *pgd = __pgd_offset_k((pgd_t *)pml4_page(*pml4), address); 
+	if (bad_address(pgd)) goto bad;
+	printk("PGD %lx ", pgd_val(*pgd)); 
+	if (!pgd_present(*pgd))	goto ret;
+
+	pmd_t *pmd = pmd_offset(pgd, address); 
+	if (bad_address(pmd)) goto bad;
+	printk("PMD %lx ", pmd_val(*pmd));
+	if (!pmd_present(*pmd))	goto ret;	 
+
+	pte_t *pte = pte_offset(pmd, address);
+	if (bad_address(pte)) goto bad;
+	printk("PTE %lx", pte_val(*pte)); 
+ret:
 	printk("\n");
+	return;
+bad:
+	printk("BAD\n");
 }
 
 int page_fault_trace; 
@@ -112,15 +121,18 @@
 	/* get the address */
 	__asm__("movq %%cr2,%0":"=r" (address));
 
+	if (regs->eflags & X86_EFLAGS_IF)
+		__sti();
+
 #ifdef CONFIG_CHECKING
 	if (page_fault_trace) 
-		printk("pfault %d rip:%lx rsp:%lx cs:%lu ss:%lu addr %lx error %lx\n",
-		       stack_smp_processor_id(), regs->rip,regs->rsp,regs->cs,
-			   regs->ss,address,error_code); 
+		printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
+		       regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code); 
+
 
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -217,14 +229,11 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
-		if (exception_trace) {
-#if 1
-			dump_pagetable(address);
-#endif	
+		if (exception_trace) 
 			printk("%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
 					current->comm, current->pid, address, regs->rip,
 					regs->rsp, error_code);
-		}
+	
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
@@ -256,14 +265,6 @@
 	console_verbose();
 	bust_spinlocks(1); 
 
-	if (!in_interrupt()) { 
-		if (!spin_trylock(&pcrash_lock)) { 
-			if (crashing_cpu != smp_processor_id()) 
-				spin_lock(&pcrash_lock);  		    
-		} 
-		crashing_cpu = smp_processor_id();
-	} 
-
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
@@ -272,14 +273,7 @@
 	printk(" printing rip:\n");
 	printk("%016lx\n", regs->rip);
 	dump_pagetable(address);
-
 	die("Oops", regs, error_code);
-
-	if (!in_interrupt()) { 
-		crashing_cpu = -1;  /* small harmless window */ 
-		spin_unlock(&pcrash_lock);
-	}
-
 	bust_spinlocks(0); 
 	do_exit(SIGKILL);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/init.c linux-2.4.21-rc3/arch/x86_64/mm/init.c
--- linux-2.4.20/arch/x86_64/mm/init.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/init.c	2003-05-22 22:06:28.000000000 +0000
@@ -189,7 +189,7 @@
 	unsigned long pfn = table_end++, paddr; 
 	void *adr;
 
-	if (table_end >= end_pfn) 
+	if (table_end >= end_pfn_map) 
 		panic("alloc_low_page: ran out of page mappings"); 
 	for (i = 0; temp_mappings[i].allocated; i++) {
 		if (!temp_mappings[i].pmd) 
@@ -246,7 +246,8 @@
 					set_pmd(pmd,  __pmd(0)); 
 				break;
 			}
-			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
+			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_NX | _PAGE_GLOBAL | paddr;
+			pe &= __supported_pte_mask; 
 			set_pmd(pmd, __pmd(pe));
 		}
 		unmap_low_page(map);
@@ -264,7 +265,7 @@
 	unsigned long next; 
 	unsigned long pgds, pmds, tables; 
 
-	end = end_pfn << PAGE_SHIFT; 
+	end = end_pfn_map << PAGE_SHIFT; 
 
 	/* 
 	 * Find space for the kernel direct mapping tables.
@@ -494,7 +495,7 @@
 	return;
 }
 
-void reserve_bootmem_generic(unsigned long phys, unsigned len) 
+void __init reserve_bootmem_generic(unsigned long phys, unsigned len) 
 { 
 	/* Should check here against the e820 map to avoid double free */ 
 #ifdef CONFIG_DISCONTIGMEM
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/ioremap.c linux-2.4.21-rc3/arch/x86_64/mm/ioremap.c
--- linux-2.4.20/arch/x86_64/mm/ioremap.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/ioremap.c	2003-05-22 22:06:40.000000000 +0000
@@ -142,7 +142,7 @@
 	 */
 	offset = phys_addr & ~PAGE_MASK;
 	phys_addr &= PAGE_MASK;
-	size = PAGE_ALIGN(last_addr) - phys_addr;
+	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
 	/*
 	 * Ok, go for it..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/k8topology.c linux-2.4.21-rc3/arch/x86_64/mm/k8topology.c
--- linux-2.4.20/arch/x86_64/mm/k8topology.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/k8topology.c	2003-05-22 22:06:51.000000000 +0000
@@ -6,7 +6,7 @@
  * Instead the northbridge registers are read directly. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: k8topology.c,v 1.3 2002/09/12 12:51:39 ak Exp $
+ * $Id: k8topology.c,v 1.7 2003/04/02 21:36:22 ak Exp $
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -23,7 +23,7 @@
 int memnode_shift;
 u8  memnodemap[NODEMAPSIZE];
 
-static int find_northbridge(void)
+static __init int find_northbridge(void)
 {
 	int num; 
 
@@ -53,7 +53,7 @@
 #define for_all_nodes(n) \
 	for (n=0; n<MAXNODE;n++) if (nodes[n].start!=nodes[n].end)
 
-static int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
+static __init int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
 {
 	int i; 
 	int shift = 24;
@@ -66,7 +66,8 @@
 			for (addr = nodes[i].start; 
 			     addr < nodes[i].end; 
 			     addr += (1UL << shift)) {
-				if (memnodemap[addr >> shift] != 0xff) { 
+				if (memnodemap[addr >> shift] != 0xff && 
+				    memnodemap[addr >> shift] != i) { 
 					printk("node %d shift %d addr %Lx conflict %d\n", 
 					       i, shift, addr, memnodemap[addr>>shift]);
 					goto next; 
@@ -127,13 +128,12 @@
 
 		limit >>= 16; 
 		limit <<= 24; 
+		limit |= (1<<24)-1;
 
 		if (limit > end_pfn << PAGE_SHIFT) 
 			limit = end_pfn << PAGE_SHIFT; 
-		if (limit <= base) { 
-			printk(KERN_INFO "Node %d beyond memory map\n", nodeid);
+		if (limit <= base)
 			continue; 
-		} 
 			
 		base >>= 16;
 		base <<= 24; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/modutil.c linux-2.4.21-rc3/arch/x86_64/mm/modutil.c
--- linux-2.4.20/arch/x86_64/mm/modutil.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/modutil.c	2003-05-22 22:06:39.000000000 +0000
@@ -10,11 +10,23 @@
  
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/proto.h>
 
-static struct vm_struct * modvmlist = NULL;
+extern char _text[], _end[]; 
+
+/* Kernel mapping to make the kernel alias visible to 
+   /proc/kcore and /dev/mem 
+
+   RED-PEN may want vsyscall mappings too 
+ */
+
+static struct vm_struct kernel_mapping = { 
+	.addr = (void *)KERNEL_TEXT_START, 
+}; 
 
 void module_unmap (void * addr)
 {
@@ -26,9 +38,11 @@
 		printk("Trying to unmap module with bad address (%p)\n", addr);
 		return;
 	}
-	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
+			write_unlock(&vmlist_lock); 
 			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
 			kfree(tmp);
 			return;
@@ -45,24 +59,55 @@
 	size = PAGE_ALIGN(size);
 	if (!size || size > MODULES_LEN) return NULL;
 		
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area) return NULL; 
+
+	memset(area, 0, sizeof(struct vm_struct));
+
+	size = round_up(size, PAGE_SIZE); 
+
 	addr = (void *) MODULES_VADDR;
-	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+		void *next;
 		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
 			break;
-		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+		next = (void *) (tmp->size + (unsigned long) tmp->addr);
+		if (next > addr)
+			addr = next;
+	}
+	if ((unsigned long) addr + size >= MODULES_END) { 
+		write_unlock(&vmlist_lock); 
+		kfree(area);
+		return NULL;
 	}
-	if ((unsigned long) addr + size >= MODULES_END) return NULL;
 	
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area) return NULL;
-	area->size = size + PAGE_SIZE;
+	area->size = size;
 	area->addr = addr;
 	area->next = *p;
 	*p = area;
+	write_unlock(&vmlist_lock); 
 
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
+	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL_EXECUTABLE)) {
 		module_unmap(addr);
 		return NULL;
 	}
 	return addr;
 }
+
+static int __init mod_vmlist_init(void)
+{
+	struct vm_struct *vm, **base;
+	write_lock(&vmlist_lock); 
+	for (base = &vmlist, vm = *base; vm; base = &vm->next, vm = *base) { 
+		if (vm->addr > (void *)KERNEL_TEXT_START) 
+			break; 
+	}  
+	kernel_mapping.size = _end - _text;
+	kernel_mapping.next = vm; 
+	*base = &kernel_mapping; 
+	write_unlock(&vmlist_lock); 
+	return 0;
+} 
+
+__initcall(mod_vmlist_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/numa.c linux-2.4.21-rc3/arch/x86_64/mm/numa.c
--- linux-2.4.20/arch/x86_64/mm/numa.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/numa.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,7 +1,7 @@
 /* 
  * Generic VM initialization for x86-64 NUMA setups.
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: numa.c,v 1.4 2002/09/05 15:28:12 ak Exp $
+ * $Id: numa.c,v 1.6 2003/04/03 12:28:08 ak Exp $
  */ 
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -183,9 +183,9 @@
 }
 
 /* [numa=off] */
-static __init int numa_setup(char *opt) 
+__init int numa_setup(char *opt) 
 { 
-	if (!strcmp(opt,"off"))
+	if (!strncmp(opt,"off",3))
 		numa_off = 1;
 	return 1;
 } 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/pageattr.c linux-2.4.21-rc3/arch/x86_64/mm/pageattr.c
--- linux-2.4.20/arch/x86_64/mm/pageattr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/mm/pageattr.c	2003-05-22 22:06:28.000000000 +0000
@@ -48,18 +48,17 @@
 {
 	struct cpuinfo_x86 *cpu = &cpu_data[smp_processor_id()]; 
 	wmb(); 
-	/* Disabled for now because there seem to be some problems with CLFLUSH */
 	if (0 && test_bit(X86_FEATURE_CLFLSH, &cpu->x86_capability)) { 
 		/* is this worth it? */ 
 		int i;
 		for (i = 0; i < PAGE_SIZE; i += cpu->x86_clflush_size) 
-			asm volatile("clflush %0" :: "m" (__pa(address) + i)); 
+			asm volatile("clflush %0" :: "m" (address + i)); 
 	} else
 		asm volatile("wbinvd":::"memory"); 
 	__flush_tlb_one(address);
 }
 
-/* no more special protections in this 2/4MB area - revert to a
+/* no more special protections in this 2MB area - revert to a
    large page again. */
 static inline void revert_page(struct page *kpte_page, unsigned long address)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/vmlinux.lds linux-2.4.21-rc3/arch/x86_64/vmlinux.lds
--- linux-2.4.20/arch/x86_64/vmlinux.lds	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/arch/x86_64/vmlinux.lds	2003-05-22 22:06:27.000000000 +0000
@@ -55,10 +55,10 @@
   .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) }
   vxtime_sequence = LOADADDR(.vxtime_sequence);
   . = ALIGN(16);
-  .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) }
-  hpet = LOADADDR(.hpet);
+  .vxtime : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.vxtime) }
+  vxtime = LOADADDR(.vxtime);
   . = ALIGN(16);
-  .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) }
+  .wall_jiffies : AT ((LOADADDR(.vxtime) + SIZEOF(.vxtime) + 15) & ~(15)) { *(.wall_jiffies) }
   wall_jiffies = LOADADDR(.wall_jiffies);
   . = ALIGN(16);
   .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) }
@@ -96,8 +96,10 @@
 
   /* Sections to be discarded */
   /DISCARD/ : {
+	*(.text.exit)
 	*(.data.exit)
 	*(.exitcall.exit)
+	*(.eh_frame)
 	}
 
   /* DWARF 2 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/acpi/acpi_ksyms.c linux-2.4.21-rc3/drivers/acpi/acpi_ksyms.c
--- linux-2.4.20/drivers/acpi/acpi_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/acpi/acpi_ksyms.c	2003-05-22 22:06:40.000000000 +0000
@@ -68,6 +68,7 @@
 EXPORT_SYMBOL(acpi_get_next_object);
 EXPORT_SYMBOL(acpi_evaluate_object);
 EXPORT_SYMBOL(acpi_get_table);
+EXPORT_SYMBOL(acpi_get_firmware_table);
 
 EXPORT_SYMBOL(acpi_install_notify_handler);
 EXPORT_SYMBOL(acpi_remove_notify_handler);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/atmdev_init.c linux-2.4.21-rc3/drivers/atm/atmdev_init.c
--- linux-2.4.20/drivers/atm/atmdev_init.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/atmdev_init.c	2003-05-22 22:06:41.000000000 +0000
@@ -19,9 +19,6 @@
 #ifdef CONFIG_ATM_HORIZON
 extern int hrz_detect(void);
 #endif
-#ifdef CONFIG_ATM_IA
-extern int ia_detect(void);
-#endif
 #ifdef CONFIG_ATM_FORE200E
 extern int fore200e_detect(void);
 #endif
@@ -53,9 +50,6 @@
 #ifdef CONFIG_ATM_HORIZON
 	devs += hrz_detect();
 #endif
-#ifdef CONFIG_ATM_IA
-	devs += ia_detect();
-#endif
 #ifdef CONFIG_ATM_FORE200E
 	devs += fore200e_detect();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/fore200e.c linux-2.4.21-rc3/drivers/atm/fore200e.c
--- linux-2.4.20/drivers/atm/fore200e.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/fore200e.c	2003-05-22 22:06:43.000000000 +0000
@@ -1135,7 +1135,7 @@
 	return;
     } 
 
-    skb->stamp = vcc->timestamp = xtime;
+    skb->stamp = xtime;
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/idt77105.c linux-2.4.21-rc3/drivers/atm/idt77105.c
--- linux-2.4.20/drivers/atm/idt77105.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/idt77105.c	2003-05-22 22:06:48.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/atm_idt77105.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
@@ -38,6 +39,7 @@
         unsigned char old_mcr;          /* storage of MCR reg while signal lost */
 };
 
+static spinlock_t idt77105_priv_lock = SPIN_LOCK_UNLOCKED;
 
 #define PRIV(dev) ((struct idt77105_priv *) dev->phy_data)
 
@@ -146,12 +148,11 @@
 	unsigned long flags;
 	struct idt77105_stats stats;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
 	memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
 	if (zero)
 		memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
-	restore_flags(flags);
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	if (arg == NULL)
 		return 0;
 	return copy_to_user(arg, &PRIV(dev)->stats,
@@ -269,11 +270,10 @@
 	if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	PRIV(dev)->dev = dev;
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
 	PRIV(dev)->next = idt77105_all;
 	idt77105_all = PRIV(dev);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
         
         /* initialise dev->signal from Good Signal Bit */
@@ -307,11 +307,9 @@
 	idt77105_stats_timer_func(0); /* clear 77105 counters */
 	(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
         
-	cli();
-	if (!start_timer) restore_flags(flags);
-	else {
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
+	if (start_timer) {
 		start_timer = 0;
-		restore_flags(flags);
                 
 		init_timer(&stats_timer);
 		stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
@@ -323,32 +321,11 @@
 		restart_timer.function = idt77105_restart_timer_func;
 		add_timer(&restart_timer);
 	}
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	return 0;
 }
 
 
-static const struct atmphy_ops idt77105_ops = {
-	idt77105_start,
-	idt77105_ioctl,
-	idt77105_int
-};
-
-
-int __init idt77105_init(struct atm_dev *dev)
-{
-	MOD_INC_USE_COUNT;
-
-	dev->phy = &idt77105_ops;
-	return 0;
-}
-
-
-/*
- * TODO: this function should be called through phy_ops
- * but that will not be possible for some time as there is
- * currently a freeze on modifying that structure
- * -- Greg Banks, 13 Sep 1999
- */
 int idt77105_stop(struct atm_dev *dev)
 {
 	struct idt77105_priv *walk, *prev;
@@ -374,30 +351,33 @@
             }
         }
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 
+static const struct atmphy_ops idt77105_ops = {
+	.start = 	idt77105_start,
+	.ioctl =	idt77105_ioctl,
+	.interrupt =	idt77105_int,
+	.stop =		idt77105_stop,
+};
 
-EXPORT_SYMBOL(idt77105_init);
-EXPORT_SYMBOL(idt77105_stop);
-
-MODULE_LICENSE("GPL");
-
-#ifdef MODULE
 
-int init_module(void)
+int idt77105_init(struct atm_dev *dev)
 {
+	dev->phy = &idt77105_ops;
 	return 0;
 }
 
+EXPORT_SYMBOL(idt77105_init);
 
-void cleanup_module(void)
+static void __exit idt77105_exit(void)
 {
         /* turn off timers */
         del_timer(&stats_timer);
         del_timer(&restart_timer);
 }
 
-#endif
+module_exit(idt77105_exit);
+
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/idt77252.c linux-2.4.21-rc3/drivers/atm/idt77252.c
--- linux-2.4.20/drivers/atm/idt77252.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/idt77252.c	2003-05-22 22:06:44.000000000 +0000
@@ -730,7 +730,7 @@
 		struct atm_vcc *vcc = vc->tx_vcc;
 
 		vc->estimator->cells += (skb->len + 47) / 48;
-		if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
+		if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) {
 			u32 cps = vc->estimator->maxcps;
 
 			vc->estimator->cps = cps;
@@ -2025,7 +2025,7 @@
 		atomic_inc(&vcc->stats->tx_err);
 		return -ENOMEM;
 	}
-	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 
 	memcpy(skb_put(skb, 52), cell, 52);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/iphase.c linux-2.4.21-rc3/drivers/atm/iphase.c
--- linux-2.4.20/drivers/atm/iphase.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/iphase.c	2003-05-22 22:06:52.000000000 +0000
@@ -1192,7 +1192,8 @@
 
 	/* Build the DLE structure */  
 	wr_ptr = iadev->rx_dle_q.write;  
-	wr_ptr->sys_pkt_addr = virt_to_bus(skb->data);	  
+	wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+		len, PCI_DMA_FROMDEVICE);
 	wr_ptr->local_pkt_addr = buf_addr;  
 	wr_ptr->bytes = len;	/* We don't know this do we ?? */  
 	wr_ptr->mode = DMA_INT_ENABLE;  
@@ -1311,6 +1312,9 @@
           struct cpcs_trailer *trailer;
           u_short length;
           struct ia_vcc *ia_vcc;
+
+	  pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr,
+	  	len, PCI_DMA_FROMDEVICE);
           /* no VCC related housekeeping done as yet. lets see */  
           vcc = ATM_SKB(skb)->vcc;
 	  if (!vcc) {
@@ -1430,7 +1434,7 @@
 	IADEV *iadev;  
 	struct rx_buf_desc *buf_desc_ptr;  
 	unsigned long rx_pkt_start = 0;  
-	u32 *odle_addr, *dle_addr;  
+	void *dle_addr;  
 	struct abr_vc_table  *abr_vc_table; 
 	u16 *vc_table;  
 	u16 *reass_table;  
@@ -1441,25 +1445,14 @@
   
 	iadev = INPH_IA_DEV(dev);  
   //    spin_lock_init(&iadev->rx_lock); 
-	/* I need to initialize the DLEs somewhere. Lets see what I   
-		need to do for this, hmmm...  
-		- allocate memory for 256 DLEs. make sure that it starts  
-		on a 4k byte address boundary. Program the start address   
-		in Receive List address register.  ..... to do for TX also  
-	   To make sure that it is a 4k byte boundary - allocate 8k and find   
-		4k byte boundary within.  
-		( (addr + (4k-1)) & ~(4k-1) )  
-	*/   
   
-	/* allocate 8k bytes */  
-	odle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
-	if (!odle_addr)  
-	{  
-		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");  
-		return -ENOMEM;
-	}  
-	/* find 4k byte boundary within the 8k allocated */  
-	dle_addr = (u32*)( ((u32)odle_addr+(4096-1)) & ~(4096-1) );  
+	/* Allocate 4k bytes - more aligned than needed (4k boundary) */
+	dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+					&iadev->rx_dle_dma);  
+	if (!dle_addr)  {  
+		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+		goto err_out;
+	}
 	iadev->rx_dle_q.start = (struct dle*)dle_addr;  
 	iadev->rx_dle_q.read = iadev->rx_dle_q.start;  
 	iadev->rx_dle_q.write = iadev->rx_dle_q.start;  
@@ -1468,7 +1461,8 @@
 	DLE that can be used. */  
   
 	/* write the upper 20 bits of the start address to rx list address register */  
-	writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_RX_LIST_ADDR);  
+	writel(iadev->rx_dle_dma & 0xfffff000,
+	       iadev->dma + IPHASE5575_RX_LIST_ADDR);  
 	IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", 
                       (u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR), 
                       *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR));  
@@ -1642,8 +1636,7 @@
 	{  
 		printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
 		dev->number);  
-		kfree(odle_addr);
-		return -ENOMEM;  
+		goto err_free_dle;
 	}  
 	memset(iadev->rx_open, 0, 4*iadev->num_vc);  
         iadev->rxing = 1;
@@ -1651,6 +1644,12 @@
 	/* Mode Register */  
 	writew(R_ONLINE, iadev->reass_reg+MODE_REG);  
 	return 0;  
+
+err_free_dle:
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+			    iadev->rx_dle_dma);  
+err_out:
+	return -ENOMEM;
 }  
   
 
@@ -1715,6 +1714,12 @@
             /* free the DMAed skb */ 
             skb = skb_dequeue(&iadev->tx_dma_q); 
             if (!skb) break;
+
+	    /* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */
+	    if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) {
+		pci_unmap_single(iadev->pci, dle->sys_pkt_addr, skb->len,
+				 PCI_DMA_TODEVICE);
+	    }
             vcc = ATM_SKB(skb)->vcc;
             if (!vcc) {
                   printk("tx_dle_intr: vcc is null\n");
@@ -1884,7 +1889,7 @@
                     return -EINVAL; 
                 }
                 if (vcc->qos.txtp.max_pcr > iadev->LineRate) {
-                   IF_CBR(printk("PCR is not availble\n");)
+                   IF_CBR(printk("PCR is not available\n");)
                    return -1;
                 }
                 vc->type = CBR;
@@ -1894,7 +1899,7 @@
                 }
        } 
 	else  
-           printk("iadev:  Non UBR, ABR and CBR traffic not supportedn"); 
+           printk("iadev:  Non UBR, ABR and CBR traffic not supported\n"); 
         
         iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE;
 	IF_EVENT(printk("ia open_tx returning \n");)  
@@ -1907,7 +1912,7 @@
 	IADEV *iadev;  
 	struct tx_buf_desc *buf_desc_ptr;
 	unsigned int tx_pkt_start;  
-	u32 *dle_addr;  
+	void *dle_addr;  
 	int i;  
 	u_short tcq_st_adr;  
 	u_short *tcq_start;  
@@ -1923,24 +1928,22 @@
  
 	IF_INIT(printk("Tx MASK REG: 0x%0x\n", 
                                 readw(iadev->seg_reg+SEG_MASK_REG));)  
-	/*---------- Initializing Transmit DLEs ----------*/  
-	/* allocating 8k memory for transmit DLEs */  
-	dle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
-	if (!dle_addr)  
-	{  
-		printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n");  
-		return -ENOMEM;
-	}  
-  
-	/* find 4k byte boundary within the 8k allocated */  
-	dle_addr = (u32*)(((u32)dle_addr+(4096-1)) & ~(4096-1));  
+
+	/* Allocate 4k (boundary aligned) bytes */
+	dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+					&iadev->tx_dle_dma);  
+	if (!dle_addr)  {
+		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+		goto err_out;
+	}
 	iadev->tx_dle_q.start = (struct dle*)dle_addr;  
 	iadev->tx_dle_q.read = iadev->tx_dle_q.start;  
 	iadev->tx_dle_q.write = iadev->tx_dle_q.start;  
 	iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES);  
 
 	/* write the upper 20 bits of the start address to tx list address register */  
-	writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_TX_LIST_ADDR);  
+	writel(iadev->tx_dle_dma & 0xfffff000,
+	       iadev->dma + IPHASE5575_TX_LIST_ADDR);  
 	writew(0xffff, iadev->seg_reg+SEG_MASK_REG);  
 	writew(0, iadev->seg_reg+MODE_REG_0);  
 	writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG);  
@@ -1984,23 +1987,28 @@
 		buf_desc_ptr++;		  
 		tx_pkt_start += iadev->tx_buf_sz;  
 	}  
-        iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(caddr_t), GFP_KERNEL);
+        iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(struct cpcs_trailer_desc), GFP_KERNEL);
         if (!iadev->tx_buf) {
             printk(KERN_ERR DEV_LABEL " couldn't get mem\n");
-            return -EAGAIN;
+	    goto err_free_dle;
         }
        	for (i= 0; i< iadev->num_tx_desc; i++)
        	{
+	    struct cpcs_trailer *cpcs;
  
-       	    iadev->tx_buf[i] = kmalloc(sizeof(struct cpcs_trailer),
-                                                           GFP_KERNEL|GFP_DMA);
-            if(!iadev->tx_buf[i]) {                
+       	    cpcs = kmalloc(sizeof(*cpcs), GFP_KERNEL|GFP_DMA);
+            if(!cpcs) {                
 		printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); 
-         	return -EAGAIN;
+		goto err_free_tx_bufs;
             }
+	    iadev->tx_buf[i].cpcs = cpcs;
+	    iadev->tx_buf[i].dma_addr = pci_map_single(iadev->pci,
+		cpcs, sizeof(*cpcs), PCI_DMA_TODEVICE);
         }
         iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
                                    sizeof(struct desc_tbl_t), GFP_KERNEL);
+        if(!iadev->desc_tbl)
+		goto err_free_all_tx_bufs;
   
 	/* Communication Queues base address */  
         i = TX_COMP_Q * iadev->memSize;
@@ -2128,7 +2136,7 @@
         iadev->testTable = kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); 
         if (!iadev->testTable) {
            printk("Get freepage  failed\n");
-           return -EAGAIN; 
+	   goto err_free_desc_tbl;
         }
 	for(i=0; i<iadev->num_vc; i++)  
 	{  
@@ -2137,7 +2145,7 @@
                 iadev->testTable[i] = kmalloc(sizeof(struct testTable_t),
 						GFP_KERNEL);
 		if (!iadev->testTable[i])
-			return -ENOMEM;
+			goto err_free_test_tables;
               	iadev->testTable[i]->lastTime = 0;
  		iadev->testTable[i]->fract = 0;
                 iadev->testTable[i]->vc_status = VC_UBR;
@@ -2193,7 +2201,30 @@
         iadev->tx_pkt_cnt = 0;
         iadev->rate_limit = iadev->LineRate / 3;
   
-	return 0;  
+	return 0;
+
+err_free_test_tables:
+	while (--i >= 0)
+		kfree(iadev->testTable[i]);
+	kfree(iadev->testTable);
+err_free_desc_tbl:
+	kfree(iadev->desc_tbl);
+err_free_all_tx_bufs:
+	i = iadev->num_tx_desc;
+err_free_tx_bufs:
+	while (--i >= 0) {
+		struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+		pci_unmap_single(iadev->pci, desc->dma_addr,
+			sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+		kfree(desc->cpcs);
+	}
+	kfree(iadev->tx_buf);
+err_free_dle:
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+			    iadev->tx_dle_dma);  
+err_out:
+	return -ENOMEM;
 }   
    
 static void ia_int(int irq, void *dev_id, struct pt_regs *regs)  
@@ -2455,6 +2486,33 @@
 	return readl(INPH_IA_DEV(dev)->phy+addr);  
 }  
 
+static void ia_free_tx(IADEV *iadev)
+{
+	int i;
+
+	kfree(iadev->desc_tbl);
+	for (i = 0; i < iadev->num_vc; i++)
+		kfree(iadev->testTable[i]);
+	kfree(iadev->testTable);
+	for (i = 0; i < iadev->num_tx_desc; i++) {
+		struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+		pci_unmap_single(iadev->pci, desc->dma_addr,
+			sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+		kfree(desc->cpcs);
+	}
+	kfree(iadev->tx_buf);
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+			    iadev->tx_dle_dma);  
+}
+
+static void ia_free_rx(IADEV *iadev)
+{
+	kfree(iadev->rx_open);
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+			    iadev->rx_dle_dma);  
+}
+
 #if LINUX_VERSION_CODE >= 0x20312
 static int __init ia_start(struct atm_dev *dev)
 #else
@@ -2462,7 +2520,7 @@
 #endif  
 {  
 	IADEV *iadev;  
-	int error = 1;  
+	int error;  
 	unsigned char phy;  
 	u32 ctrl_reg;  
 	IF_EVENT(printk(">ia_start\n");)  
@@ -2470,7 +2528,8 @@
         if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) {  
                 printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",  
                     dev->number, iadev->irq);  
-                return -EAGAIN;  
+		error = -EAGAIN;
+		goto err_out;
         }  
         /* @@@ should release IRQ on error */  
 	/* enabling memory + master */  
@@ -2480,8 +2539,8 @@
 	{  
                 printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+"  
                     "master (0x%x)\n",dev->number, error);  
-                free_irq(iadev->irq, dev); 
-                return -EIO;  
+		error = -EIO;  
+		goto err_free_irq;
         }  
 	udelay(10);  
   
@@ -2515,15 +2574,11 @@
     
         ia_hw_type(iadev); 
 	error = tx_init(dev);  
-	if (error) {
-           free_irq(iadev->irq, dev);  
-           return error;
-        }  
+	if (error)
+		goto err_free_irq;
 	error = rx_init(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev); 
-          return error;  
-        }
+	if (error)
+		goto err_free_tx;
   
 	ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG);  
        	writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG);   
@@ -2538,33 +2593,36 @@
 
         if (iadev->phy_type &  FE_25MBIT_PHY) {
            ia_mb25_init(iadev);
-           return 0;
-        }
-        if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
+        } else if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
            ia_suni_pm7345_init(iadev);
-           return 0;
-        }
-
-	error = suni_init(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev); 
-          return error;  
-        }
-
-        /* Enable interrupt on loss of signal SUNI_RSOP_CIE 0x10
-           SUNI_RSOP_CIE_LOSE - 0x04
-        */
-        ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10);         
+        } else {
+		error = suni_init(dev);
+		if (error)
+			goto err_free_rx;
+		/* 
+		 * Enable interrupt on loss of signal
+		 * SUNI_RSOP_CIE - 0x10
+		 * SUNI_RSOP_CIE_LOSE - 0x04
+		 */
+		ia_phy_put(dev, ia_phy_get(dev, 0x10) | 0x04, 0x10);
 #ifndef MODULE
-	error = dev->phy->start(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev);
-          return error;
-        }   
+		error = dev->phy->start(dev);
+		if (error)
+			goto err_free_rx;
 #endif
-        /* Get iadev->carrier_detect status */
-        IaFrontEndIntr(iadev);
-	return 0;  
+		/* Get iadev->carrier_detect status */
+		IaFrontEndIntr(iadev);
+	}
+	return 0;
+
+err_free_rx:
+	ia_free_rx(iadev);
+err_free_tx:
+	ia_free_tx(iadev);
+err_free_irq:
+	free_irq(iadev->irq, dev);  
+err_out:
+	return error;
 }  
   
 static void ia_close(struct atm_vcc *vcc)  
@@ -2873,10 +2931,10 @@
         struct tx_buf_desc *buf_desc_ptr;
         int desc;
         int comp_code;
-        unsigned int addr;
-        int total_len, pad, last;
+        int total_len;
         struct cpcs_trailer *trailer;
         struct ia_vcc *iavcc;
+
         iadev = INPH_IA_DEV(vcc->dev);  
         iavcc = INPH_IA_VCC(vcc);
         if (!iavcc->txing) {
@@ -2897,12 +2955,18 @@
           return 0;
         }
         if ((u32)skb->data & 3) {
-           printk("Misaligned SKB\n");
-           if (vcc->pop)
-                 vcc->pop(vcc, skb);
-           else
-                 dev_kfree_skb_any(skb);
-           return 0;
+           /* The copy will end up aligned */
+           struct sk_buff *newskb = skb_copy(skb, GFP_ATOMIC);
+           if(newskb == NULL)
+           {
+	           if (vcc->pop)
+	                 vcc->pop(vcc, skb);
+	           else
+	                 dev_kfree_skb_any(skb);
+	           return 0;
+	   }
+	   kfree(skb);
+	   skb = newskb;
         }       
 	/* Get a descriptor number from our free descriptor queue  
 	   We get the descr number from the TCQ now, since I am using  
@@ -2955,19 +3019,13 @@
 	/* Figure out the exact length of the packet and padding required to 
            make it  aligned on a 48 byte boundary.  */
 	total_len = skb->len + sizeof(struct cpcs_trailer);  
-	last = total_len - (total_len/48)*48;  
-	pad = 48 - last;  
-	total_len = pad + total_len;  
-	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);)  
+	total_len = ((total_len + 47) / 48) * 48;
+	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, total_len - skb->len);)  
  
 	/* Put the packet in a tx buffer */   
-	if (!iadev->tx_buf[desc-1])  
-		printk("couldn't get free page\n");  
-
+	trailer = iadev->tx_buf[desc-1].cpcs;
         IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n",
                   (u32)skb, (u32)skb->data, skb->len, desc);)
-        addr = virt_to_bus(skb->data);
-	trailer = (struct cpcs_trailer*)iadev->tx_buf[desc-1];  
 	trailer->control = 0; 
         /*big endian*/ 
 	trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8);
@@ -2983,6 +3041,7 @@
 	buf_desc_ptr = (struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE);  
 	buf_desc_ptr += desc;	/* points to the corresponding entry */  
 	buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT;   
+	/* Huh ? p.115 of users guide describes this as a read-only register */
         writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG);
 	buf_desc_ptr->vc_index = vcc->vci;
 	buf_desc_ptr->bytes = total_len;  
@@ -2993,7 +3052,8 @@
 	/* Build the DLE structure */  
 	wr_ptr = iadev->tx_dle_q.write;  
 	memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));  
-	wr_ptr->sys_pkt_addr = addr;  
+	wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+		skb->len, PCI_DMA_TODEVICE);
 	wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | 
                                                   buf_desc_ptr->buf_start_lo;  
 	/* wr_ptr->bytes = swap(total_len);	didn't seem to affect ?? */  
@@ -3011,7 +3071,7 @@
 		wr_ptr = iadev->tx_dle_q.start;  
         
         /* Build trailer dle */
-        wr_ptr->sys_pkt_addr = virt_to_bus(iadev->tx_buf[desc-1]);
+        wr_ptr->sys_pkt_addr = iadev->tx_buf[desc-1].dma_addr;
         wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | 
           buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer);
 
@@ -3163,135 +3223,130 @@
 };  
 	  
   
-#if LINUX_VERSION_CODE >= 0x20312
-int __init ia_detect(void)
-#else
-__initfunc(int ia_detect(void)) 
-#endif 
+static int __devinit ia_init_one(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
 {  
 	struct atm_dev *dev;  
 	IADEV *iadev;  
         unsigned long flags;
-        int index = 0;  
-	struct pci_dev *prev_dev;       
-	if (!pci_present()) {  
-		printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n");  
-		return 0;  
-	}  
+	int ret;
+
 	iadev = kmalloc(sizeof(*iadev), GFP_KERNEL); 
-	if (!iadev) return -ENOMEM;  
-        memset((char*)iadev, 0, sizeof(*iadev));
-	prev_dev = NULL;  
-	while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE,  
-		PCI_DEVICE_ID_IPHASE_5575,  prev_dev))) {  
-		IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
-                     iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), 
-                                                 PCI_FUNC(iadev->pci->devfn));)  
-		if (pci_enable_device(iadev->pci)) break;
-		dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
-		if (!dev) break;  
-		IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", 
-                                                             dev->number);)  
-		INPH_IA_DEV(dev) = iadev; 
-                // TODO: multi_board using ia_boards logic in cleanup_module
-		ia_dev[index] = iadev;
-		_ia_dev[index] = dev;
-                IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", 
-                                        (u32)dev, iadev->LineRate);)
-                iadev_count++;
-                spin_lock_init(&iadev->misc_lock);
-                spin_lock_irqsave(&iadev->misc_lock, flags); 
-		if (ia_init(dev) || ia_start(dev)) {  
-			atm_dev_deregister(dev);  
-                        IF_INIT(printk("IA register failed!\n");)
-                        ia_dev[index] = NULL;
-                        _ia_dev[index] = NULL;
-                        iadev_count--;
-                        spin_unlock_irqrestore(&iadev->misc_lock, flags); 
-			return -EINVAL;  
-		}  
-                spin_unlock_irqrestore(&iadev->misc_lock, flags);
-                IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
-		prev_dev = iadev->pci;  
-		iadev->next_board = ia_boards;  
-		ia_boards = dev;  
-		iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);  
-		if (!iadev) break;   
-                memset((char*)iadev, 0, sizeof(*iadev)); 
-		index++;  
-                dev = NULL;
-	}  
-	return index;  
-}  
-  
+	if (!iadev) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	memset(iadev, 0, sizeof(*iadev));
+	iadev->pci = pdev;
 
-#ifdef MODULE  
-  
-int init_module(void)  
-{  
-	IF_EVENT(printk(">ia init_module\n");)  
-	if (!ia_detect()) {  
-		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
-		return -ENXIO;  
-	}  
-   	ia_timer.expires = jiffies + 3*HZ;
-   	add_timer(&ia_timer); 
-   
-	return 0;  
-}  
-  
-  
-void cleanup_module(void)  
-{  
-	struct atm_dev *dev;  
-	IADEV *iadev;  
-	unsigned short command;  
-        int i, j= 0;
- 
-	IF_EVENT(printk(">ia cleanup_module\n");)  
-	if (MOD_IN_USE)  
-		printk("ia: module in use\n");  
-        del_timer(&ia_timer);
-	while(ia_dev[j])  
-	{  
-		dev = ia_boards;  
-		iadev = INPH_IA_DEV(dev);  
-		ia_boards = iadev->next_board;  
-                
-        	/* disable interrupt of lost signal */
-        	ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); 
-        	udelay(1);
-
-      		/* De-register device */  
-      		atm_dev_deregister(dev);  
-		IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
-		for (i= 0; i< iadev->num_tx_desc; i++)
-                        kfree(iadev->tx_buf[i]);
-                kfree(iadev->tx_buf);
-      		/* Disable memory mapping and busmastering */  
-		if (pci_read_config_word(iadev->pci,  
-					     PCI_COMMAND, &command) != 0)  
-      		{  
-         		printk("ia: can't read PCI_COMMAND.\n");  
-      		}  
-      		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);  
-      		if (pci_write_config_word(iadev->pci,  
-					      PCI_COMMAND, command) != 0)  
-      		{  
-         		printk("ia: can't write PCI_COMMAND.\n");  
-      		}  
-      		free_irq(iadev->irq, dev);  
-      		iounmap((void *) iadev->base);  
-      		kfree(iadev);  
-                j++;
-	}  
-	/* and voila whatever we tried seems to work. I don't know if it will  
-		fix suni errors though. Really doubt that. */  
-        for (i = 0; i<8; i++) {
-               ia_dev[i] =  NULL;
-              _ia_dev[i] = NULL;
-        }
-}  
+	IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
+		pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));)
+	if (pci_enable_device(pdev)) {
+		ret = -ENODEV;
+		goto err_out_free_iadev;
+	}
+	dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_out_disable_dev;
+	}
+	INPH_IA_DEV(dev) = iadev; 
+	IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);)
+	IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev,
+		iadev->LineRate);)
+
+	ia_dev[iadev_count] = iadev;
+	_ia_dev[iadev_count] = dev;
+	iadev_count++;
+	spin_lock_init(&iadev->misc_lock);
+	/* First fixes first. I don't want to think about this now. */
+	spin_lock_irqsave(&iadev->misc_lock, flags); 
+	if (ia_init(dev) || ia_start(dev)) {  
+		IF_INIT(printk("IA register failed!\n");)
+		iadev_count--;
+		ia_dev[iadev_count] = NULL;
+		_ia_dev[iadev_count] = NULL;
+		spin_unlock_irqrestore(&iadev->misc_lock, flags); 
+		ret = -EINVAL;
+		goto err_out_deregister_dev;
+	}
+	spin_unlock_irqrestore(&iadev->misc_lock, flags); 
+	IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
 
-#endif  
+	iadev->next_board = ia_boards;  
+	ia_boards = dev;  
+
+	pci_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_out_deregister_dev:
+	atm_dev_deregister(dev);  
+err_out_disable_dev:
+	pci_disable_device(pdev);
+err_out_free_iadev:
+	kfree(iadev);
+err_out:
+	return ret;
+}
+
+static void __devexit ia_remove_one(struct pci_dev *pdev)
+{
+	struct atm_dev *dev = pci_get_drvdata(pdev);
+	IADEV *iadev = INPH_IA_DEV(dev);
+
+	ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); 
+	udelay(1);
+
+	/* De-register device */  
+      	free_irq(iadev->irq, dev);
+	iadev_count--;
+	ia_dev[iadev_count] = NULL;
+	_ia_dev[iadev_count] = NULL;
+	atm_dev_deregister(dev);
+	IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
+
+      	iounmap((void *) iadev->base);  
+	pci_disable_device(pdev);
+
+	ia_free_rx(iadev);
+	ia_free_tx(iadev);
+
+      	kfree(iadev);
+}
+
+static struct pci_device_id ia_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_IPHASE, 0x0008, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_IPHASE, 0x0009, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, ia_pci_tbl);
+
+static struct pci_driver ia_driver = {
+	.name =         DEV_LABEL,
+	.id_table =     ia_pci_tbl,
+	.probe =        ia_init_one,
+	.remove =       __devexit_p(ia_remove_one),
+};
+
+static int __init ia_init_module(void)
+{
+	int ret;
+
+	ret = pci_module_init(&ia_driver);
+	if (ret >= 0) {
+		ia_timer.expires = jiffies + 3*HZ;
+		add_timer(&ia_timer); 
+	}
+	return ret;
+}
+
+static void __exit ia_cleanup_module(void)
+{
+	pci_unregister_driver(&ia_driver);
+
+        del_timer(&ia_timer);
+}
 
+module_init(ia_init_module);
+module_exit(ia_cleanup_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/iphase.h linux-2.4.21-rc3/drivers/atm/iphase.h
--- linux-2.4.20/drivers/atm/iphase.h	2001-02-04 18:05:29.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/iphase.h	2003-05-22 22:06:38.000000000 +0000
@@ -200,7 +200,13 @@
 	u_short length;  
 	u_int	crc32;  
 };  
-  
+
+struct cpcs_trailer_desc
+{
+	struct cpcs_trailer *cpcs;
+	dma_addr_t dma_addr;
+};
+
 struct ia_vcc 
 { 
 	int rxing;	 
@@ -272,6 +278,7 @@
 #define DLE_ENTRIES 256  
 #define DMA_INT_ENABLE 0x0002	/* use for both Tx and Rx */  
 #define TX_DLE_PSI 0x0001  
+#define DLE_TOTAL_SIZE (sizeof(struct dle)*DLE_ENTRIES)
   
 /* Descriptor List Entries (DLE) */  
 struct dle 
@@ -1017,7 +1024,7 @@
         struct wait_queue     *close_wait;
         struct wait_queue     *timeout_wait;
 #endif
-	caddr_t *tx_buf;  
+	struct cpcs_trailer_desc *tx_buf;
         u16 num_tx_desc, tx_buf_sz, rate_limit;
         u32 tx_cell_cnt, tx_pkt_cnt;
         u32 MAIN_VC_TABLE_ADDR, EXT_VC_TABLE_ADDR, ABR_SCHED_TABLE_ADDR;
@@ -1063,7 +1070,9 @@
         struct desc_tbl_t *desc_tbl;
         u_short host_tcq_wr;
         struct testTable_t **testTable;
-} IADEV;  
+	dma_addr_t tx_dle_dma;
+	dma_addr_t rx_dle_dma;
+} IADEV;
   
   
 #define INPH_IA_DEV(d) ((IADEV *) (d)->dev_data)  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/nicstar.c linux-2.4.21-rc3/drivers/atm/nicstar.c
--- linux-2.4.20/drivers/atm/nicstar.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/nicstar.c	2003-05-22 22:06:38.000000000 +0000
@@ -359,11 +359,8 @@
 
       card = cards[i];
 
-#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
-      if (card->max_pcr == ATM_25_PCR) {
-        idt77105_stop(card->atmdev);
-      }
-#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
+      if (card->atmdev->phy && card->atmdev->phy->stop)
+        card->atmdev->phy->stop(card->atmdev);
 
       /* Stop everything */
       writel(0x00000000, card->membase + CFG);
@@ -549,11 +546,6 @@
    card->atmdev = NULL;
    card->pcidev = pcidev;
    card->membase = pci_resource_start(pcidev, 1);
-#ifdef __powerpc__
-   /* Compensate for different memory map between host CPU and PCI bus.
-      Shouldn't we use a macro for this? */
-   card->membase += KERNELBASE;
-#endif /* __powerpc__ */
    card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE);
    if (card->membase == 0)
    {
@@ -964,22 +956,13 @@
    card->atmdev->phy = NULL;
 
 #ifdef CONFIG_ATM_NICSTAR_USE_SUNI
-   if (card->max_pcr == ATM_OC3_PCR) {
+   if (card->max_pcr == ATM_OC3_PCR)
       suni_init(card->atmdev);
-
-      MOD_INC_USE_COUNT;
-      /* Can't remove the nicstar driver or the suni driver would oops */
-   }
 #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
 
 #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
-   if (card->max_pcr == ATM_25_PCR) {
+   if (card->max_pcr == ATM_25_PCR)
       idt77105_init(card->atmdev);
-      /* Note that for the IDT77105 PHY we don't need the awful
-       * module count hack that the SUNI needs because we can
-       * stop the '105 when the nicstar module is cleaned up.
-       */
-   }
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
    if (card->atmdev->phy && card->atmdev->phy->start)
@@ -1597,7 +1580,7 @@
          
 	 fill_tst(card, n, vc);
       }
-      else /* not CBR */
+      else if (vcc->qos.txtp.traffic_class == ATM_UBR)
       {
          vc->cbr_scd = 0x00000000;
 	 vc->scq = card->scq0;
@@ -2386,6 +2369,7 @@
          {
             push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
                         0, 0);
+            atomic_inc(&vcc->stats->rx_drop);
          }
          else
 	 {
@@ -2413,6 +2397,7 @@
             {
                push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
                            0, 0);
+               atomic_inc(&vcc->stats->rx_drop);
             }
             else
 	    {
@@ -2437,6 +2422,7 @@
             {
                push_rxbufs(card, BUF_LG, (u32) skb,
                            (u32) virt_to_bus(skb->data), 0, 0);
+               atomic_inc(&vcc->stats->rx_drop);
             }
             else
             {
@@ -2521,6 +2507,7 @@
             }
 	    else
 	       dev_kfree_skb_any(hb);
+	    atomic_inc(&vcc->stats->rx_drop);
          }
          else
 	 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/suni.c linux-2.4.21-rc3/drivers/atm/suni.c
--- linux-2.4.20/drivers/atm/suni.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/suni.c	2003-05-22 22:06:39.000000000 +0000
@@ -233,8 +233,6 @@
 	if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
 		return -ENOMEM;
 
-	MOD_INC_USE_COUNT;
-
 	PRIV(dev)->dev = dev;
 	spin_lock_irqsave(&sunis_lock,flags);
 	first = !sunis;
@@ -280,7 +278,6 @@
 	spin_unlock_irqrestore(&sunis_lock,flags);
 	kfree(PRIV(dev));
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -293,14 +290,14 @@
 };
 
 
-int __init suni_init(struct atm_dev *dev)
+int suni_init(struct atm_dev *dev)
 {
 	unsigned char mri;
 
 	mri = GET(MRI); /* reset SUNI */
 	PUT(mri | SUNI_MRI_RESET,MRI);
 	PUT(mri,MRI);
-	PUT(0,MT); /* disable all tests */
+	PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */
 	REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET,
 	    TPOP_APM); /* use SONET */
 	REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP,
@@ -310,24 +307,6 @@
 	return 0;
 }
 
-
 EXPORT_SYMBOL(suni_init);
 
-
 MODULE_LICENSE("GPL");
-
-#ifdef MODULE
-
-
-int init_module(void)
-{
-	return 0;
-}
-
-
-void cleanup_module(void)
-{
-	/* Nay */
-}
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/suni.h linux-2.4.21-rc3/drivers/atm/suni.h
--- linux-2.4.20/drivers/atm/suni.h	2000-12-11 21:21:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/atm/suni.h	2003-05-22 22:06:27.000000000 +0000
@@ -198,6 +198,7 @@
 #define SUNI_MT_IOTST		0x04	/* RW, enable test mode */
 #define SUNI_MT_DBCTRL		0x08	/* W, control data bus by CSB pin */
 #define SUNI_MT_PMCTST		0x10	/* W, PMC test mode */
+#define SUNI_MT_DS27_53		0x80	/* RW, select between 8- or 16- bit */
 
 
 #define SUNI_IDLE_PATTERN       0x6a    /* idle pattern */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/Makefile linux-2.4.21-rc3/drivers/block/Makefile
--- linux-2.4.20/drivers/block/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -10,7 +10,7 @@
 
 O_TARGET := block.o
 
-export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o
+export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o acsi.o
 
 obj-y	:= ll_rw_blk.o blkpg.o genhd.o elevator.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/amiflop.c linux-2.4.21-rc3/drivers/block/amiflop.c
--- linux-2.4.20/drivers/block/amiflop.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/amiflop.c	2003-05-22 22:06:43.000000000 +0000
@@ -333,7 +333,7 @@
 
 	get_fdc(drive);
 	save_flags (flags);
-	sti();
+	cli();
 
 	selected = -1;
 
@@ -366,10 +366,8 @@
 		unit[nr].motor = 1;
 		fd_select(nr);
 
-		del_timer(&motor_on_timer);
 		motor_on_timer.data = nr;
-		motor_on_timer.expires = jiffies + HZ/2;
-		add_timer(&motor_on_timer);
+		mod_timer(&motor_on_timer, jiffies + HZ/2);
 
 		on_attempts = 10;
 		sleep_on (&motor_wait);
@@ -427,11 +425,9 @@
 	int drive;
 
 	drive = nr & 3;
-	del_timer(motor_off_timer + drive);
-	motor_off_timer[drive].expires = jiffies + 3*HZ;
 	/* called this way it is always from interrupt */
 	motor_off_timer[drive].data = nr | 0x80000000;
-	add_timer(motor_off_timer + nr);
+	mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
 }
 
 static int fd_calibrate(int drive)
@@ -1466,10 +1462,7 @@
 
 			unit[drive].dirty = 1;
 		        /* reset the timer */
-		        del_timer (flush_track_timer + drive);
-			    
-			flush_track_timer[drive].expires = jiffies + 1;
-			add_timer (flush_track_timer + drive);
+			mod_timer(flush_track_timer + drive, jiffies + 1);
 			restore_flags (flags);
 			break;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.c linux-2.4.21-rc3/drivers/block/cciss.c
--- linux-2.4.20/drivers/block/cciss.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cciss.c	2003-05-22 22:06:52.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SMART2 Controllers
- *    Copyright 2000 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
+ *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. 
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 
@@ -44,12 +44,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.42)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,42)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.42");
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -66,6 +67,12 @@
                         0x0E11, 0x4082, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
                         0x0E11, 0x4083, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409A, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409B, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409C, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -77,15 +84,21 @@
  *  access = Address of the struct of function pointers 
  */
 static struct board_type products[] = {
-	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
+	{ 0x40700E11, "Smart Array 5300", &SA5_access},
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
 	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
+	{ 0x409A0E11, "Smart Array 641", &SA5_access},
+	{ 0x409B0E11, "Smart Array 642", &SA5_access},
+	{ 0x409C0E11, "Smart Array 6400", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
 #define MAX_CONFIG_WAIT 1000 
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD 	 128
 #define NR_CMDS		 128 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -104,6 +117,9 @@
 
 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(int cltr, int opened_vol, __u64 requested_lun);
+static int cciss_rescan_disk(int cltr, int logvol);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -130,6 +146,11 @@
 
 #include "cciss_scsi.c"		/* For SCSI tape support */
 
+#define ENG_GIG	1048576000
+#define ENG_GIG_FACTOR (ENG_GIG/512)
+#define	RAID_UNKNOWN 6
+static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG",
+				   "UNKNOWN"};
 /*
  * Report information about this controller.
  */
@@ -137,53 +158,67 @@
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
 		int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
-
-        ctlr = h->ctlr;
-        size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-                "       Board ID: 0x%08lx\n"
-		"       Firmware Version: %c%c%c%c\n"
-                "       Memory Address: 0x%08lx\n"
-                "       IRQ: %d\n"
-                "       Logical drives: %d\n"
-                "       Current Q depth: %d\n"
-		"       Current # commands on controller %d\n"
-                "       Max Q depth since init: %d\n"
-		"       Max # commands on controller since init: %d\n"
-		"       Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned long)h->vaddr,
-                (unsigned int)h->intr,
-                h->num_luns, 
-                h->Qdepth, h->commands_outstanding,
-		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t*)data;
+	drive_info_struct *drv;
+	unsigned long flags;
+	unsigned int vol_sz, vol_sz_frac;
 
-        pos += size; len += size;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+		
+	ctlr = h->ctlr;
+	size = sprintf(buffer, "%s: HP %s Controller\n"
+ 		"Board ID: 0x%08lx\n"
+		"Firmware Version: %c%c%c%c\n"
+ 		"IRQ: %d\n"
+ 		"Logical drives: %d\n"
+ 		"Current Q depth: %d\n"
+ 		"Current # commands on controller: %d\n"
+ 		"Max Q depth since init: %d\n"
+		"Max # commands on controller since init: %d\n"
+		"Max SG entries since init: %d\n\n",
+  		h->devname,
+  		h->product_name,
+  		(unsigned long)h->board_id,
+  		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
+  		(unsigned int)h->intr,
+  		h->num_luns, 
+  		h->Qdepth, h->commands_outstanding,
+  		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++) {
-                drv = &h->drv[i];
-                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;
-        }
-
-	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
-                        h->nr_allocs, h->nr_frees);
-        pos += size; len += size;
-
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
-        return len;
+	for(i=0; i<=h->highest_lun; i++) {
+		drv = &h->drv[i];
+		if (drv->nr_blocks == 0)
+			continue;
+		vol_sz = drv->nr_blocks/ENG_GIG_FACTOR; 
+		vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR;
+
+		if (drv->raid_level > 5)
+			drv->raid_level = RAID_UNKNOWN;
+		size = sprintf(buffer+len, "cciss/c%dd%d:"
+				"\t%4d.%02dGB\tRAID %s\n",
+		       		 ctlr, i, vol_sz,vol_sz_frac,
+				 raid_label[drv->raid_level]);
+		pos += size, len += size;
+        }
+
+	*eof = 1;
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	h->busy_configuring = 0;
+	return len;
 }
 
 static int
@@ -197,16 +232,19 @@
 	int rc;
 #endif
 
-	if (count > sizeof(cmd)-1) return -EINVAL;
-	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	if (count > sizeof(cmd)-1) 
+		return -EINVAL;
+	if (copy_from_user(cmd, buffer, count)) 
+		return -EFAULT;
 	cmd[count] = '\0';
-	len = strlen(cmd);	// safe???
+	len = strlen(cmd);	
 	if (cmd[len-1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
 			rc = cciss_engage_scsi(h->ctlr);
-			if (rc != 0) return -rc;
+			if (rc != 0) 
+				return -rc;
 			return count;
 		}
 		/* might be nice to have "disengage" too, but it's not
@@ -225,8 +263,10 @@
 
 	if (proc_cciss == NULL) {
 		proc_cciss = proc_mkdir("cciss", proc_root_driver);
-		if (!proc_cciss)
+		if (!proc_cciss) {
+			printk("cciss:  proc_mkdir failed\n");
 			return;
+		}
 	}
 
 	pde = create_proc_read_entry(hba[i]->devname,
@@ -250,11 +290,10 @@
 	u64bit temp64;
 	dma_addr_t cmd_dma_handle, err_dma_handle;
 
-	if (!get_from_pool)
-	{
+	if (!get_from_pool) {
 		c = (CommandList_struct *) pci_alloc_consistent(
 			h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-        	if(c==NULL)
+        	if (c==NULL)
                  	return NULL;
 		memset(c, 0, sizeof(CommandList_struct));
 
@@ -310,8 +349,7 @@
 	int i;
 	u64bit temp64;
 
-	if( !got_from_pool)
-	{ 
+	if (!got_from_pool) { 
 		temp64.val32.lower = c->ErrDesc.Addr.lower;
 		temp64.val32.upper = c->ErrDesc.Addr.upper;
 		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
@@ -336,24 +374,22 @@
 	
 	/* Loop through each real device */ 
 	hba[ctlr]->gendisk.nr_real = 0; 
-	for(i=0; i< NWD; i++)
-	{
+	for(i=0; i< NWD; i++) {
 		drv = &(hba[ctlr]->drv[i]);
-		if( !(drv->nr_blocks))
+		if (!(drv->nr_blocks))
 			continue;
 		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
 		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
 
 		/* for each partition */ 
-		for(j=0; j<MAX_PART; j++)
-		{
+		for(j=0; j<MAX_PART; j++) {
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
 			hba[ctlr]->hardsizes[ (i<<NWD_SHIFT) + j] = 
 				drv->block_size;
 		}
-		hba[ctlr]->gendisk.nr_real++;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -371,13 +407,23 @@
 		return -ENXIO;
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
-	 * so array config can still work. I don't think I really like this,
+	 * so array config can still work. Root is also allowed to open any
+	 * volume that has a LUN ID, so it can issue IOCTL to reread the
+	 * disk information.  I don't think I really like this.
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
 	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) { /* not online? */
-		if (MINOR(inode->i_rdev) != 0)	 /* not node 0? */
-			return -ENXIO;
+		if (MINOR(inode->i_rdev) != 0) {	 /* not node 0? */
+			/* if not node 0 make sure it is a partition = 0 */
+			if (MINOR(inode->i_rdev) & 0x0f) {
+				return -ENXIO;
+				/* if it is, make sure we have a LUN ID */
+			} else if (hba[ctlr]->drv[MINOR(inode->i_rdev)
+					>> NWD_SHIFT].LunID == 0) {
+				return -ENXIO;
+			}
+		}
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 	}
@@ -419,8 +465,8 @@
 #endif /* CCISS_DEBUG */ 
 	
 	switch(cmd) {
-	case HDIO_GETGEO:
-	{
+	   case HDIO_GETGEO:
+	   {
 		struct hd_geometry driver_geo;
 		if (hba[ctlr]->drv[dsk].cylinders) {
 			driver_geo.heads = hba[ctlr]->drv[dsk].heads;
@@ -437,8 +483,8 @@
 		if (copy_to_user((void *) arg, &driver_geo,
 				sizeof( struct hd_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
+		return 0;
+	   }
 	case HDIO_GETGEO_BIG:
 	{
 		struct hd_big_geometry driver_geo;
@@ -457,18 +503,14 @@
 		if (copy_to_user((void *) arg, &driver_geo,  
 				sizeof( struct hd_big_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
-	case BLKGETSIZE:
-		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
-		return 0;
-	case BLKGETSIZE64:
-		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
 		return 0;
+	}
 	case BLKRRPART:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		return revalidate_logvol(inode->i_rdev, 1);
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
@@ -479,30 +521,32 @@
 	case BLKPG:
 	case BLKELVGET:
 	case BLKELVSET:
-		return( blk_ioctl(inode->i_rdev, cmd, arg));
+		return blk_ioctl(inode->i_rdev, cmd, arg);
 	case CCISS_GETPCIINFO:
 	{
 		cciss_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pdev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pdev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
 		if (copy_to_user((void *) arg, &pciinfo,  sizeof( cciss_pci_info_struct )))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}	
 	case CCISS_GETINTINFO:
 	{
 		cciss_coalint_struct intinfo;
 		ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
 		intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
 		if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct )))
 			return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETINTINFO:
         {
@@ -511,25 +555,21 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;	
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;	
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
 			return -EFAULT;
-		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
-		{
-//			printk("cciss_ioctl: delay and count cannot be 0\n");
-			return( -EINVAL);
+		if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) {
+			return -EINVAL;
 		}
+
 		spin_lock_irqsave(&io_request_lock, flags);
 		/* Can only safely update if no commands outstanding */ 
-		if (c->commands_outstanding > 0 )
-		{
-//			printk("cciss_ioctl: cannot change coalasing "
-//				"%d commands outstanding on controller\n", 
-//					c->commands_outstanding);
+		if (c->commands_outstanding > 0 ) {
 			spin_unlock_irqrestore(&io_request_lock, flags);
-			return(-EINVAL);
+			return -EINVAL;
 		}
 		/* Update the field, and then ring the doorbell */ 
 		writel( intinfo.delay, 
@@ -538,8 +578,7 @@
                         &(c->cfgtable->HostWrite.CoalIntCount));
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -548,8 +587,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 	case CCISS_GETNODENAME:
         {
@@ -557,12 +596,13 @@
                 ctlr_info_t *c = hba[ctlr];
 		int i; 
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		for(i=0;i<16;i++)
 			NodeName[i] = readb(&c->cfgtable->ServerName[i]);
                 if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type)))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETNODENAME:
 	{
@@ -571,8 +611,10 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		
 		if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
 			return -EFAULT;
@@ -585,8 +627,7 @@
 			
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -595,8 +636,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 
 	case CCISS_GETHEARTBEAT:
@@ -604,45 +645,68 @@
                 Heartbeat_type heartbeat;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 heartbeat = readl(&c->cfgtable->HeartBeat);
                 if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETBUSTYPES:
         {
                 BusTypes_type BusTypes;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 BusTypes = readl(&c->cfgtable->BusTypes);
                 if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) ))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETFIRMVER:
         {
 		FirmwareVer_type firmware;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		memcpy(firmware, hba[ctlr]->firm_ver, 4);
 
                 if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
         case CCISS_GETDRIVVER:
         {
 		DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+                if (!arg) 
+			return -EINVAL;
 
                 if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) ))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
+	case CCISS_RESCANDISK:
+	{
+		return cciss_rescan_disk(ctlr, dsk);
+	}
+	case CCISS_DEREGDISK:
+		return deregister_disk(ctlr,dsk);
+
+	case CCISS_REGNEWD:
+		return register_new_disk(ctlr, dsk, 0);
+	case CCISS_REGNEWDISK:
+	{
+		__u64 new_logvol;
 
+		if (!arg) 
+			return -EINVAL;
+		if (copy_from_user(&new_logvol, (void *) arg, 
+			sizeof( __u64)))
+			return -EFAULT;
+		return register_new_disk(ctlr, dsk, new_logvol);
+	}
 	case CCISS_GETLUNINFO:
 	{
 		LogvolInfo_struct luninfo;
@@ -656,14 +720,14 @@
   		start = (dsk << NWD_SHIFT);
 		for(i=1; i <MAX_PART; i++) {
 			int minor = start+i;
-			if(hba[ctlr]->sizes[minor] != 0)
+			if (hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
 		}
 		luninfo.num_parts = num_parts;
 		if (copy_to_user((void *) arg, &luninfo,
 				sizeof( LogvolInfo_struct) ))
 			return -EFAULT;
-		return(0);
+		return 0;
 	}
 	case CCISS_PASSTHRU:
 	{
@@ -675,28 +739,28 @@
 		unsigned long flags;
 		DECLARE_COMPLETION(wait);
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 	
-		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
 
 		if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) ))
 			return -EFAULT;
-		if((iocommand.buf_size < 1) && 
-				(iocommand.Request.Type.Direction != XFER_NONE))
-		{	
+		if ((iocommand.buf_size < 1) && 
+				(iocommand.Request.Type.Direction 
+				 	!= XFER_NONE)) {	
 			return -EINVAL;
 		} 
 		/* Check kmalloc limits */
-		if(iocommand.buf_size > 128000)
+		if (iocommand.buf_size > 128000)
 			return -EINVAL;
-		if(iocommand.buf_size > 0)
-		{
+		if (iocommand.buf_size > 0) {
 			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-			if( buff == NULL) 
-				return -EFAULT;
+			if (buff == NULL) 
+				return -ENOMEM;
 		}
-		if (iocommand.Request.Type.Direction == XFER_WRITE)
-		{
+		if (iocommand.Request.Type.Direction == XFER_WRITE) {
 			/* Copy the data into the buffer we created */ 
 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
 			{
@@ -704,40 +768,37 @@
 				return -EFAULT;
 			}
 		}
-		if ((c = cmd_alloc(h , 0)) == NULL)
-		{
+		if ((c = cmd_alloc(h , 0)) == NULL) {
 			kfree(buff);
 			return -ENOMEM;
 		}
-			// Fill in the command type 
+			/* Fill in the command type */
 		c->cmd_type = CMD_IOCTL_PEND;
-			// Fill in Command Header 
-		c->Header.ReplyQueue = 0;  // unused in simple mode
-		if( iocommand.buf_size > 0) 	// buffer to fill 
-		{
+			/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
 			c->Header.SGList = 1;
 			c->Header.SGTotal= 1;
-		} else	// no buffers to fill  
-		{
+		} else	{  /* no buffers to fill  */
 			c->Header.SGList = 0;
                 	c->Header.SGTotal= 0;
 		}
 		c->Header.LUN = iocommand.LUN_info;
-		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
 		
-		// Fill in Request block 
+		/* Fill in Request block */
 		c->Request = iocommand.Request; 
 	
-		// Fill in the scatter gather information
-		if (iocommand.buf_size > 0 ) 
-		{
+		/* Fill in the scatter gather information */
+		if (iocommand.buf_size > 0 ) {
 			temp64.val = pci_map_single( h->pdev, buff,
                                         iocommand.buf_size, 
                                 PCI_DMA_BIDIRECTIONAL);	
 			c->SG[0].Addr.lower = temp64.val32.lower;
 			c->SG[0].Addr.upper = temp64.val32.upper;
 			c->SG[0].Len = iocommand.buf_size;
-			c->SG[0].Ext = 0;  // we are not chaining
+			c->SG[0].Ext = 0;  /* we are not chaining */
 		}
 		c->waiting = &wait;
 
@@ -758,18 +819,17 @@
 
 		/* Copy the error information out */ 
 		iocommand.error_info = *(c->err_info);
-		if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
-		{
+		if (copy_to_user((void *) arg, &iocommand, 
+				sizeof( IOCTL_Command_struct) ) ) {
 			kfree(buff);
 			cmd_free(h, c, 0);
-			return( -EFAULT);	
+			return( -EFAULT);
 		} 	
 
-		if (iocommand.Request.Type.Direction == XFER_READ)
-                {
+		if (iocommand.Request.Type.Direction == XFER_READ) {
                         /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
-			{
+                        if (copy_to_user(iocommand.buf, buff, 
+						iocommand.buf_size)) {
                         	kfree(buff);
 				cmd_free(h, c, 0);
 				return -EFAULT;
@@ -777,9 +837,149 @@
                 }
                 kfree(buff);
 		cmd_free(h, c, 0);
-                return(0);
+                return 0;
 	} 
+	case CCISS_BIG_PASSTHRU:
+	{
+		BIG_IOCTL_Command_struct iocommand;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		char 	*buff[MAXSGENTRIES] = {NULL,};
+		int	buff_size[MAXSGENTRIES] = {0,};
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
 
+		if (!arg) 
+			return -EINVAL;
+		
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+
+		if (copy_from_user(&iocommand, (void *) arg, sizeof( BIG_IOCTL_Command_struct) ))
+			return -EFAULT;
+		if ((iocommand.buf_size < 1) && 
+			(iocommand.Request.Type.Direction != XFER_NONE)) {
+			return -EINVAL;
+		} 
+		/* Check kmalloc limits  using all SGs */
+		if (iocommand.malloc_size > MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (iocommand.buf_size > iocommand.malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		if (iocommand.buf_size > 0) {
+			__u32   size_left_alloc = iocommand.buf_size;
+			BYTE    *data_ptr = (BYTE *) iocommand.buf;
+			while (size_left_alloc > 0) {
+				buff_size[sg_used] = (size_left_alloc 
+							> iocommand.malloc_size)
+					? iocommand.malloc_size : size_left_alloc;
+				buff[sg_used] = kmalloc( buff_size[sg_used], 
+						GFP_KERNEL);
+				if (buff[sg_used] == NULL) {
+					status = -ENOMEM;
+					goto cleanup1;
+				}
+				if (iocommand.Request.Type.Direction == 
+						XFER_WRITE)
+				   /* Copy the data into the buffer created */
+				   if (copy_from_user(buff[sg_used], data_ptr, 
+						buff_size[sg_used])) {
+					status = -ENOMEM;
+					goto cleanup1;			
+				   }
+				size_left_alloc -= buff_size[sg_used];
+				data_ptr += buff_size[sg_used];
+				sg_used++;
+			}
+			
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		/* Fill in the command type */
+		c->cmd_type = CMD_IOCTL_PEND;
+		/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
+			c->Header.SGList = sg_used;
+			c->Header.SGTotal= sg_used;
+		} else	{	/* no buffers to fill */
+			c->Header.SGList = 0;
+			c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = iocommand.LUN_info;
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
+		
+	/* Fill in Request block */
+	c->Request = iocommand.Request; 
+	/* Fill in the scatter gather information */
+	if (iocommand.buf_size > 0 ) {
+		int i;
+		for(i=0; i< sg_used; i++) {
+			temp64.val = pci_map_single( h->pdev, buff[i], 
+					buff_size[i], 
+					PCI_DMA_BIDIRECTIONAL);
+
+			c->SG[i].Addr.lower = temp64.val32.lower;
+			c->SG[i].Addr.upper = temp64.val32.upper;
+			c->SG[i].Len = buff_size[i];
+			c->SG[i].Ext = 0;  /* we are not chaining */
+		}
+	}
+	c->waiting = &wait;
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+	/* unlock the buffers from DMA */
+	for(i=0; i< sg_used; i++) {
+		temp64.val32.lower = c->SG[i].Addr.lower;
+		temp64.val32.upper = c->SG[i].Addr.upper;
+		pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+	}
+	/* Copy the error information out */
+		iocommand.error_info = *(c->err_info);
+		if (copy_to_user((void *) arg, &iocommand, 
+					sizeof( IOCTL_Command_struct) ) ) {
+				cmd_free(h, c, 0);
+				status = -EFAULT;
+				goto cleanup1;
+		}
+		if (iocommand.Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) iocommand.buf;
+	        	for(i=0; i< sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+		
+
+cleanup1:
+		for(i=0; i< sg_used; i++) {
+			if (buff[i] != NULL)
+				kfree(buff[i]);
+		}
+		return status;
+	}
 	default:
 		return -EBADRQC;
 	}
@@ -837,6 +1037,642 @@
 #endif /* CCISS_DEBUG */ 
 	return revalidate_logvol(dev, 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(&io_request_lock, flags);
+	/* make sure logical volume is NOT is use */
+	if (h->drv[logvol].usage_count > 1 || h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* invalidate the devices and deregister the disk */
+	max_p = gdev->max_p;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		/* printk("invalidating( %d %d)\n", ctlr, minor); */
+		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 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].cylinders = 0;
+	h->drv[logvol].LunID = 0;
+	h->busy_configuring = 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;
+	DECLARE_COMPLETION(wait);
+
+	if ((c = cmd_alloc(h , 0)) == NULL)
+		return -ENOMEM;
+	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;  /* tag is phys addr of cmd */
+	/* 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;
+			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;
+			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%x 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 */
+	}
+
+resend_cmd2:
+	c->waiting = &wait;
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);
+
+
+	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);
+				if (c->retry_count < MAX_CMD_RETRIES) 
+				{ 
+					printk(KERN_WARNING "retrying cmd\n"); 
+					c->retry_count++; 
+					/* erase the old error */ 
+					/* information */ 
+					memset(c->err_info, 0, 
+						sizeof(ErrorInfo_struct)); 
+					return_status = IO_OK;
+					INIT_COMPLETION(wait);
+					goto resend_cmd2;
+					
+				}
+				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;
+		}
+	}
+
+	/* unlock the buffers from DMA */
+	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+			size, PCI_DMA_BIDIRECTIONAL);
+	cmd_free(h, c, 0);
+	return return_status;
+}
+static int register_new_disk(int ctlr, int opened_vol, __u64 requested_lun)
+{
+	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;
+	unsigned long flags;
+	int req_lunid = (int) (requested_lun & (__u64) 0xffffffff);
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->num_luns >= CISS_MAX_LUN) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EINVAL;
+	}
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	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);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	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);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+
+	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;
+		h->busy_configuring = 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 {	/* new lun found */
+			
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			if (req_lunid)  /* we are looking for a specific lun */
+			{
+				if (lunid != req_lunid)
+				{
+#ifdef CCISS_DEBUG
+					printk("new lun %x is not %x\n",
+							lunid, req_lunid);
+#endif /* CCISS_DEBUG */
+					continue;
+				}
+			}
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;
+		}
+	}
+	if (!new_lun_found) {
+		printk(KERN_DEBUG "cciss:  New Logical Volume not found\n");
+		h->busy_configuring = 0;
+		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");
+		h->busy_configuring = 0;
+		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 < logvol)
+		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; /* secs/trk */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+			hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+		} 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];
+			hba[ctlr]->drv[logvol].raid_level = 
+				inq_buff->data_byte[8];
+		}
+	} 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;
+	}
+	if (hba[ctlr]->drv[logvol].raid_level > 5)
+		hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders, 
+		raid_label[hba[ctlr]->drv[logvol].raid_level]);
+
+	/* special case for c?d0, which may be opened even when
+	   it does not "exist".  In that case, don't mess with usage count.
+	   Also, /dev/c1d1 could be used to re-add c0d0 so we can't just 
+	   check whether logvol == 0, must check logvol != opened_vol */
+	if (logvol != opened_vol)
+		hba[ctlr]->drv[logvol].usage_count = 0;
+
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = total_size;
+	hba[ctlr]->sizes[start] = total_size;
+
+	for(i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 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] = block_size;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks);
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	h->busy_configuring = 0;
+	return logvol;
+}
+
+static int cciss_rescan_disk(int ctlr, int logvol)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	int start, max_p, i;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	unsigned int block_size;
+	unsigned int total_size;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	if (hba[ctlr]->sizes[logvol << NWD_SHIFT] != 0) {
+		/* disk is possible on line, return just a warning */
+		return 1;
+	}
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(size_buff);
+		return -1;
+	}
+	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 = block_size = 0;
+	}
+	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].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* Sectors/track */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+		} else {
+			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].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors / 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);
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = hba[ctlr]->sizes[start]= total_size;
+
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 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]->hardsizes[minor] = block_size;
+	}
+
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks );
+
+	kfree(size_buff);
+	kfree(inq_buff);
+	return 0;
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -844,20 +1680,21 @@
  */
 static unsigned long pollcomplete(int ctlr)
 {
-        unsigned long done;
-        int i;
+	unsigned long done;
+	int i;
 
-        /* Wait (up to 2 seconds) for a command to complete */
+	/* Wait (up to 20 seconds) for a command to complete */
 
-        for (i = 200000; i > 0; i--) {
-                done = hba[ctlr]->access.command_completed(hba[ctlr]);
-                if (done == FIFO_EMPTY) {
-                        udelay(10);     /* a short fixed delay */
-                } else
-                        return (done);
-        }
-        /* Invalid address to tell caller we ran out of time */
-        return 1;
+        for (i = 20 * HZ; i > 0; i--) {
+		done = hba[ctlr]->access.command_completed(hba[ctlr]);
+		if (done == FIFO_EMPTY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} else
+			return done;
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
 }
 /*
  * Send a command to the controller, and wait for it to complete.  
@@ -880,28 +1717,26 @@
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
+	int status = IO_OK;
 
 	c = cmd_alloc(info_p, 1);
-	if (c == NULL)
-	{
+	if (c == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
-		return(IO_ERROR);
+		return IO_ERROR;
 	}
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
+	/* 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  
-	{
+	} 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)
-	{
+	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
@@ -912,29 +1747,27 @@
 				otherwise, if use_unit_num == 2,
 				mode = 0(periph dev addr) target = scsi3addr
 			*/
-			if(use_unit_num == 1)
-			{
+			if (use_unit_num == 1) {
 				c->Header.LUN.LogDev.VolId=
                                 	hba[ctlr]->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
 			}
-			else if (use_unit_num == 2)
-			{
+			else if (use_unit_num == 2) {
 				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
-				c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+				c->Header.LUN.LogDev.Mode = 0; 
+							/* phys dev addr */
 			}
 
 			/* are we trying to read a vital product page */
-			if(page_code != 0)
-			{
+			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.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.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;
@@ -945,12 +1778,12 @@
                                 So we have nothing to write.
                         */
                         c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        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.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] = cmd;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        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;
@@ -961,38 +1794,38 @@
 				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.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.Type.Direction = XFER_READ; /* Read */
+                        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.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.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",
+				"cciss:  Unknown Command 0x%x sent attempted\n",
 				  cmd);
 			cmd_free(info_p, c, 1);
-			return(IO_ERROR);
+			return IO_ERROR;
 	};
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
+	/* Fill in the scatter gather information */
+	if (size > 0) {
 		buff_dma_handle.val = (__u64) pci_map_single( info_p->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
+		c->SG[0].Ext = 0;  /* we are not chaining */
 	}
+resend_cmd1:
 	/*
          * Disable interrupt
          */
@@ -1003,11 +1836,9 @@
 	
 	/* Make sure there is room in the command FIFO */
         /* Actually it should be completely empty at this time. */
-        for (i = 200000; i > 0; i--) 
-	{
+        for (i = 200000; i > 0; i--) {
 		/* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-		{
+                if (!(info_p->access.fifo_full(info_p))) {
 			
                         break;
                 }
@@ -1025,13 +1856,9 @@
 	printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	/* unlock the data buffer from DMA */
-	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
 	if (complete != 1) {
 		if ( (complete & CISS_ERROR_BIT)
-		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-		     {
+		     && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
 			/* if data overrun or underun on Report command 
 				ignore it 
 			*/
@@ -1042,41 +1869,64 @@
 					CMD_DATA_OVERRUN) || 
 				 (c->err_info->CommandStatus == 
 					CMD_DATA_UNDERRUN)
-			 	))
-			{
+			 	)) {
 				complete = c->busaddr;
-			} else
-			{
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+			} else {
+				if (c->err_info->CommandStatus == 
+						CMD_UNSOLICITED_ABORT) {
+					printk(KERN_WARNING "cciss: "
+						"cmd %p aborted do "
+					"to an unsolicited abort \n", c); 
+					if (c->retry_count < MAX_CMD_RETRIES) {
+						printk(KERN_WARNING
+						   "retrying cmd\n");
+						c->retry_count++;
+						/* erase the old error */
+						/* information */
+						memset(c->err_info, 0, 
+						   sizeof(ErrorInfo_struct));
+						goto resend_cmd1;
+					} else {
+						printk(KERN_WARNING
+						   "retried to many times\n");
+						status = IO_ERROR;
+						goto cleanup1;
+					}
+				}
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" Error %x \n", ctlr, 
 					c->err_info->CommandStatus); 
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" offensive info\n"
 				"  size %x\n   num %x   value %x\n", ctlr,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-				cmd_free(info_p,c, 1);
-				return(IO_ERROR);
+				status = IO_ERROR;
+				goto cleanup1;
 			}
 		}
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+                        status = IO_ERROR;
+			goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+                status = IO_ERROR;
         }
+		
+cleanup1:	
+	/* unlock the data buffer from DMA */
+	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+                                size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(info_p, c, 1);
-        return (IO_OK);
+        return status;
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1127,11 +1977,9 @@
 {
 	CommandList_struct *c;
 	
-	while(( c = h->reqQ) != NULL )
-	{
+	while(( c = h->reqQ) != NULL ) {
 		/* can't do anything if fifo is full */
-		if ((h->access.fifo_full(h)))
-		{
+		if ((h->access.fifo_full(h))) {
 			printk(KERN_WARNING "cciss: fifo full \n");
 			return;
 		}
@@ -1151,8 +1999,7 @@
 {
 	struct buffer_head *xbh;
 	
-	while(bh)
-	{
+	while(bh) {
 		xbh = bh->b_reqnext; 
 		bh->b_reqnext = NULL; 
 		blk_finished_io(bh->b_size >> 9);
@@ -1160,39 +2007,44 @@
 		bh = xbh;
 	}
 } 
+/* This code assumes io_request_lock is already held */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */ 
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+	/* erase the old error information */
+	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+	/* add it to software queue and then send it to the controller */
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth; 
+
+	start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, 
+		int timeout)
 {
 	int status = 1;
+	int retry_cmd = 0;
 	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
-	/* unmap the DMA mapping for all the scatter gather elements */
-	if (cmd->Request.Type.Direction == XFER_READ)
-		ddir = PCI_DMA_FROMDEVICE;
-	else
-		ddir = PCI_DMA_TODEVICE;
-	for(i=0; i<cmd->Header.SGList; i++)
-	{
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, ddir);
-	}
 
-	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(cmd->err_info->CommandStatus)
-		{
+	if (cmd->err_info->CommandStatus != 0) { 
+		/* an error has occurred */ 
+		switch (cmd->err_info->CommandStatus) {
 			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
 				status = 0;
 			
-				if( cmd->err_info->ScsiStatus == 0x02) {
+				if (cmd->err_info->ScsiStatus == 0x02) {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has CHECK CONDITION,"
 						" sense key = 0x%x\n", cmd,
@@ -1200,10 +2052,9 @@
 					/* 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;
+					/* recovered error */
+					if ( sense_key == 0x1)
+						status = 1;
 				} else {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has SCSI Status 0x%x\n",
@@ -1251,8 +2102,18 @@
 				status=0;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", cmd);
+				printk(KERN_WARNING "cciss: cmd %p aborted do "
+					"to an unsolicited abort \n",
+				       	cmd);
+				if (cmd->retry_count < MAX_CMD_RETRIES) {
+					retry_cmd=1;
+					printk(KERN_WARNING
+						"retrying cmd\n");
+					cmd->retry_count++;
+				} else {
+					printk(KERN_WARNING
+					"retried to many times\n");
+				}
 				status=0;
 			break;
 			case CMD_TIMEOUT:
@@ -1267,12 +2128,29 @@
 				status=0;
 		}
 	}
+	/* We need to return this command */
+	if (retry_cmd) {
+		resend_cciss_cmd(h,cmd);
+		return;
+	}	
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
+	}
 	complete_buffers(cmd->rq->bh, status);
-
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", cmd->rq);
 #endif /* CCISS_DEBUG */ 
 	end_that_request_last(cmd->rq);
+	cmd_free(h,cmd,1);
 }
 
 
@@ -1289,7 +2167,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-	if (blk_seg_merge_ok(rq->bhtail, bh))
+	if (blk_seg_merge_ok(rq->bhtail, bh))	
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1347,8 +2225,7 @@
 	if (creq->nr_segments > MAXSGENTRIES)
                 BUG();
 
-        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-        {
+        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
                 printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
                                 h->ctlr, creq->rq_dev, creq);
                 blkdev_dequeue_request(creq);
@@ -1370,34 +2247,33 @@
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	c->Header.Tag.lower = c->busaddr;  /* use the physical address */
+					/* the cmd block for tag */
 	c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
 	c->Header.LUN.LogDev.Mode = 1;
-	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+	c->Request.CDBLen = 10; /* 12 byte commands not in FW yet. */
+	c->Request.Type.Type =  TYPE_CMD; /* It is a command.  */
 	c->Request.Type.Attribute = ATTR_SIMPLE; 
 	c->Request.Type.Direction = 
 		(creq->cmd == READ) ? XFER_READ: XFER_WRITE; 
-	c->Request.Timeout = 0; // Don't time out	
+	c->Request.Timeout = 0; /* Don't time out */
 	c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE;
 	start_blk = hba[h->ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;
 #ifdef CCISS_DEBUG
 	if (bh == NULL)
 		panic("cciss: bh== NULL?");
-	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
+	printk(KERN_DEBUG "cciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
 	seg = 0;
 	lastdataend = ~0ULL;
-	while(bh)
-	{
+	while(bh) {
 		if (bh_phys(bh) == lastdataend)
-		{  // tack it on to the last segment 
+		{  /* tack it on to the last segment */
 			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
-		} else
-		{
+		} else {
 			if (seg == MAXSGENTRIES)
 				BUG();
 			tmp_sg[seg].page = bh->b_page;
@@ -1420,10 +2296,10 @@
 			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+                c->SG[i].Ext = 0;  /* we are not chaining */
 	}
 	/* track how many SG entries we are using */ 
-	if( seg > h->maxSG)
+	if (seg > h->maxSG)
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
@@ -1432,11 +2308,11 @@
 
 	c->Header.SGList = c->Header.SGTotal = seg;
 	c->Request.CDB[1]= 0;
-	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	/* MSB */
 	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
 	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
 	c->Request.CDB[5]= start_blk & 0xff;
-	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
+	c->Request.CDB[6]= 0; /* (sect >> 24) & 0xff; MSB */
 	c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
 	c->Request.CDB[8]= creq->nr_sectors & 0xff; 
 	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -1445,7 +2321,7 @@
 
 	addQ(&(h->reqQ),c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
+	if (h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
 	goto next;
@@ -1463,7 +2339,7 @@
 
 
 	/* Is this interrupt for us? */
-	if ( h->access.intr_pending(h) == 0)
+	if (h->access.intr_pending(h) == 0)
 		return;
 
 	/*
@@ -1471,14 +2347,11 @@
 	 * we had better do something about it.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
-	while( h->access.intr_pending(h))
-	{
-		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
-		{
+	while( h->access.intr_pending(h)) {
+		while((a = h->access.command_completed(h)) != FIFO_EMPTY) {
 			a1 = a;
 			a &= ~3;
-			if ((c = h->cmpQ) == NULL)
-			{  
+			if ((c = h->cmpQ) == NULL) {  
 				printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
 				continue;	
 			} 
@@ -1494,8 +2367,7 @@
 			 if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
-					complete_command(c, 0);
-					cmd_free(h, c, 1);
+					complete_command(h, c, 0);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					complete(c->waiting);
 				}
@@ -1557,7 +2429,7 @@
 static void release_io_mem(ctlr_info_t *c)
 {
 	/* if IO mem was not protected do nothing */
-	if( c->io_mem_addr == 0)
+	if (c->io_mem_addr == 0)
 		return;
 	release_region(c->io_mem_addr, c->io_mem_length);
 	c->io_mem_addr = 0;
@@ -1582,15 +2454,13 @@
 	for(i=0; i<6; i++)
 		addr[i] = pdev->resource[i].start;
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-		return( -1);
+		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) {
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
-		return(-1);
+		return -1;
 	}
 	
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
@@ -1606,7 +2476,7 @@
 	/* check to see if controller has been disabled */
 	if (!(command & 0x02)) {
 		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-		return(-1);
+		return -1;
 	}
 	/* search for our IO range so we can protect it */
 	for (i=0; i<6; i++) {
@@ -1700,8 +2570,7 @@
 	if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
 	      (readb(&c->cfgtable->Signature[1]) != 'I') ||
 	      (readb(&c->cfgtable->Signature[2]) != 'S') ||
-	      (readb(&c->cfgtable->Signature[3]) != 'S') )
-	{
+	      (readb(&c->cfgtable->Signature[3]) != 'S') ) {
 		printk("Does not appear to be a valid CISS config table\n");
 		return -1;
 	}
@@ -1714,8 +2583,7 @@
 		&(c->cfgtable->HostWrite.TransportRequest));
 	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-	for(i=0;i<MAX_CONFIG_WAIT;i++)
-	{
+	for(i=0;i<MAX_CONFIG_WAIT;i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
@@ -1729,8 +2597,7 @@
 	print_cfg_table(c->cfgtable);	
 #endif /* CCISS_DEBUG */ 
 
-	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-	{
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
 		printk(KERN_WARNING "cciss: unable to get board into"
 					" simple mode\n");
 		return -1;
@@ -1755,22 +2622,19 @@
 	int total_size; 
 
 	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-	if (ld_buff == NULL)
-	{
+	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
 	memset(ld_buff, 0, sizeof(ReportLunData_struct));
 	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
+        if (size_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
 		kfree(ld_buff);
                 return;
         }
 	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
+        if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
 		kfree(size_buff);
@@ -1779,14 +2643,12 @@
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
 		sizeof(InquiryData_struct), 0, 0 ,0, NULL);
-	if (return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
 		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
 		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
 		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-	} else /* send command failed */
-	{
+	} else  {	/* send command failed */
 		printk(KERN_WARNING "cciss: unable to determine firmware"
 			" version of controller\n");
 	}
@@ -1794,8 +2656,7 @@
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
 			sizeof(ReportLunData_struct), 0, 0, 0, NULL);
 
-	if( return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
 		printk("LUN Data\n--------------------------\n");
 #endif /* CCISS_DEBUG */ 
@@ -1804,16 +2665,14 @@
 		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 */
-	{
+	} else { /* reading number of logical volumes failed */
 		printk(KERN_WARNING "cciss: report logical volume"
 			" command failed\n");
 		listlength = 0;
 	}
-	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-	{
-		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
+	hba[cntl_num]->num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+		printk(KERN_ERR "cciss:  only %d number of logical volumes supported\n",
 			CISS_MAX_LUN);
 		hba[cntl_num]->num_luns = CISS_MAX_LUN;
 	}
@@ -1822,8 +2681,9 @@
 		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;
@@ -1839,8 +2699,7 @@
 	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
 				sizeof( ReadCapdata_struct), 1, i, 0, NULL);
-	  	if (return_code == IO_OK)
-		{
+	  	if (return_code == IO_OK) {
 			total_size = (0xff & 
 				(unsigned int)(size_buff->total_size[0])) << 24;
 			total_size |= (0xff & 
@@ -1849,7 +2708,8 @@
 				(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
+			total_size++; 	/* command returns highest */
+					/* block address */
 
 			block_size = (0xff & 
 				(unsigned int)(size_buff->block_size[0])) << 24;
@@ -1859,8 +2719,7 @@
 				(unsigned int)(size_buff->block_size[2])) << 8;
                 	block_size |= (0xff & 
 				(unsigned int)(size_buff->block_size[3]));
-		} else /* read capacity command failed */ 
-		{
+		} else {	/* read capacity command failed */ 
 			printk(KERN_WARNING "cciss: read capacity failed\n");
 			total_size = block_size = 0; 
 		}	
@@ -1871,18 +2730,18 @@
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
 			sizeof(InquiryData_struct), 1, i, 0xC1, NULL );
-	  	if (return_code == IO_OK)
-		{
-			if(inq_buff->data_byte[8] == 0xFF)
-			{
+	  	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[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
                            hba[cntl_num]->drv[i].heads = 255;
-                           hba[cntl_num]->drv[i].sectors = 32; // Sectors per track
-                           hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;                	} else
-			{
+                           hba[cntl_num]->drv[i].sectors = 32; /* Sectors */
+			   					/* per track */
+                           hba[cntl_num]->drv[i].cylinders = total_size 
+				   				/ 255 / 32;
+			} else {
 
 		 	   hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
@@ -1894,23 +2753,27 @@
 					(inq_buff->data_byte[4] & 0xff) << 8;
 			   hba[cntl_num]->drv[i].cylinders += 
                                         inq_buff->data_byte[5];
+                           hba[cntl_num]->drv[i].raid_level = 
+					inq_buff->data_byte[8]; 
 			}
 		}
-		else /* Get geometry failed */
-		{
+		else {	/* Get geometry failed */
 			printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); 
 
 			hba[cntl_num]->drv[i].block_size = block_size;
 			hba[cntl_num]->drv[i].nr_blocks = total_size;
 			hba[cntl_num]->drv[i].heads = 255;
-			hba[cntl_num]->drv[i].sectors = 32; // Sectors per track 
+			hba[cntl_num]->drv[i].sectors = 32; 	/* Sectors */
+								/* per track */
 			hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;
 		}
-		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+		if (hba[cntl_num]->drv[i].raid_level > 5)
+			hba[cntl_num]->drv[i].raid_level = RAID_UNKNOWN;
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
 			hba[cntl_num]->drv[i].heads, 
 			hba[cntl_num]->drv[i].sectors,
-			hba[cntl_num]->drv[i].cylinders);
-
+			hba[cntl_num]->drv[i].cylinders,
+			raid_label[hba[cntl_num]->drv[i].raid_level]); 
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
@@ -1922,22 +2785,19 @@
 static int alloc_cciss_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if (hba[i]==NULL) {
 				printk(KERN_ERR "cciss: out of memory.\n");
-				return (-1);
+				return -1;
 			}
-			return (i);
+			return i;
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
 		" of 8 controllers.\n");
-	return(-1);
+	return -1;
 }
 
 static void free_hba(int i)
@@ -1963,13 +2823,12 @@
 		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
 			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if( i < 0 ) 
-		return (-1);
+	if (i < 0 ) 
+		return -1;
 	memset(hba[i], 0, sizeof(ctlr_info_t));
-	if (cciss_pci_init(hba[i], pdev) != 0)
-	{
+	if (cciss_pci_init(hba[i], pdev) != 0) {
 		free_hba(i);
-		return (-1);
+		return -1;
 	}
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
@@ -1986,26 +2845,25 @@
 		return -ENODEV;
 	}
 		
-	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) {
 		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);
+		return -1;
 	}
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-	if( request_irq(hba[i]->intr, do_cciss_intr, 
+	if (request_irq(hba[i]->intr, do_cciss_intr, 
 		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-			hba[i]->devname, hba[i]))
-	{
-		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+			hba[i]->devname, hba[i])) {
+
+		printk(KERN_ERR "cciss: 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);
+		return -1;
 	}
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
         	((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
@@ -2015,17 +2873,17 @@
 	hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
 		hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
 		&(hba[i]->errinfo_pool_dhandle));
-	if((hba[i]->cmd_pool_bits == NULL) 
+	if ((hba[i]->cmd_pool_bits == NULL) 
 		|| (hba[i]->cmd_pool == NULL)
-		|| (hba[i]->errinfo_pool == NULL))
-        {
-		if(hba[i]->cmd_pool_bits)
+		|| (hba[i]->errinfo_pool == NULL)) {
+
+		if (hba[i]->cmd_pool_bits)
                 	kfree(hba[i]->cmd_pool_bits);
-                if(hba[i]->cmd_pool)
+                if (hba[i]->cmd_pool)
                 	pci_free_consistent(hba[i]->pdev,  
 				NR_CMDS * sizeof(CommandList_struct), 
 				hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);	
-		if(hba[i]->errinfo_pool)
+		if (hba[i]->errinfo_pool)
 			pci_free_consistent(hba[i]->pdev,
 				NR_CMDS * sizeof( ErrorInfo_struct),
 				hba[i]->errinfo_pool, 
@@ -2035,7 +2893,7 @@
 		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
-		return(-1);
+		return -1;
 	}
 
 	/* Initialize the pdev driver private data. 
@@ -2082,7 +2940,8 @@
 	hba[i]->gendisk.max_p = MAX_PART;
 	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;
+	hba[i]->gendisk.fops = &cciss_fops;
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -2096,7 +2955,7 @@
 
 	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
 
-	return(1);
+	return 1;
 }
 
 static void __devexit cciss_remove_one (struct pci_dev *pdev)
@@ -2106,15 +2965,13 @@
 	char flush_buf[4];
 	int return_code; 
 
-	if (pci_get_drvdata(pdev) == NULL)
-	{
+	if (pci_get_drvdata(pdev) == NULL) {
 		printk( KERN_ERR "cciss: Unable to remove device \n");
 		return;
 	}
 	tmp_ptr = pci_get_drvdata(pdev);
 	i = tmp_ptr->ctlr;
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cciss: device appears to "
 			"already be removed \n");
 		return;
@@ -2175,7 +3032,7 @@
 static int __init init_cciss_module(void)
 {
 
-	return ( cciss_init());
+	return cciss_init();
 }
 
 static void __exit cleanup_cciss_module(void)
@@ -2184,10 +3041,8 @@
 
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
-	for (i=0; i< MAX_CTLR; i++) 
-	{
-		if (hba[i] != NULL)
-		{
+	for (i=0; i< MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
 			printk(KERN_WARNING "cciss: had to remove"
 					" controller %d\n", i);
 			cciss_remove_one(hba[i]->pdev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.h linux-2.4.21-rc3/drivers/block/cciss.h
--- linux-2.4.20/drivers/block/cciss.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cciss.h	2003-05-22 22:06:24.000000000 +0000
@@ -27,13 +27,14 @@
 };
 typedef struct _drive_info_struct
 {
- 	__u32   LunID;	
-	int 	usage_count;
-	int 	nr_blocks;
-	int	block_size;
-	int 	heads;
-	int	sectors;
-	int 	cylinders;
+ 	__u32   	LunID;	
+	int 		usage_count;
+	unsigned int 	nr_blocks;
+	int		block_size;
+	int 		heads;
+	int		sectors;
+	int 		cylinders;
+	int 		raid_level;
 } drive_info_struct;
 
 struct ctlr_info 
@@ -55,6 +56,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
@@ -85,6 +87,7 @@
 	int              sizes[256];
 	int              blocksizes[256];
 	int              hardsizes[256];
+	int busy_configuring;
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_cmd.h linux-2.4.21-rc3/drivers/block/cciss_cmd.h
--- linux-2.4.20/drivers/block/cciss_cmd.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cciss_cmd.h	2003-05-22 22:06:28.000000000 +0000
@@ -1,16 +1,17 @@
 #ifndef CCISS_CMD_H
 #define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+/* ########################################################################## */
+/* DEFINES                                                                    */
+/* ########################################################################## */
 #define CISS_VERSION "1.00"
 
-//general boundary defintions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+/* general boundary defintions */
+#define SENSEINFOBYTES          32	/* note that this value may vary */
+					/* between host implementations  */
 #define MAXSGENTRIES            31
 #define MAXREPLYQS              256
 
-//Command Status value
+/* Command Status value */
 #define CMD_SUCCESS             0x0000
 #define CMD_TARGET_STATUS       0x0001
 #define CMD_DATA_UNDERRUN       0x0002
@@ -25,30 +26,30 @@
 #define CMD_TIMEOUT             0x000B
 #define CMD_UNABORTABLE		0x000C
 
-//transfer direction
+/* transfer direction */
 #define XFER_NONE               0x00
 #define XFER_WRITE              0x01
 #define XFER_READ               0x02
 #define XFER_RSVD               0x03
 
-//task attribute
+/* task attribute */
 #define ATTR_UNTAGGED           0x00
 #define ATTR_SIMPLE             0x04
 #define ATTR_HEADOFQUEUE        0x05
 #define ATTR_ORDERED            0x06
 #define ATTR_ACA                0x07
 
-//cdb type
+/* cdb type */
 #define TYPE_CMD				0x00
 #define TYPE_MSG				0x01
 
-//config space register offsets
+/* config space register offsets */
 #define CFG_VENDORID            0x00
 #define CFG_DEVICEID            0x02
 #define CFG_I2OBAR              0x10
 #define CFG_MEM1BAR             0x14
 
-//i2o space register offsets
+/* i2o space register offsets */
 #define I2O_IBDB_SET            0x20
 #define I2O_IBDB_CLEAR          0x70
 #define I2O_INT_STATUS          0x30
@@ -56,7 +57,7 @@
 #define I2O_IBPOST_Q            0x40
 #define I2O_OBPOST_Q            0x44
 
-//Configuration Table
+/* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 
@@ -78,24 +79,24 @@
    __u64	val;
 } u64bit;
 
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
-#define QWORD vals32 
-
-//###########################################################################
-//STRUCTURES
-//###########################################################################
+/*  Type defs used in the following structs */
+typedef	__u8 BYTE;
+typedef	__u16 WORD;
+typedef __u16 HWORD;
+typedef	__u32 DWORD; 
+typedef vals32 QWORD; 
+
+/* ######################################################################### */
+/* STRUCTURES                                                                */
+/* ######################################################################### */
 #define CISS_MAX_LUN	16	
 #define CISS_MAX_PHYS_LUN	1024
-// SCSI-3 Cmmands 
+/* SCSI-3 Cmmands  */
 
 #pragma pack(1)	
 
 #define CISS_INQUIRY 0x12
-//Date returned
+/* Data returned */
 typedef struct _InquiryData_struct
 {
   BYTE data_byte[36];
@@ -103,7 +104,7 @@
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
 #define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
-// Data returned
+/*  Data returned */
 typedef struct _ReportLUNdata_struct
 {
   BYTE LUNListLength[4];
@@ -114,39 +115,39 @@
 #define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
 typedef struct _ReadCapdata_struct
 {
-  BYTE total_size[4];	// Total size in blocks
-  BYTE block_size[4];	// Size of blocks in bytes
+  BYTE total_size[4];	/* Total size in blocks */
+  BYTE block_size[4];	/* Size of blocks in bytes */
 } ReadCapdata_struct;
 
-// 12 byte commands not implemented in firmware yet. 
-// #define CCISS_READ 	0xa8	// Read(12)
-// #define CCISS_WRITE	0xaa	// Write(12)
- #define CCISS_READ   0x28    // Read(10)
- #define CCISS_WRITE  0x2a    // Write(10)
+/* 12 byte commands not implemented in firmware yet.  */
+/* #define CCISS_READ 	0xa8	Read(12)	*/
+/* #define CCISS_WRITE	0xaa	Write(12) 	*/
+ #define CCISS_READ   0x28    /* Read(10) */
+ #define CCISS_WRITE  0x2a    /* Write(10) */
 
-// BMIC commands 
+/* 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
+#define CCISS_CACHE_FLUSH 0x01	/* 0xC2 was already being used by CCISS */
 
-//Command List Structure
+/* Command List Structure */
 typedef union _SCSI3Addr_struct {
    struct {
     BYTE Dev;
     BYTE Bus:6;
-    BYTE Mode:2;        // b00
+    BYTE Mode:2;        /* b00 */
   } PeripDev;
    struct {
     BYTE DevLSB;
     BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
+    BYTE Mode:2;        /* b01 */
   } LogDev;
    struct {
     BYTE Dev:5;
     BYTE Bus:3;
     BYTE Targ:6;
-    BYTE Mode:2;        // b10
+    BYTE Mode:2;        /* b10 */
   } LogUnit;
 } SCSI3Addr_struct;
 
@@ -154,7 +155,7 @@
   DWORD             TargetId:24;
   DWORD             Bus:6;
   DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
+  SCSI3Addr_struct  Target[2]; /* 2 level target device addr */
 } PhysDevAddr_struct;
   
 typedef struct _LogDevAddr_struct {
@@ -205,8 +206,8 @@
   }Common_Info;
   struct{
     BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
+    BYTE  offense_size;	/* size of offending entry 	*/
+    BYTE  offense_num; 	/* byte # of offense 0-base 	*/
     DWORD offense_value;
   }Invalid_Cmd;
 }MoreErrInfo_struct;
@@ -240,12 +241,13 @@
   struct _CommandList_struct *next;
   struct request *	   rq;
   struct completion *waiting;
+  int	 retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif
 } CommandList_struct;
 
-//Configuration Table Structure
+/* Configuration Table Structure */
 typedef struct _HostWrite_struct {
   DWORD TransportRequest;
   DWORD Reserved;
@@ -266,4 +268,4 @@
   DWORD            HeartBeat;
 } CfgTable_struct;
 #pragma pack()	 
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.c linux-2.4.21-rc3/drivers/block/cciss_scsi.c
--- linux-2.4.20/drivers/block/cciss_scsi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cciss_scsi.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,7 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
- *
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
+ *    
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net 
  *
  *    Author: Stephen M. Cameron
  */
@@ -233,8 +233,8 @@
 		printk( "cciss: %d scsi commands are still outstanding.\n",
 			CMD_STACK_SIZE - stk->top);
 		// BUG();
-		printk("WE HAVE A BUG HERE!!! stk=%p\n",
-			stk);
+		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+			(unsigned int) stk);
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -896,7 +896,7 @@
 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	memcpy(cp->Request.CDB, cdb, cdblen);
-	cp->Request.Timeout = 1000;		// guarantee completion.
+	cp->Request.Timeout = 0;	// No timeout
 	cp->Request.CDBLen = cdblen;
 	cp->Request.Type.Type = TYPE_CMD;
 	cp->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1414,7 +1414,7 @@
 
 	// Fill in the request block...
 
-	cp->Request.Timeout = 1000; // guarantee completion
+	cp->Request.Timeout = 0; // No timeout 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
 	cp->Request.CDBLen = cmd->cmd_len;
@@ -1578,14 +1578,14 @@
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned long flags;
+	unsigned int flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
 	CPQ_TAPE_LOCK(ctlr, flags);
 	size = sprintf(buffer + *len,
-		"       Sequential access devices: %d\n\n",
-			ccissscsi[ctlr].ndevices);
+		"Sequential access devices: %d\n\n",
+		 ccissscsi[ctlr].ndevices);
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 	*pos += size; *len += size;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.h linux-2.4.21-rc3/drivers/block/cciss_scsi.h
--- linux-2.4.20/drivers/block/cciss_scsi.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cciss_scsi.h	2003-05-22 22:06:26.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 #ifdef CONFIG_CISS_SCSI_TAPE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cpqarray.c linux-2.4.21-rc3/drivers/block/cpqarray.c
--- linux-2.4.20/drivers/block/cpqarray.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/cpqarray.c	2003-05-22 22:06:27.000000000 +0000
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
  *
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
@@ -41,13 +41,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.21)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,21)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.21");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
 MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -162,6 +162,7 @@
 static int ida_release(struct inode *inode, struct file *filep);
 static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
 static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+static int ida_ctlr_big_ioctl( int ctlr, int dsk, ida_big_ioctl_t *io);
 
 static void do_ida_request(request_queue_t *q);
 static void start_io(ctlr_info_t *h);
@@ -279,8 +280,7 @@
 
 	for(i=0; i<=h->highest_lun; i++) {
 		drv = &h->drv[i];
-		if(drv->nr_blks != 0)
-		{
+		if(drv->nr_blks != 0) {
 		    	size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
 				ctlr, i, drv->blk_size, drv->nr_blks);
 			pos += size; len += size;
@@ -293,7 +293,8 @@
 
 	c = h->reqQ;
 	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->reqQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -302,7 +303,8 @@
 
 	c = h->cmpQ;
 	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->cmpQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -352,12 +354,12 @@
 	ctlr_info_t *tmp_ptr;
 	char buff[4]; 
 
-		if (pdev->driver_data == NULL)
+	tmp_ptr = pci_get_drvdata(pdev);
+	if (tmp_ptr == NULL)
 	{
 		printk( KERN_ERR "cpqarray: Unable to remove device \n");
 		return;
 	}
-	tmp_ptr = (ctlr_info_t *) pdev->driver_data;
 	i = tmp_ptr->ctlr;
 	if (hba[i] == NULL) 
 	{
@@ -369,13 +371,12 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    */
 	memset(buff, 0 , 4);
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
 	free_irq(hba[i]->intr, hba[i]);
-	pdev->driver_data = NULL;
+	pci_set_drvdata(pdev, NULL);
 	/* remove it from the disk list */
 	del_gendisk(&(hba[i]->gendisk));
 
@@ -399,8 +400,7 @@
 {
 	char buff[4]; 
 
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cpqarray: device appears to "
 			"already be removed \n");
 		return;
@@ -409,8 +409,7 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    
 	 * no data returned, but don't want to send NULL to sendcmd */	
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
@@ -488,15 +487,14 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	/* fill in default block size */
 	for(j=0;j<256;j++)
-                hba[i]->hardsizes[j] = BLOCK_SIZE;
+                hba[i]->hardsizes[j] = hba[i]->drv[j].blk_size;
 
 	sprintf(hba[i]->devname, "ida%d", i);
         hba[i]->ctlr = i;
 	/* Initialize the pdev driver private data */
-	pdev->driver_data = hba[i];
+	pci_set_drvdata(pdev, hba[i]);
 
-	if (cpqarray_pci_init(hba[i], pdev) != 0)
-	{
+	if (cpqarray_pci_init(hba[i], pdev) != 0) {
 		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
@@ -510,8 +508,7 @@
 	
 	/* If this successful it should insure that we are the only */
 	/* instance of the driver */	
-	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) 
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
         	printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
                                 MAJOR_NR+i);
                 release_io_mem(hba[i]);
@@ -522,8 +519,8 @@
 	
 	hba[i]->access.set_intr_mask(hba[i], 0);
 	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) 
-	{
+		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+				hba[i]->devname, hba[i])) {
 
 		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
 				hba[i]->intr, hba[i]->devname);
@@ -538,8 +535,7 @@
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
 				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
 		
-	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
-	{
+	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
 		if(hba[i]->cmd_pool_bits)
 			kfree(hba[i]->cmd_pool_bits);
 		if(hba[i]->cmd_pool)
@@ -583,6 +579,7 @@
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; 
+	hba[i]->gendisk.fops = &ida_fops;
 	
 		/* Get on the disk list */
 	add_gendisk(&(hba[i]->gendisk));
@@ -622,8 +619,7 @@
 	pci_register_driver(&cpqarray_pci_driver);
 	cpqarray_eisa_detect();
 
-	for(i=0; i< MAX_CTLR; i++)
-        {
+	for(i=0; i< MAX_CTLR; i++) {
 		if (hba[i] != NULL)
 			num_cntlrs_reg++;
 	}
@@ -634,13 +630,10 @@
 static int alloc_cpqarray_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if(hba[i]==NULL) {
 				printk(KERN_ERR "cpqarray: out of memory.\n");
 				return (-1);
 			}
@@ -674,8 +667,7 @@
 
 	pci_read_config_word(pdev, PCI_COMMAND, &command);
 	/* check to see if controller has been disabled */
-	if(!(command & 0x02))
-	{
+	if(!(command & 0x02)) {
 		printk(KERN_WARNING "cpqarray: controller appears to be disabled\n");
 		return(-1);
 	}
@@ -688,13 +680,11 @@
 	for(i=0; i<6; i++)
 		addr[i] = pci_resource_start(pdev, i);
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
 		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) {
 		printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
 		return -1;
 	}
@@ -719,18 +709,16 @@
 );
 
 	c->intr = irq;
-	for(i=0; i<6; i++)
-	{
-		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
-		{ /* IO space */  
+	for(i=0; i<6; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { 
+			/* IO space */  
 			c->io_mem_addr = addr[i];
 			c->io_mem_length = pci_resource_end(pdev, i) 
 				- pci_resource_start(pdev, i) +1; 
 			// printk("IO Value found addr[%d] %lx %lx\n",
 			//		i, c->io_mem_addr, c->io_mem_length);
 			if(!request_region( c->io_mem_addr, c->io_mem_length,
-				"cpqarray"))
-			{
+				"cpqarray")) {
 				printk( KERN_WARNING "cpqarray 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;
@@ -740,7 +728,8 @@
 	}	
 	c->paddr = 0;
 	for(i=0; i<6; i++)
-		if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) {
+		if (!(pci_resource_flags(pdev, i) & 
+					PCI_BASE_ADDRESS_SPACE_IO)) {
 			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
@@ -843,8 +832,7 @@
 		hba[ctlr]->io_mem_length = 0x7FF;		
 		if(!request_region( hba[ctlr]->io_mem_addr, 
 					hba[ctlr]->io_mem_length, 
-				"cpqarray"))
-		{
+				"cpqarray")) {
 			printk( KERN_WARNING "cpqarray: I/0 range already in use addr = %lx length=%ld\n",
 			 hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length);
 			free_hba(ctlr);
@@ -854,10 +842,14 @@
 		 * Read the config register to find our interrupt
 		 */
 		intr = inb(eisa[i]+0xCC0) >> 4;
-		if (intr & 1) intr = 11;
-		else if (intr & 2) intr = 10;
-		else if (intr & 4) intr = 14;
-		else if (intr & 8) intr = 15;
+		if (intr & 1) 
+			intr = 11;
+		else if (intr & 2) 
+			intr = 10;
+		else if (intr & 4) 
+			intr = 14;
+		else if (intr & 8) 
+			intr = 15;
 		
 		hba[ctlr]->intr = intr;
 		sprintf(hba[ctlr]->devname, "ida%d", ctlr);
@@ -894,19 +886,18 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
-		return -ENXIO;
-
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
 	 * so array config can still work.  I don't think I really like this,
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
-	if (suser()
-		&& hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0 
-		&& MINOR(inode->i_rdev) != 0)
-		return -ENXIO;
+	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) {
+		if (MINOR(inode->i_rdev) != 0)
+			return -ENXIO;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
 
 	hba[ctlr]->drv[dsk].usage_count++;
 	hba[ctlr]->usage_count++;
@@ -947,7 +938,8 @@
 static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
 {
 	if (c && c->next != c) {
-		if (*Qptr == c) *Qptr = c->next;
+		if (*Qptr == c) 
+			*Qptr = c->next;
 		c->prev->next = c->next;
 		c->next->prev = c->prev;
 	} else {
@@ -985,8 +977,7 @@
 	if (creq->nr_segments > SG_MAX)
 		BUG();
 
-	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-	{
+	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
 		printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
 				h->ctlr, creq->rq_dev, creq);
 		blkdev_dequeue_request(creq);
@@ -1036,8 +1027,7 @@
 		bh = bh->b_reqnext;
 	}
 	/* Now do all the DMA Mappings */
-	for( i=0; i < seg; i++)
-	{
+	for( i=0; i < seg; i++) {
 		c->req.sg[i].size = tmp_sg[i].length;
 		c->req.sg[i].addr = (__u32) pci_map_page(
                 		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
@@ -1131,7 +1121,8 @@
 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
 		ok = 0;	
 	}
-	if (timeout) ok = 0;
+	if (timeout) 
+		ok = 0;
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
@@ -1192,15 +1183,14 @@
                                  *  But rcode = 0.
                                  */
 
-				if((a1 & 0x03) && (c->req.hdr.rcode == 0))
-                                {
+				if((a1 & 0x03) && (c->req.hdr.rcode == 0)) {
                                 	c->req.hdr.rcode = RCODE_INVREQ;
                                 }
 				if (c->type == CMD_RWREQ) {
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
 				} else if (c->type == CMD_IOCTL_PEND) {
-					c->type = CMD_IOCTL_DONE;
+					complete(c->waiting);
 				}
 				continue;
 			}
@@ -1238,8 +1228,6 @@
 	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
 	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
 	int error;
-	ida_ioctl_t *io = (ida_ioctl_t*)arg;
-	ida_ioctl_t my_io;
 
 	switch(cmd) {
 	case HDIO_GETGEO:
@@ -1286,26 +1274,50 @@
 	}
 
 	case IDAGETDRVINFO:
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
-	case BLKGETSIZE:
-		if (!arg) return -EINVAL;
-		return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, 
-			(unsigned long *)arg);
-	case BLKGETSIZE64:
-		return put_user((u64)(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects) << 9, (u64*)arg);
+	}
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
-		if (!suser()) return -EPERM;
-		error = copy_from_user(&my_io, io, sizeof(my_io));
-		if (error) return error;
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
+		ida_ioctl_t my_io;
+
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
-		if (error) return error;
-		if(copy_to_user(io, &my_io, sizeof(my_io)))
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
 			return -EFAULT;
-		return error;
+		return 0;
+	}
+	case IDABIGPASSTHRU:
+	{
+
+		ida_big_ioctl_t *io = (ida_big_ioctl_t*)arg;
+		ida_big_ioctl_t my_io;
+		
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
+		error = ida_ctlr_big_ioctl(ctlr, dsk, &my_io);
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
+		return 0;
+	}
 	case IDAGETCTLRSIG:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
 		return 0;
 	case IDAREVALIDATEVOLS:
@@ -1319,7 +1331,8 @@
 		
 		ida_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
@@ -1347,8 +1360,7 @@
 
 		/* count partitions 1 to 15 with sizes > 0 */
 		start = (dsk << NWD_SHIFT); 	
-		for(i=1; i <IDA_MAX_PART; i++)
-		{
+		for(i=1; i <IDA_MAX_PART; i++) {
 			int minor = start+i;
 			if(hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
@@ -1360,6 +1372,8 @@
 		return(0);
 	}
 
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
@@ -1394,6 +1408,7 @@
 	void *p = NULL;
 	unsigned long flags;
 	int error;
+	DECLARE_COMPLETION(wait);
 
 	if ((c = cmd_alloc(h, 0)) == NULL)
 		return -ENOMEM;
@@ -1411,8 +1426,7 @@
 	switch(io->cmd) {
 	case PASSTHRU_A:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
 			error = -ENOMEM; 
 			cmd_free(h, c, 0); 
 			return(error);
@@ -1431,11 +1445,11 @@
 		c->req.hdr.sg_cnt = 1;
 		break;
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case READ_FLASH_ROM:
 	case SENSE_CONTROLLER_PERFORMANCE:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1452,8 +1466,7 @@
 	case COLLECT_BUFFER:
 	case WRITE_FLASH_ROM:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
- 		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1474,7 +1487,9 @@
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 		c->req.hdr.sg_cnt = 1;
 	}
-	
+
+	c->waiting = &wait;
+
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&h->reqQ, c);
@@ -1483,8 +1498,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	/* Unmap the DMA  */
 	pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size, 
@@ -1496,6 +1510,7 @@
                                 sizeof(ida_ioctl_t),
                                 PCI_DMA_BIDIRECTIONAL);
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
@@ -1520,6 +1535,175 @@
 }
 
 /*
+ * ida_ctlr_big_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  
+ */
+static int ida_ctlr_big_ioctl(int ctlr, int dsk, ida_big_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	__u8   *scsi_param = NULL;
+	__u8	*buff[SG_MAX] = {NULL,};
+	size_t	buff_size[SG_MAX];
+	__u8	sg_used = 0;
+	unsigned long flags;
+	int error = 0;
+	int i;
+	DECLARE_COMPLETION(wait);
+
+	/* Check kmalloc limits  using all SGs */
+	if( io->buff_malloc_size > IDA_MAX_KMALLOC_SIZE)
+		return -EINVAL;
+	if( io->buff_size > io->buff_malloc_size * SG_MAX)
+		return -EINVAL;
+	if ((c = cmd_alloc(h, 0)) == NULL)
+		return -ENOMEM;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.cmd = io->cmd;
+	c->req.hdr.blk = io->blk;
+	c->req.hdr.blk_cnt = io->blk_cnt;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	/* for passthru_a the scsi command is in another record */
+	if (io->cmd == PASSTHRU_A) {
+
+		if (io->scsi_param == NULL)
+		{
+			error = -EINVAL;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+		scsi_param = kmalloc(sizeof(scsi_param_t),  GFP_KERNEL);
+		if (scsi_param == NULL) {
+			error = -ENOMEM;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+
+		/* copy the scsi command to get passed thru */ 	
+		if (copy_from_user(scsi_param, io->scsi_param, 
+					sizeof(scsi_param_t))) {	
+			kfree(scsi_param);
+			cmd_free(h, c, 0);
+			return -EFAULT;
+		}
+
+		/* with this command the scsi command is seperate */
+		c->req.hdr.blk = pci_map_single(h->pci_dev, scsi_param,
+				sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* fill in the SG entries */
+	/* create buffers if we need to */ 
+	if(io->buff_size > 0) {
+		size_t size_left_alloc = io->buff_size;
+		__u8 *data_ptr = io->buff;
+
+		while(size_left_alloc > 0) {
+			buff_size[sg_used] = (size_left_alloc 
+					> io->buff_malloc_size)
+				? io->buff_malloc_size : size_left_alloc;
+			buff[sg_used] = kmalloc( buff_size[sg_used], 
+					GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				error = -ENOMEM;
+				goto ida_alloc_cleanup;
+			}
+			if(io->xfer_type & IDA_XFER_WRITE) {
+				/* Copy the data into the buffer created */
+				if (copy_from_user(buff[sg_used], data_ptr,
+						buff_size[sg_used])) {
+					error = -EFAULT;
+					goto ida_alloc_cleanup;
+				}
+			}
+			/* put the data into the scatter gather list */
+			c->req.sg[sg_used].size = buff_size[sg_used];
+			c->req.sg[sg_used].addr = pci_map_single(h->pci_dev, 
+					buff[sg_used], buff_size[sg_used],
+					 PCI_DMA_BIDIRECTIONAL);
+			
+			size_left_alloc -= buff_size[sg_used];
+			data_ptr += buff_size[sg_used];
+			sg_used++;
+		}
+	}
+	c->req.hdr.sg_cnt = sg_used;
+
+	c->waiting = &wait;
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* Wait for completion */
+	wait_for_completion(&wait);
+	/* Unmap the DMA  */
+	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+		pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				c->req.sg[i].size, PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* if we are reading data from the hardware copy it back to user */
+	if (io->xfer_type & IDA_XFER_READ) {
+		__u8	*data_ptr = io->buff;
+		int i;
+
+	    	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+			if (copy_to_user(data_ptr, buff[i], buff_size[i])) { 
+				error = -EFAULT;
+				goto ida_alloc_cleanup;
+			}
+			data_ptr += buff_size[i];
+			
+		}
+
+	}
+
+	io->rcode = c->req.hdr.rcode;
+
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		/* copy the scsi_params back to the user */ 
+		if( copy_to_user(io->scsi_param, scsi_param, 
+					sizeof(scsi_param_t))) {
+			error = -EFAULT;	
+		}
+		kfree(scsi_param);
+	}
+	cmd_free(h, c, 0);
+	return(error);
+	
+ida_alloc_cleanup:
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		kfree(scsi_param);
+	}
+	for (i=0; i<sg_used; i++) {
+		if(buff[sg_used] != NULL) {	
+			pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				buff_size[sg_used], PCI_DMA_BIDIRECTIONAL);
+			kfree(buff[sg_used]);
+		}
+	}	
+	cmd_free(h, c, 0);
+	return(error);
+}
+/*
  * Commands are pre-allocated in a large block.  Here we use a simple bitmap
  * scheme to suballocte them to the driver.  Operations that are not time
  * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
@@ -1720,7 +1904,7 @@
 	hba[ctlr]->gendisk.nr_real = 0;
 
 	for(i=0;i<256;i++)
-                hba[ctlr]->hardsizes[i] = BLOCK_SIZE;
+                hba[ctlr]->hardsizes[i] = 0;
 	/*
 	 * Tell the array controller not to give us any interrupts while
 	 * we check the new geometry.  Then turn interrupts back on when
@@ -1752,8 +1936,7 @@
 
 	spin_lock_irqsave(&io_request_lock, flags);
 	/* make sure logical volume is NOT is use */
-	if( h->drv[logvol].usage_count > 1)
-	{
+	if( h->drv[logvol].usage_count > 1) {
 		spin_unlock_irqrestore(&io_request_lock, flags);
                 return -EBUSY;
 	}
@@ -1763,21 +1946,21 @@
 	/* invalidate the devices and deregister the disk */ 
 	max_p = gdev->max_p;
 	start = logvol << gdev->minor_shift;
-	for (i=max_p-1; i>=0; i--)
-	{
+	for (i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		// printk("invalidating( %d %d)\n", ctlr, minor);
 		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
 		/* so open will now fail */
 		hba[ctlr]->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 (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
 		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++)
-		{
+		for(i=0; i<h->highest_lun; i++) {
 			/* if the disk has size > 0, it is available */
 			if (hba[ctlr]->sizes[i << gdev->minor_shift] != 0)
 				newhighest = i;
@@ -1789,7 +1972,8 @@
 	gdev->nr_real = h->highest_lun+1; 
 	/* zero out the disk size info */ 
 	h->drv[logvol].nr_blks = 0;
-	h->drv[logvol].blk_size = BLOCK_SIZE;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].blk_size = 0;
 	return(0);
 
 }
@@ -1806,6 +1990,7 @@
 	cmdlist_t *c;
 	unsigned long flags;
 	ctlr_info_t *info_p = hba[ctlr];
+	DECLARE_COMPLETION(wait);
 
 	c = cmd_alloc(info_p, 0);
 	if(!c)
@@ -1835,6 +2020,7 @@
 	c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, 
 		buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 
+	c->waiting = &wait;
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&info_p->reqQ, c);
@@ -1843,8 +2029,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	if (c->req.hdr.rcode & RCODE_FATAL) {
 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
@@ -1885,14 +2070,12 @@
 		return -EINVAL;
 
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
 	}
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
@@ -1905,8 +2088,7 @@
 	 */
 	ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
 		ctlr, id_lstatus_buf, size, 0, 0, logvol);
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 			/*
 			   If can't get logical drive status, set
 			   the logical drive map to 0, so the
@@ -1922,8 +2104,7 @@
 	/*
 		   Make sure the logical drive is configured
 	 */
-	if (id_lstatus_buf->status == LOG_NOT_CONF) 
-	{
+	if (id_lstatus_buf->status == LOG_NOT_CONF) {
 		printk(KERN_WARNING "cpqarray: c%dd%d array not configured\n",
 			ctlr, logvol); 
 		kfree(id_lstatus_buf);
@@ -1937,8 +2118,7 @@
 			   logical drive won't be set and
 			   idastubopen will return error. 
 			 */
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 		printk(KERN_WARNING "cpqarray: c%dd%d unable to ID logical volume\n",
 			ctlr,logvol);
 		kfree(id_lstatus_buf);
@@ -1963,8 +2143,7 @@
 	max_p = gdev->max_p;
 	start = logvol<< gdev->minor_shift;
 	
-	for(i=max_p-1; i>=0; i--) 
-	{
+	for(i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
 		gdev->part[minor].start_sect = 0;
@@ -1972,6 +2151,7 @@
 	
 		/* reset the blocksize so we can read the partition table */
 		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = drv->blk_size;
 	}
 	++hba[ctlr]->log_drives;
 	gdev->nr_real = info_p->highest_lun + 1;
@@ -2075,8 +2255,7 @@
 	/* Command does not return anything, but idasend command needs a 
 		buffer */
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf==NULL)
-	{
+	if(id_ctlr_buf==NULL) {
 		printk(KERN_WARNING "cpqarray: Out of memory. "
 			"Unable to start background processing.\n");
 		return;
@@ -2110,23 +2289,20 @@
 	info_p->log_drv_map = 0;	
 	
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf == NULL)
-	{
+	if(id_ctlr_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
@@ -2134,8 +2310,7 @@
 	}
 
 	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
-	if(sense_config_buf == NULL)
-	{
+	if(sense_config_buf == NULL) {
 		kfree(id_lstatus_buf);
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
@@ -2285,10 +2460,8 @@
 
         pci_unregister_driver(&cpqarray_pci_driver);
         /* double check that all controller entrys have been removed */
-        for (i=0; i< MAX_CTLR; i++)
-        {
-                if (hba[i] != NULL)
-                {
+        for (i=0; i< MAX_CTLR; i++) {
+                if (hba[i] != NULL) {
                         printk(KERN_WARNING "cpqarray: had to remove"
                                         " controller %d\n", i);
                         cpqarray_remove_one_eisa(i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/elevator.c linux-2.4.21-rc3/drivers/block/elevator.c
--- linux-2.4.20/drivers/block/elevator.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/elevator.c	2003-05-22 22:06:51.000000000 +0000
@@ -83,21 +83,22 @@
 	struct list_head *entry = &q->queue_head;
 	unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
 	struct request *__rq;
+	int backmerge_only = 0;
 
-	while ((entry = entry->prev) != head) {
+	while (!backmerge_only && (entry = entry->prev) != head) {
 		__rq = blkdev_entry_to_request(entry);
 
 		/*
 		 * we can't insert beyond a zero sequence point
 		 */
 		if (__rq->elevator_sequence <= 0)
-			break;
+			backmerge_only = 1;
 
 		if (__rq->waiting)
 			continue;
 		if (__rq->rq_dev != bh->b_rdev)
 			continue;
-		if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head))
+		if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head) && !backmerge_only)
 			*req = __rq;
 		if (__rq->cmd != rw)
 			continue;
@@ -107,7 +108,7 @@
 			ret = ELEVATOR_BACK_MERGE;
 			*req = __rq;
 			break;
-		} else if (__rq->sector - count == bh->b_rsector) {
+		} else if (__rq->sector - count == bh->b_rsector && !backmerge_only) {
 			ret = ELEVATOR_FRONT_MERGE;
 			__rq->elevator_sequence--;
 			*req = __rq;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_cmd.h linux-2.4.21-rc3/drivers/block/ida_cmd.h
--- linux-2.4.20/drivers/block/ida_cmd.h	2001-11-03 01:45:42.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/ida_cmd.h	2003-05-22 22:06:39.000000000 +0000
@@ -82,7 +82,6 @@
 
 #define CMD_RWREQ	0x00
 #define CMD_IOCTL_PEND	0x01
-#define CMD_IOCTL_DONE	0x02
 
 typedef struct cmdlist {
 	chdr_t	hdr;
@@ -94,6 +93,7 @@
 	struct cmdlist *prev;
 	struct cmdlist *next;
 	struct request *rq;
+	struct completion *waiting;
 	int type;
 } cmdlist_t;
 	
@@ -318,6 +318,8 @@
 	__u8	reserved[510];
 } mp_delay_t;
 
+#define SENSE_SURF_STATUS	0x70
+
 #define PASSTHRU_A	0x91
 typedef struct {
 	__u8	target;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_ioctl.h linux-2.4.21-rc3/drivers/block/ida_ioctl.h
--- linux-2.4.20/drivers/block/ida_ioctl.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/ida_ioctl.h	2003-05-22 22:06:44.000000000 +0000
@@ -34,6 +34,7 @@
 #define IDADEREGDISK		0x33333434
 #define IDAREGNEWDISK		0x34343535
 #define IDAGETLOGINFO		0x35353636
+#define IDABIGPASSTHRU          0x36363535
 
 typedef struct _ida_pci_info_struct
 {
@@ -94,4 +95,27 @@
 	} c;
 } ida_ioctl_t;
 
+#define IDA_MAX_KMALLOC_SIZE 128000
+
+/* transfer type of the commands */
+#define IDA_XFER_NONE	0x00
+#define IDA_XFER_READ	0x01
+#define IDA_XFER_WRITE	0x02
+#define IDA_XFER_BOTH	0x03
+
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+	__u32	blk;
+	__u16	blk_cnt;
+
+	__u8	xfer_type;
+	__u8    *buff;
+	size_t	buff_size;
+	__u32	buff_malloc_size;
+	scsi_param_t *scsi_param; /* used only for PASSTHRU_A */
+
+} ida_big_ioctl_t;
+
 #endif /* IDA_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ll_rw_blk.c linux-2.4.21-rc3/drivers/block/ll_rw_blk.c
--- linux-2.4.20/drivers/block/ll_rw_blk.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/ll_rw_blk.c	2003-05-22 22:06:26.000000000 +0000
@@ -394,7 +394,7 @@
 	unsigned long flags;
 	/* Several broken drivers assume that this function doesn't sleep,
 	 * this causes system hangs during boot.
-	 * As a temporary fix, make the the function non-blocking.
+	 * As a temporary fix, make the function non-blocking.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
 	while (q->nr_requests < nr_requests) {
@@ -1129,7 +1129,7 @@
 
 		if (maxsector < count || maxsector - count < sector) {
 			/* Yecch */
-			bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
+			bh->b_state &= ~(1 << BH_Dirty);
 
 			/* This may well happen - the kernel calls bread()
 			   without checking the size of the device, e.g.,
@@ -1140,7 +1140,6 @@
 			       kdevname(bh->b_rdev), rw,
 			       (sector + count)>>1, minorsize);
 
-			/* Yecch again */
 			bh->b_end_io(bh, 0);
 			return;
 		}
@@ -1376,11 +1375,12 @@
 
 void end_that_request_last(struct request *req)
 {
-	if (req->waiting != NULL)
-		complete(req->waiting);
-	req_finished_io(req);
+	struct completion *waiting = req->waiting;
 
+	req_finished_io(req);
 	blkdev_release_request(req);
+	if (waiting)
+		complete(waiting);
 }
 
 int __init blk_dev_init(void)
@@ -1413,12 +1413,6 @@
 #ifdef CONFIG_ISP16_CDI
 	isp16_init();
 #endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
-	ide_init();		/* this MUST precede hd_init */
-#endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
-	hd_init();
-#endif
 #ifdef CONFIG_BLK_DEV_PS2
 	ps2esdi_init();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/loop.c linux-2.4.21-rc3/drivers/block/loop.c
--- linux-2.4.20/drivers/block/loop.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/loop.c	2003-05-22 22:06:48.000000000 +0000
@@ -199,9 +199,9 @@
 		page = grab_cache_page(mapping, index);
 		if (!page)
 			goto fail;
+		kaddr = kmap(page);
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
-		kaddr = page_address(page);
 		flush_dcache_page(page);
 		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV);
 		if (transfer_result) {
@@ -216,6 +216,7 @@
 			goto unlock;
 		if (transfer_result)
 			goto unlock;
+		kunmap(page);
 		data += size;
 		len -= size;
 		offset = 0;
@@ -228,6 +229,7 @@
 	return 0;
 
 unlock:
+	kunmap(page);
 	UnlockPage(page);
 	page_cache_release(page);
 fail:
@@ -418,6 +420,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 	memset(bh, 0, sizeof(*bh));
@@ -437,6 +440,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 
@@ -563,6 +567,7 @@
 
 	daemonize();
 	exit_files(current);
+	reparent_to_init();
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
@@ -571,9 +576,6 @@
 	flush_signals(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	current->policy = SCHED_OTHER;
-	current->nice = -20;
-
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_bound;
 	atomic_inc(&lo->lo_pending);
@@ -645,7 +647,7 @@
 		lo_device = inode->i_rdev;
 		if (lo_device == dev) {
 			error = -EBUSY;
-			goto out;
+			goto out_putf;
 		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
@@ -1014,11 +1016,6 @@
 		return -EIO;
 	}
 
-	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
-	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
-			      MAJOR_NR, 0,
-			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-			      &lo_fops, NULL);
 
 	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
 	if (!loop_dev)
@@ -1051,13 +1048,21 @@
 	for (i = 0; i < max_loop; i++)
 		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
 
+	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
+	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
+			      MAJOR_NR, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			      &lo_fops, NULL);
+
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
-out_sizes:
-	kfree(loop_dev);
 out_blksizes:
 	kfree(loop_sizes);
+out_sizes:
+	kfree(loop_dev);
+	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
+		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
 }
@@ -1067,7 +1072,6 @@
 	devfs_unregister(devfs_handle);
 	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
 	kfree(loop_dev);
 	kfree(loop_sizes);
 	kfree(loop_blksizes);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/nbd.c linux-2.4.21-rc3/drivers/block/nbd.c
--- linux-2.4.20/drivers/block/nbd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/nbd.c	2003-05-22 22:06:38.000000000 +0000
@@ -26,6 +26,8 @@
  *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
  * 01-12-6 Fix deadlock condition by making queue locks independant of
  *   the transmit lock. <steve@chygwyn.com>
+ * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
+ *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
  *
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
  * why not: would need verify_area and friends, would share yet another 
@@ -101,9 +103,12 @@
 	oldfs = get_fs();
 	set_fs(get_ds());
 
+	/* Allow interception of SIGKILL only
+	 * Don't allow other signals to interrupt the transmission */
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
+	sigdelsetmask(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
@@ -126,6 +131,17 @@
 		else
 			result = sock_recvmsg(sock, &msg, size, 0);
 
+		if (signal_pending(current)) {
+			siginfo_t info;
+			spin_lock_irqsave(&current->sigmask_lock, flags);
+			printk(KERN_WARNING "NBD (pid %d: %s) got signal %d\n",
+				current->pid, current->comm, 
+				dequeue_signal(&current->blocked, &info));
+			spin_unlock_irqrestore(&current->sigmask_lock, flags);
+			result = -EINTR;
+			break;
+		}
+
 		if (result <= 0) {
 #ifdef PARANOIA
 			printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n",
@@ -150,7 +166,7 @@
 
 void nbd_send_req(struct nbd_device *lo, struct request *req)
 {
-	int result;
+	int result = -1;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
@@ -164,6 +180,10 @@
 
 	down(&lo->tx_lock);
 
+	if (!sock || !lo->sock) {
+		FAIL("Attempted sendmsg to closed socket\n");
+	}
+
 	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
 	if (result <= 0)
 		FAIL("Sendmsg failed for control.");
@@ -345,10 +365,28 @@
 		spin_unlock_irq(&io_request_lock);
 
 		spin_lock(&lo->queue_lock);
+		if (!lo->file) {
+			spin_unlock(&lo->queue_lock);
+			printk(KERN_ERR "nbd: failed between accept and semaphore, file lost\n");
+			req->errors++;
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
+
 		list_add_tail(&req->queue, &lo->queue_head);
 		spin_unlock(&lo->queue_lock);
 
 		nbd_send_req(lo, req);
+		if (req->errors) {
+			printk(KERN_ERR "nbd: nbd_send_req failed\n");
+			spin_lock(&lo->queue_lock);
+			list_del(&req->queue);
+			spin_unlock(&lo->queue_lock);
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
 
 		spin_lock_irq(&io_request_lock);
 		continue;
@@ -397,12 +435,14 @@
 			printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
 			return -EBUSY;
 		}
-		spin_unlock(&lo->queue_lock);
 		file = lo->file;
-		if (!file)
+		if (!file) {
+			spin_unlock(&lo->queue_lock);
 			return -EINVAL;
+		}
 		lo->file = NULL;
 		lo->sock = NULL;
+		spin_unlock(&lo->queue_lock);
 		fput(file);
 		return 0;
 	case NBD_SET_SOCK:
@@ -443,6 +483,26 @@
 		if (!lo->file)
 			return -EINVAL;
 		nbd_do_it(lo);
+		/* on return tidy up in case we have a signal */
+		/* Forcibly shutdown the socket causing all listeners
+		 * to error
+		 *
+		 * FIXME: This code is duplicated from sys_shutdown, but
+		 * there should be a more generic interface rather than
+		 * calling socket ops directly here */
+		down(&lo->tx_lock);
+		printk(KERN_WARNING "nbd: shutting down socket\n");
+		lo->sock->ops->shutdown(lo->sock, SEND_SHUTDOWN|RCV_SHUTDOWN);
+		lo->sock = NULL;
+		up(&lo->tx_lock);
+		spin_lock(&lo->queue_lock);
+		file = lo->file;
+		lo->file = NULL;
+		spin_unlock(&lo->queue_lock);
+		nbd_clear_que(lo);
+		printk(KERN_WARNING "nbd: queue cleared\n");
+		if (file)
+			fput(file);
 		return lo->harderror;
 	case NBD_CLEAR_QUE:
 		nbd_clear_que(lo);
@@ -523,7 +583,7 @@
 		init_MUTEX(&nbd_dev[i].tx_lock);
 		nbd_blksizes[i] = 1024;
 		nbd_blksize_bits[i] = 10;
-		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
+		nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */
 		nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
 		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
 				nbd_bytesizes[i]>>9);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/umem.c linux-2.4.21-rc3/drivers/block/umem.c
--- linux-2.4.20/drivers/block/umem.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/block/umem.c	2003-05-22 22:06:50.000000000 +0000
@@ -151,6 +151,7 @@
 	spinlock_t 	lock;
 	int		check_batteries;
 
+	int		flags;
 };
 
 static struct cardinfo cards[MM_MAXCARDS];
@@ -575,9 +576,12 @@
         }
 
 	/* clear COMPLETION interrupts */
-	writel(cpu_to_le32(DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE),
-	       card->csr_remap+ DMA_STATUS_CTRL);
-
+	if (card->flags & UM_FLAG_NO_BYTE_STATUS)
+		writel(cpu_to_le32(DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE),
+		       card->csr_remap+ DMA_STATUS_CTRL);
+	else
+		writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16,
+		       card->csr_remap+ DMA_STATUS_CTRL + 2);
 	
 	/* log errors and clear interrupt status */
 	if (dma_status & DMASCR_ANY_ERR) {
@@ -741,15 +745,16 @@
 {
 	int i;
 
-	for (i = 0; i < num_cards; i++) {
-		struct cardinfo *card = &cards[i];
-		spin_lock_bh(&card->lock);
-		if (card->Active >= 0)
-			card->check_batteries = 1;
-		else
-			check_batteries(card);
-		spin_unlock_bh(&card->lock);
-	}
+	for (i = 0; i < num_cards; i++) 
+		if (!(cards[i].flags & UM_FLAG_NO_BATT)) {
+			struct cardinfo *card = &cards[i];
+			spin_lock_bh(&card->lock);
+			if (card->Active >= 0)
+				card->check_batteries = 1;
+			else
+				check_batteries(card);
+			spin_unlock_bh(&card->lock);
+		}
 
 	init_battery_timer();
 }
@@ -1069,6 +1074,7 @@
 	unsigned char	mem_present;
 	unsigned char	batt_status;
 	unsigned int	saved_bar, data;
+	int		magic_number;
 
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
@@ -1133,12 +1139,32 @@
 	printk(KERN_INFO "MM%d: MEM area not remapped (CONFIG_MM_MAP_MEMORY not set)\n",
 	       card->card_number);
 #endif
-	if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != MM_MAGIC_VALUE) {
+	switch(card->dev->device) {
+	case 0x5415:
+		card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG;
+		magic_number = 0x59;
+		break;
+
+	case 0x5425:
+		magic_number = 0x5C;
+		break;
+
+	case 0x6155:
+		card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG | UM_FLAG_NO_BATT;
+		magic_number = 0x99;
+		break;
+
+	default:
+		magic_number = 0x100;
+		break;
+	}
+
+	if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) {
 		printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number);
 		ret = -ENOMEM;
-
 		goto failed_magic;
 	}
+
 	card->mm_pages[0].desc = pci_alloc_consistent(card->dev,
 						      PAGE_SIZE*2,
 						      &card->mm_pages[0].page_dma);
@@ -1196,14 +1222,19 @@
 	card->battery[1].good = !(batt_status & BATTERY_2_FAILURE);
 	card->battery[0].last_change = card->battery[1].last_change = jiffies;
 
-	printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
-	       card->card_number, card->mm_size,
-	       (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"),
-	       card->battery[0].good ? "OK" : "FAILURE",
-	       (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"),
-	       card->battery[1].good ? "OK" : "FAILURE");
+	if (card->flags & UM_FLAG_NO_BATT) 
+		printk(KERN_INFO "MM%d: Size %d KB\n",
+		       card->card_number, card->mm_size);
+	else {
+		printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
+		       card->card_number, card->mm_size,
+		       (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"),
+		       card->battery[0].good ? "OK" : "FAILURE",
+		       (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"),
+		       card->battery[1].good ? "OK" : "FAILURE");
 
-	set_fault_to_battery_status(card);
+		set_fault_to_battery_status(card);
+	}
 
 	pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &saved_bar);
 	data = 0xffffffff;
@@ -1230,7 +1261,7 @@
 
         spin_lock_init(&card->lock);
 
-	dev->driver_data = card;
+	pci_set_drvdata(dev, card);
 
 	if (pci_write_cmd != 0x0F) 	/* If not Memory Write & Invalidate */
 		pci_write_cmd = 0x07;	/* then Memory Write command */
@@ -1290,7 +1321,7 @@
 */
 static void mm_pci_remove(struct pci_dev *dev)
 {
-	struct cardinfo *card = dev->driver_data;
+	struct cardinfo *card = pci_get_drvdata(dev);
 
 	tasklet_kill(&card->tasklet);
 	iounmap(card->csr_remap);
@@ -1314,6 +1345,19 @@
 static const struct pci_device_id __devinitdata mm_pci_ids[] = { {
 	vendor:		PCI_VENDOR_ID_MICRO_MEMORY,
 	device:		PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
+	}, {
+	vendor:		PCI_VENDOR_ID_MICRO_MEMORY,
+	device:		PCI_DEVICE_ID_MICRO_MEMORY_5425CN,
+	}, {
+	.vendor =	PCI_VENDOR_ID_MICRO_MEMORY,
+	.device =	PCI_DEVICE_ID_MICRO_MEMORY_6155,
+	}, {
+	.vendor	=	0x8086,
+	.device	=	0xB555,
+	.subvendor=	0x1332,
+	.subdevice=	0x5460,
+	.class	=	0x050000,
+	.class_mask=	0,
 	}, { /* end: all zeroes */ }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Config.in linux-2.4.21-rc3/drivers/bluetooth/Config.in
--- linux-2.4.20/drivers/bluetooth/Config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/Config.in	2003-05-22 22:06:48.000000000 +0000
@@ -1,14 +1,21 @@
+#
+# Bluetooth HCI device drivers configuration
+#
+
 mainmenu_option next_comment
 comment 'Bluetooth device drivers'
 
 dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
 if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
+   bool '  SCO (voice) support'  CONFIG_BLUEZ_USB_SCO
    bool '  USB zero packet support'  CONFIG_BLUEZ_USB_ZERO_PACKET
 fi
 
 dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
 if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
    bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
+   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
+   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
 fi
 
 dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
@@ -17,6 +24,9 @@
 
 dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
 
+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
+
 dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
 
 endmenu
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Makefile linux-2.4.21-rc3/drivers/bluetooth/Makefile
--- linux-2.4.20/drivers/bluetooth/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/Makefile	2003-05-22 22:06:53.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for Bluetooth HCI device drivers.
+# Makefile for the Linux Bluetooth HCI device drivers
 #
 
 O_TARGET	:= bluetooth.o
@@ -9,13 +9,15 @@
 obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
 obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
 
-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
-uart-y				:= hci_ldisc.o
-uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
+obj-$(CONFIG_BLUEZ_HCIUART)		+= hci_uart.o
+uart-y					:= hci_ldisc.o
+uart-$(CONFIG_BLUEZ_HCIUART_H4)		+= hci_h4.o
+uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
 
 obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
 obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
 obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
+obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
 
 include $(TOPDIR)/Rules.make
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/btuart_cs.c linux-2.4.21-rc3/drivers/bluetooth/btuart_cs.c
--- linux-2.4.20/drivers/bluetooth/btuart_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/btuart_cs.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,906 @@
+/*
+ *
+ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct btuart_info_t {
+	dev_link_t link;
+	dev_node_t node;
+
+	struct hci_dev hdev;
+
+	spinlock_t lock;	/* For serializing operations */
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+} btuart_info_t;
+
+
+void btuart_config(dev_link_t *link);
+void btuart_release(u_long arg);
+int btuart_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "btuart_cs";
+
+dev_link_t *btuart_attach(void);
+void btuart_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+
+/* Maximum baud rate */
+#define SPEED_MAX  115200
+
+/* Default baud rate: 57600, 115200, 230400 or 460800 */
+#define DEFAULT_BAUD_RATE  115200
+
+
+/* Transmit states  */
+#define XMIT_SENDING	1
+#define XMIT_WAKEUP	2
+#define XMIT_WAITING	8
+
+/* Receiver states */
+#define RECV_WAIT_PACKET_TYPE	0
+#define RECV_WAIT_EVENT_HEADER	1
+#define RECV_WAIT_ACL_HEADER	2
+#define RECV_WAIT_SCO_HEADER	3
+#define RECV_WAIT_DATA		4
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	/* Tx FIFO should be empty */
+	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
+		return 0;
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase + UART_TX);
+		actual++;
+	}
+
+	return actual;
+}
+
+
+static void btuart_write_wakeup(btuart_info_t *info)
+{
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (!(info->link.state & DEV_PRESENT))
+			return;
+
+		if (!(skb = skb_dequeue(&(info->txq))))
+			break;
+
+		/* Send frame */
+		len = btuart_write(iobase, 16, skb->data, skb->len);
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (len == skb->len) {
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, len);
+			skb_queue_head(&(info->txq), skb);
+		}
+
+		info->hdev.stat.byte_tx += len;
+
+	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+	clear_bit(XMIT_SENDING, &(info->tx_state));
+}
+
+
+static void btuart_receive(btuart_info_t *info)
+{
+	unsigned int iobase;
+	int boguscount = 0;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	do {
+		info->hdev.stat.byte_rx++;
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL) {
+			info->rx_state = RECV_WAIT_PACKET_TYPE;
+			info->rx_count = 0;
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
+				return;
+			}
+		}
+
+		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
+
+			info->rx_skb->dev = (void *)&(info->hdev);
+			info->rx_skb->pkt_type = inb(iobase + UART_RX);
+
+			switch (info->rx_skb->pkt_type) {
+
+			case HCI_EVENT_PKT:
+				info->rx_state = RECV_WAIT_EVENT_HEADER;
+				info->rx_count = HCI_EVENT_HDR_SIZE;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				info->rx_state = RECV_WAIT_ACL_HEADER;
+				info->rx_count = HCI_ACL_HDR_SIZE;
+				break;
+
+			case HCI_SCODATA_PKT:
+				info->rx_state = RECV_WAIT_SCO_HEADER;
+				info->rx_count = HCI_SCO_HDR_SIZE;
+				break;
+
+			default:
+				/* Unknown packet */
+				printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+				info->hdev.stat.err_rx++;
+				clear_bit(HCI_RUNNING, &(info->hdev.flags));
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			}
+
+		} else {
+
+			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
+			info->rx_count--;
+
+			if (info->rx_count == 0) {
+
+				int dlen;
+				hci_event_hdr *eh;
+				hci_acl_hdr *ah;
+				hci_sco_hdr *sh;
+
+
+				switch (info->rx_state) {
+
+				case RECV_WAIT_EVENT_HEADER:
+					eh = (hci_event_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = eh->plen;
+					break;
+
+				case RECV_WAIT_ACL_HEADER:
+					ah = (hci_acl_hdr *)(info->rx_skb->data);
+					dlen = __le16_to_cpu(ah->dlen);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = dlen;
+					break;
+
+				case RECV_WAIT_SCO_HEADER:
+					sh = (hci_sco_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = sh->dlen;
+					break;
+
+				case RECV_WAIT_DATA:
+					hci_recv_frame(info->rx_skb);
+					info->rx_skb = NULL;
+					break;
+
+				}
+
+			}
+
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 16)
+			break;
+
+	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
+}
+
+
+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	btuart_info_t *info = dev_inst;
+	unsigned int iobase;
+	int boguscount = 0;
+	int iir, lsr;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+	while (iir) {
+
+		/* Clear interrupt */
+		lsr = inb(iobase + UART_LSR);
+
+		switch (iir) {
+		case UART_IIR_RLSI:
+			printk(KERN_NOTICE "btuart_cs: RLSI\n");
+			break;
+		case UART_IIR_RDI:
+			/* Receive interrupt */
+			btuart_receive(info);
+			break;
+		case UART_IIR_THRI:
+			if (lsr & UART_LSR_THRE) {
+				/* Transmitter ready for data */
+				btuart_write_wakeup(info);
+			}
+			break;
+		default:
+			printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
+			break;
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 100)
+			break;
+
+		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+
+	}
+
+	spin_unlock(&(info->lock));
+}
+
+
+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+{
+	unsigned long flags;
+	unsigned int iobase;
+	int fcr;		/* FIFO control reg */
+	int lcr;		/* Line control reg */
+	int divisor;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	divisor = SPEED_MAX / speed;
+
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+
+	/* 
+	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+	 * about this timeout since it will always be fast enough. 
+	 */
+
+	if (speed < 38400)
+		fcr |= UART_FCR_TRIGGER_1;
+	else
+		fcr |= UART_FCR_TRIGGER_14;
+
+	/* Bluetooth cards use 8N1 */
+	lcr = UART_LCR_WLEN8;
+
+	outb(UART_LCR_DLAB | lcr, iobase + UART_LCR);	/* Set DLAB */
+	outb(divisor & 0xff, iobase + UART_DLL);	/* Set speed */
+	outb(divisor >> 8, iobase + UART_DLM);
+	outb(lcr, iobase + UART_LCR);	/* Set 8N1  */
+	outb(fcr, iobase + UART_FCR);	/* Enable FIFO's */
+
+	/* Turn on interrups */
+	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+}
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int btuart_hci_flush(struct hci_dev *hdev)
+{
+	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	return 0;
+}
+
+
+static int btuart_hci_open(struct hci_dev *hdev)
+{
+	set_bit(HCI_RUNNING, &(hdev->flags));
+
+	return 0;
+}
+
+
+static int btuart_hci_close(struct hci_dev *hdev)
+{
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	btuart_hci_flush(hdev);
+
+	return 0;
+}
+
+
+static int btuart_hci_send_frame(struct sk_buff *skb)
+{
+	btuart_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+
+	if (!hdev) {
+		printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
+
+	info = (btuart_info_t *)(hdev->driver_data);
+
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	};
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+	skb_queue_tail(&(info->txq), skb);
+
+	btuart_write_wakeup(info);
+
+	return 0;
+}
+
+
+static void btuart_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+
+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int btuart_open(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev;
+
+	spin_lock_init(&(info->lock));
+
+	skb_queue_head_init(&(info->txq));
+
+	info->rx_state = RECV_WAIT_PACKET_TYPE;
+	info->rx_count = 0;
+	info->rx_skb = NULL;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	/* Initialize UART */
+	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+
+	/* Turn on interrupts */
+	// outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	btuart_change_speed(info, DEFAULT_BAUD_RATE);
+
+	/* Timeout before it is safe to send the first HCI packet */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ);
+
+
+	/* Initialize and register HCI device */
+
+	hdev = &(info->hdev);
+
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
+
+	hdev->open = btuart_hci_open;
+	hdev->close = btuart_hci_close;
+	hdev->flush = btuart_hci_flush;
+	hdev->send = btuart_hci_send_frame;
+	hdev->destruct = btuart_hci_destruct;
+	hdev->ioctl = btuart_hci_ioctl;
+
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+int btuart_close(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev = &(info->hdev);
+
+	btuart_hci_close(hdev);
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+	return 0;
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *btuart_attach(void)
+{
+	btuart_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &btuart_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+	link->irq.Handler = btuart_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &btuart_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		btuart_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void btuart_detach(dev_link_t *link)
+{
+	btuart_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+
+	if (*linkp == NULL)
+		return;
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG)
+		btuart_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
+
+	return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void btuart_config(dev_link_t *link)
+{
+	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	client_handle_t handle = link->handle;
+	btuart_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	config_info_t config;
+	int i, j, try, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	/* First pass: look for a config entry that looks normal. */
+	tuple.TupleData = (cisdata_t *) buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	/* Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++) {
+		i = first_tuple(handle, &tuple, &parse);
+		while (i != CS_NO_MORE_ITEMS) {
+			if (i != CS_SUCCESS)
+				goto next_entry;
+			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
+				link->conf.ConfigIndex = cf->index;
+				link->io.BasePort1 = cf->io.win[0].base;
+				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+next_entry:
+			i = next_tuple(handle, &tuple, &parse);
+		}
+	}
+
+	/* Second pass: try to find an entry that isn't picky about
+	   its base address, then try to grab any standard serial port
+	   address, and finally try to get any free port. */
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
+		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+			link->conf.ConfigIndex = cf->index;
+			for (j = 0; j < 5; j++) {
+				link->io.BasePort1 = base[j];
+				link->io.IOAddrLines = base[j] ? 16 : 3;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+		}
+		i = next_tuple(handle, &tuple, &parse);
+	}
+
+found_port:
+	if (i != CS_SUCCESS) {
+		printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (btuart_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+
+failed:
+	btuart_release((u_long) link);
+}
+
+
+void btuart_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	btuart_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		btuart_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+
+int btuart_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	btuart_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			btuart_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		btuart_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_btuart_cs(void)
+{
+	servinfo_t serv;
+	int err;
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
+		return -1;
+	}
+
+	err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
+
+	return err;
+}
+
+
+void __exit exit_btuart_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
+
+	while (dev_list != NULL)
+		btuart_detach(dev_list);
+}
+
+
+module_init(init_btuart_cs);
+module_exit(exit_btuart_cs);
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.c linux-2.4.21-rc3/drivers/bluetooth/hci_bcsp.c
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_bcsp.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,710 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#define VERSION "0.1"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
+#include "hci_bcsp.h"
+
+#ifndef HCI_UART_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#undef  BT_DMP
+#define BT_DMP( A... )
+#endif
+
+/* ---- BCSP CRC calculation ---- */
+
+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
+initial value 0xffff, bits shifted in reverse order. */
+
+static const u16 crc_table[] = {
+	0x0000, 0x1081, 0x2102, 0x3183,
+	0x4204, 0x5285, 0x6306, 0x7387,
+	0x8408, 0x9489, 0xa50a, 0xb58b,
+	0xc60c, 0xd68d, 0xe70e, 0xf78f
+};
+
+/* Initialise the crc calculator */
+#define BCSP_CRC_INIT(x) x = 0xffff
+
+/*
+   Update crc with next data byte
+
+   Implementation note
+        The data byte is treated as two nibbles.  The crc is generated
+        in reverse, i.e., bits are fed into the register from the top.
+*/
+static void bcsp_crc_update(u16 *crc, u8 d)
+{
+	u16 reg = *crc;
+
+	reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
+	reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
+
+	*crc = reg;
+}
+
+/*
+   Get reverse of generated crc
+
+   Implementation note
+        The crc generator (bcsp_crc_init() and bcsp_crc_update())
+        creates a reversed crc, so it needs to be swapped back before
+        being passed on.
+*/
+static u16 bcsp_crc_reverse(u16 crc)
+{
+	u16 b, rev;
+
+	for (b = 0, rev = 0; b < 16; b++) {
+		rev = rev << 1;
+		rev |= (crc & 1);
+		crc = crc >> 1;
+	}
+	return (rev);
+}
+
+/* ---- BCSP core ---- */
+
+static void bcsp_slip_msgdelim(struct sk_buff *skb)
+{
+	const char pkt_delim = 0xc0;
+	memcpy(skb_put(skb, 1), &pkt_delim, 1);
+}
+
+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
+{
+	const char esc_c0[2] = { 0xdb, 0xdc };
+	const char esc_db[2] = { 0xdb, 0xdd };
+
+	switch (c) {
+	case 0xc0:
+		memcpy(skb_put(skb, 2), &esc_c0, 2);
+		break;
+	case 0xdb:
+		memcpy(skb_put(skb, 2), &esc_db, 2);
+		break;
+	default:
+		memcpy(skb_put(skb, 1), &c, 1);
+	}
+}
+
+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+
+	if (skb->len > 0xFFF) {
+		BT_ERR("Packet too long");
+		kfree_skb(skb);
+		return 0;
+	}
+
+	switch (skb->pkt_type) {
+	case HCI_ACLDATA_PKT:
+	case HCI_COMMAND_PKT:
+		skb_queue_tail(&bcsp->rel, skb);
+		break;
+
+	case HCI_SCODATA_PKT:
+		skb_queue_tail(&bcsp->unrel, skb);
+		break;
+		
+	default:
+		BT_ERR("Unknown packet type");
+		kfree_skb(skb);
+		break;
+	}
+	return 0;
+}
+
+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
+		int len, int pkt_type)
+{
+	struct sk_buff *nskb;
+	u8  hdr[4], chan;
+	int rel, i;
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
+#endif
+
+	switch (pkt_type) {
+	case HCI_ACLDATA_PKT:
+		chan = 6;	/* BCSP ACL channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_COMMAND_PKT:
+		chan = 5;	/* BCSP cmd/evt channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_SCODATA_PKT:
+		chan = 7;	/* BCSP SCO channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_LE_PKT:
+		chan = 1;	/* BCSP LE channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_ACK_PKT:
+		chan = 0;	/* BCSP internal channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	default:
+		BT_ERR("Unknown packet type");
+		return NULL;
+	}
+
+	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
+	   (because bytes 0xc0 and 0xdb are escaped, worst case is
+	   when the packet is all made of 0xc0 and 0xdb :) )
+	   + 2 (0xc0 delimiters at start and end). */
+
+	nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
+	if (!nskb)
+		return NULL;
+
+	nskb->pkt_type = pkt_type;
+
+	bcsp_slip_msgdelim(nskb);
+
+	hdr[0] = bcsp->rxseq_txack << 3;
+	bcsp->txack_req = 0;
+	BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
+
+	if (rel) {
+		hdr[0] |= 0x80 + bcsp->msgq_txseq;
+		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
+		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
+	}
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	hdr[0] |= 0x40;
+#endif
+
+	hdr[1]  = (len << 4) & 0xFF;
+	hdr[1] |= chan;
+	hdr[2]  = len >> 4;
+	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
+
+	/* Put BCSP header */
+	for (i = 0; i < 4; i++) {
+		bcsp_slip_one_byte(nskb, hdr[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
+#endif
+	}
+
+	/* Put payload */
+	for (i = 0; i < len; i++) {
+		bcsp_slip_one_byte(nskb, data[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
+#endif
+	}
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	/* Put CRC */
+	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
+	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
+	bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
+#endif
+
+	bcsp_slip_msgdelim(nskb);
+	return nskb;
+}
+
+/* This is a rewrite of pkt_avail in ABCSP */
+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	unsigned long flags;
+	struct sk_buff *skb;
+	
+	/* First of all, check for unreliable messages in the queue,
+	   since they have priority */
+
+	if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			kfree_skb(skb);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->unrel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	/* Now, try to send a reliable pkt. We can only send a
+	   reliable packet if the number of packets sent but not yet ack'ed
+	   is < than the winsize */
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			__skb_queue_tail(&bcsp->unack, skb);
+			mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
+			spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->rel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+
+	/* We could not send a reliable packet, either because there are
+	   none or because there are too many unack'ed pkts. Did we receive
+	   any packets we have not acknowledged yet ? */
+
+	if (bcsp->txack_req) {
+		/* if so, craft an empty ACK pkt and send it on BCSP unreliable
+		   channel 0 */
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
+		return nskb;
+	}
+
+	/* We have nothing to send */
+	return NULL;
+}
+
+static int bcsp_flush(struct hci_uart *hu)
+{
+	BT_DBG("hu %p", hu);
+	return 0;
+}
+
+/* Remove ack'ed packets */
+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+	int i, pkts_to_be_removed;
+	u8 seqno;
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	pkts_to_be_removed = bcsp->unack.qlen;
+	seqno = bcsp->msgq_txseq;
+
+	while (pkts_to_be_removed) {
+		if (bcsp->rxack == seqno)
+			break;
+		pkts_to_be_removed--;
+		seqno = (seqno - 1) & 0x07;
+	}
+
+	if (bcsp->rxack != seqno)
+		BT_ERR("Peer acked invalid packet");
+
+	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
+	       pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
+
+	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
+			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
+		struct sk_buff *nskb;
+
+		nskb = skb->next;
+		__skb_unlink(skb, &bcsp->unack);
+		kfree_skb(skb);
+		skb = nskb;
+	}
+	if (bcsp->unack.qlen == 0)
+		del_timer(&bcsp->tbcsp);
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	if (i != pkts_to_be_removed)
+		BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
+}
+
+/* Handle BCSP link-establishment packets. When we
+   detect a "sync" packet, symptom that the BT module has reset,
+   we do nothing :) (yet) */
+static void bcsp_handle_le_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
+	u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
+	u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
+
+	/* spot "conf" pkts and reply with a "conf rsp" pkt */
+	if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
+		struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
+
+		BT_DBG("Found a LE conf pkt");
+		if (!nskb)
+			return;
+		memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
+		nskb->pkt_type = BCSP_LE_PKT;
+
+		skb_queue_head(&bcsp->unrel, nskb);
+		hci_uart_tx_wakeup(hu);
+	}
+	/* Spot "sync" pkts. If we find one...disaster! */
+	else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
+		BT_ERR("Found a LE sync pkt, card has reset");
+	}
+}
+
+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
+{
+	const u8 c0 = 0xc0, db = 0xdb;
+
+	switch (bcsp->rx_esc_state) {
+	case BCSP_ESCSTATE_NOESC:
+		switch (byte) {
+		case 0xdb:
+			bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
+			break;
+		default:
+			memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp->message_crc, byte);
+			bcsp->rx_count--;
+		}
+		break;
+
+	case BCSP_ESCSTATE_ESC:
+		switch (byte) {
+		case 0xdc:
+			memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp-> message_crc, 0xc0);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		case 0xdd:
+			memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC) 
+				bcsp_crc_update(&bcsp-> message_crc, 0xdb);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		default:
+			BT_ERR ("Invalid byte %02x after esc byte", byte);
+			kfree_skb(bcsp->rx_skb);
+			bcsp->rx_skb = NULL;
+			bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+			bcsp->rx_count = 0;
+		}
+	}
+}
+
+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	int pass_up;
+
+	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
+		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
+		bcsp->rxseq_txack++;
+		bcsp->rxseq_txack %= 0x8;
+		bcsp->txack_req    = 1;
+
+		/* If needed, transmit an ack pkt */
+		hci_uart_tx_wakeup(hu);
+	}
+
+	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
+	BT_DBG("Request for pkt %u from card", bcsp->rxack);
+
+	bcsp_pkt_cull(bcsp);
+	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
+		bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
+			!(bcsp->rx_skb->data[0] & 0x80)) {
+		bcsp_handle_le_pkt(hu);
+		pass_up = 0;
+	} else
+		pass_up = 0;
+
+	if (!pass_up) {
+		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
+	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
+			BT_ERR ("Packet for unknown channel (%u %s)",
+				bcsp->rx_skb->data[1] & 0x0f,
+				bcsp->rx_skb->data[0] & 0x80 ? 
+				"reliable" : "unreliable");
+		}
+		kfree_skb(bcsp->rx_skb);
+	} else {
+		/* Pull out BCSP hdr */
+		skb_pull(bcsp->rx_skb, 4);
+
+		hci_recv_frame(bcsp->rx_skb);
+	}
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+	bcsp->rx_skb = NULL;
+}
+
+/* Recv data */
+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	register unsigned char *ptr;
+
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+		hu, count, bcsp->rx_state, bcsp->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (bcsp->rx_count) {
+			if (*ptr == 0xc0) {
+				BT_ERR("Short BCSP packet");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				bcsp->rx_count = 0;
+			} else
+				bcsp_unslip_one_byte(bcsp, *ptr);
+
+			ptr++; count--;
+			continue;
+		}
+
+		switch (bcsp->rx_state) {
+		case BCSP_W4_BCSP_HDR:
+			if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
+					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
+				BT_ERR("Error in BCSP hdr checksum");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
+			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
+				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
+					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			bcsp->rx_state = BCSP_W4_DATA;
+			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
+					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
+			continue;
+
+		case BCSP_W4_DATA:
+			if (bcsp->rx_skb->data[0] & 0x40) {	/* pkt with crc */
+				bcsp->rx_state = BCSP_W4_CRC;
+				bcsp->rx_count = 2;
+			} else
+				bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_CRC:
+			if (bcsp_crc_reverse(bcsp->message_crc) !=
+					(bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
+					bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
+
+				BT_ERR ("Checksum failed: computed %04x received %04x",
+					bcsp_crc_reverse(bcsp->message_crc),
+				     	(bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
+				     	bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
+			bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_PKT_DELIMITER:
+			switch (*ptr) {
+			case 0xc0:
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				break;
+			default:
+				/*BT_ERR("Ignoring byte %02x", *ptr);*/
+				break;
+			}
+			ptr++; count--;
+			break;
+
+		case BCSP_W4_PKT_START:
+			switch (*ptr) {
+			case 0xc0:
+				ptr++; count--;
+				break;
+
+			default:
+				bcsp->rx_state = BCSP_W4_BCSP_HDR;
+				bcsp->rx_count = 4;
+				bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+				BCSP_CRC_INIT(bcsp->message_crc);
+				
+				/* Do not increment ptr or decrement count
+				 * Allocate packet. Max len of a BCSP pkt= 
+				 * 0xFFF (payload) +4 (header) +2 (crc) */
+
+				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
+				if (!bcsp->rx_skb) {
+					BT_ERR("Can't allocate mem for new packet");
+					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+					bcsp->rx_count = 0;
+					return 0;
+				}
+				bcsp->rx_skb->dev = (void *) &hu->hdev;
+				break;
+			}
+			break;
+		}
+	}
+	return count;
+}
+
+	/* Arrange to retransmit all messages in the relq. */
+static void bcsp_timed_event(unsigned long arg)
+{
+	struct hci_uart *hu = (struct hci_uart *) arg;
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
+		bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
+		skb_queue_head(&bcsp->rel, skb);
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	hci_uart_tx_wakeup(hu);
+}
+
+static int bcsp_open(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp;
+
+	BT_DBG("hu %p", hu);
+
+	bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
+	if (!bcsp)
+		return -ENOMEM;
+	memset(bcsp, 0, sizeof(*bcsp));
+
+	hu->priv = bcsp;
+	skb_queue_head_init(&bcsp->unack);
+	skb_queue_head_init(&bcsp->rel);
+	skb_queue_head_init(&bcsp->unrel);
+
+	init_timer(&bcsp->tbcsp);
+	bcsp->tbcsp.function = bcsp_timed_event;
+	bcsp->tbcsp.data     = (u_long) hu;
+
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+
+	return 0;
+}
+
+static int bcsp_close(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	hu->priv = NULL;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&bcsp->unack);
+	skb_queue_purge(&bcsp->rel);
+	skb_queue_purge(&bcsp->unrel);
+	del_timer(&bcsp->tbcsp);
+
+	kfree(bcsp);
+	return 0;
+}
+
+static struct hci_uart_proto bcsp = {
+	id:      HCI_UART_BCSP,
+	open:    bcsp_open,
+	close:   bcsp_close,
+	enqueue: bcsp_enqueue,
+	dequeue: bcsp_dequeue,
+	recv:    bcsp_recv,
+	flush:   bcsp_flush
+};
+
+int bcsp_init(void)
+{
+	return hci_uart_register_proto(&bcsp);
+}
+
+int bcsp_deinit(void)
+{
+	return hci_uart_unregister_proto(&bcsp);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.h linux-2.4.21-rc3/drivers/bluetooth/hci_bcsp.h
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_bcsp.h	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,70 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+ * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#ifndef __HCI_BCSP_H__
+#define __HCI_BCSP_H__
+
+#define BCSP_TXWINSIZE  4
+
+#define BCSP_ACK_PKT    0x05
+#define BCSP_LE_PKT     0x06
+
+struct bcsp_struct {
+	struct sk_buff_head unack;	/* Unack'ed packets queue */
+	struct sk_buff_head rel;	/* Reliable packets queue */
+	struct sk_buff_head unrel;	/* Unreliable packets queue */
+
+	unsigned long rx_count;
+	struct  sk_buff *rx_skb;
+	u8      rxseq_txack;		/* rxseq == txack. */
+	u8      rxack;			/* Last packet sent by us that the peer ack'ed */
+	struct  timer_list tbcsp;
+	
+	enum {
+		BCSP_W4_PKT_DELIMITER,
+		BCSP_W4_PKT_START,
+		BCSP_W4_BCSP_HDR,
+		BCSP_W4_DATA,
+		BCSP_W4_CRC
+	} rx_state;
+
+	enum {
+		BCSP_ESCSTATE_NOESC,
+		BCSP_ESCSTATE_ESC
+	} rx_esc_state;
+
+	u16     message_crc;
+	u8      txack_req;		/* Do we need to send ack's to the peer? */
+
+	/* Reliable packet sequence number - used to assign seq to each rel pkt. */
+	u8      msgq_txseq;
+};
+
+#endif	/* __HCI_BCSP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.c linux-2.4.21-rc3/drivers/bluetooth/hci_h4.c
--- linux-2.4.20/drivers/bluetooth/hci_h4.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_h4.c	2003-05-22 22:06:50.000000000 +0000
@@ -25,15 +25,14 @@
 /*
  * BlueZ HCI UART(H4) protocol.
  *
- * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $    
  */
-#define VERSION "1.1"
+#define VERSION "1.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -64,63 +63,61 @@
 #endif
 
 /* Initialize protocol */
-static int h4_open(struct n_hci *n_hci)
+static int h4_open(struct hci_uart *hu)
 {
 	struct h4_struct *h4;
 	
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 	
 	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
 	if (!h4)
 		return -ENOMEM;
 	memset(h4, 0, sizeof(*h4));
 
-	n_hci->priv = h4;
+	skb_queue_head_init(&h4->txq);
+
+	hu->priv = h4;
 	return 0;
 }
 
 /* Flush protocol data */
-static int h4_flush(struct n_hci *n_hci)
+static int h4_flush(struct hci_uart *hu)
 {
-	BT_DBG("n_hci %p", n_hci);
+	struct h4_struct *h4 = hu->priv;
+
+	BT_DBG("hu %p", hu);
+	skb_queue_purge(&h4->txq);
 	return 0;
 }
 
 /* Close protocol */
-static int h4_close(struct n_hci *n_hci)
+static int h4_close(struct hci_uart *hu)
 {
-	struct h4_struct *h4 = n_hci->priv;
-	n_hci->priv = NULL;
+	struct h4_struct *h4 = hu->priv;
+	hu->priv = NULL;
 
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 
+	skb_queue_purge(&h4->txq);
 	if (h4->rx_skb)
 		kfree_skb(h4->rx_skb);
 
+	hu->priv = NULL;
 	kfree(h4);
 	return 0;
 }
 
-/* Send data */
-static int h4_send(struct n_hci *n_hci, void *data, int len)
+/* Enqueue frame for transmittion (padding, crc, etc) */
+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 {
-	struct tty_struct *tty = n_hci->tty;
-	
-	BT_DBG("n_hci %p len %d", n_hci, len);
+	struct h4_struct *h4 = hu->priv;
 
-	/* Send frame to TTY driver */
-	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-	return tty->driver.write(tty, 0, data, len);
-}
-
-/* Init frame before queueing (padding, crc, etc) */
-static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
-{
-	BT_DBG("n_hci %p skb %p", n_hci, skb);
+	BT_DBG("hu %p skb %p", hu, skb);
 
 	/* Prepend skb with frame type */
 	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-	return skb;
+	skb_queue_tail(&h4->txq, skb);
+	return 0;
 }
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
@@ -132,7 +129,7 @@
 		BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
 		hci_recv_frame(h4->rx_skb);
 	} else if (len > room) {
-		BT_ERR("Data length is to large");
+		BT_ERR("Data length is too large");
 		kfree_skb(h4->rx_skb);
 	} else {
 		h4->rx_state = H4_W4_DATA;
@@ -147,16 +144,17 @@
 }
 
 /* Recv data */
-static int h4_recv(struct n_hci *n_hci, void *data, int count)
+static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
-	struct h4_struct *h4 = n_hci->priv;
+	struct h4_struct *h4 = hu->priv;
 	register char *ptr;
 	hci_event_hdr *eh;
 	hci_acl_hdr   *ah;
 	hci_sco_hdr   *sh;
 	register int len, type, dlen;
 
-	BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+			hu, count, h4->rx_state, h4->rx_count);
 
 	ptr = data;
 	while (count) {
@@ -204,7 +202,7 @@
 
 				h4_check_data_len(h4, sh->dlen);
 				continue;
-			};
+			}
 		}
 
 		/* H4_W4_PACKET_TYPE */
@@ -232,7 +230,7 @@
 
 		default:
 			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-			n_hci->hdev.stat.err_rx++;
+			hu->hdev.stat.err_rx++;
 			ptr++; count--;
 			continue;
 		};
@@ -246,20 +244,26 @@
 			h4->rx_count = 0;
 			return 0;
 		}
-		h4->rx_skb->dev = (void *) &n_hci->hdev;
+		h4->rx_skb->dev = (void *) &hu->hdev;
 		h4->rx_skb->pkt_type = type;
 	}
 	return count;
 }
 
+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
+{
+	struct h4_struct *h4 = hu->priv;
+	return skb_dequeue(&h4->txq);
+}
+
 static struct hci_uart_proto h4p = {
-	id:    HCI_UART_H4,
-	open:  h4_open,
-	close: h4_close,
-	send:  h4_send,
-	recv:  h4_recv,
-	preq:  h4_preq,
-	flush: h4_flush,
+	id:      HCI_UART_H4,
+	open:    h4_open,
+	close:   h4_close,
+	recv:    h4_recv,
+	enqueue: h4_enqueue,
+	dequeue: h4_dequeue,
+	flush:   h4_flush,
 };
 	      
 int h4_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.h linux-2.4.21-rc3/drivers/bluetooth/hci_h4.h
--- linux-2.4.20/drivers/bluetooth/hci_h4.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_h4.h	2003-05-22 22:06:39.000000000 +0000
@@ -23,7 +23,7 @@
 */
 
 /*
- * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
 #ifdef __KERNEL__
@@ -31,6 +31,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
 };
 
 /* H4 receiver States */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_ldisc.c linux-2.4.21-rc3/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.20/drivers/bluetooth/hci_ldisc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_ldisc.c	2003-05-22 22:06:40.000000000 +0000
@@ -25,14 +25,15 @@
 /*
  * BlueZ HCI UART driver.
  *
- * $Id: hci_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $    
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -87,16 +88,86 @@
 	return 0;
 }
 
-static struct hci_uart_proto *n_hci_get_proto(unsigned int id)
+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
 {
 	if (id >= HCI_UART_MAX_PROTO)
 		return NULL;
 	return hup[id];
 }
 
+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
+{
+	struct hci_dev *hdev = &hu->hdev;
+	
+	/* Update HCI stat counters */
+	switch (pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	}
+}
+
+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
+{
+	struct sk_buff *skb = hu->tx_skb;
+	if (!skb)
+		skb = hu->proto->dequeue(hu);
+	else
+		hu->tx_skb = NULL;
+	return skb;
+}
+
+int hci_uart_tx_wakeup(struct hci_uart *hu)
+{
+	struct tty_struct *tty = hu->tty;
+	struct hci_dev *hdev = &hu->hdev;
+	struct sk_buff *skb;
+	
+	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
+		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+		return 0;
+	}
+
+	BT_DBG("");
+
+restart:
+	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+
+	while ((skb = hci_uart_dequeue(hu))) {
+		int len;
+	
+		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+		len = tty->driver.write(tty, 0, skb->data, skb->len);
+		hdev->stat.byte_tx += len;
+
+		skb_pull(skb, len);
+		if (skb->len) {
+			hu->tx_skb = skb;
+			break;
+		}
+	
+		hci_uart_tx_complete(hu, skb->pkt_type);
+		kfree_skb(skb);
+	} 
+	
+	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
+		goto restart;
+
+	clear_bit(HCI_UART_SENDING, &hu->tx_state);
+	return 0;
+}
+
 /* ------- Interface to HCI layer ------ */
 /* Initialize device */
-static int n_hci_open(struct hci_dev *hdev)
+static int hci_uart_open(struct hci_dev *hdev)
 {
 	BT_DBG("%s %p", hdev->name, hdev);
 
@@ -107,15 +178,16 @@
 }
 
 /* Reset device */
-static int n_hci_flush(struct hci_dev *hdev)
+static int hci_uart_flush(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
-	struct tty_struct *tty = n_hci->tty;
+	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+	struct tty_struct *tty = hu->tty;
 
 	BT_DBG("hdev %p tty %p", hdev, tty);
 
-	/* Drop TX queue */
-	skb_queue_purge(&n_hci->txq);
+	if (hu->tx_skb) {
+		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
+	}
 
 	/* Flush any pending characters in the driver and discipline. */
 	if (tty->ldisc.flush_buffer)
@@ -124,80 +196,30 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 
-	if (n_hci->proto->flush)
-		n_hci->proto->flush(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hu->proto->flush(hu);
 
 	return 0;
 }
 
 /* Close device */
-static int n_hci_close(struct hci_dev *hdev)
+static int hci_uart_close(struct hci_dev *hdev)
 {
 	BT_DBG("hdev %p", hdev);
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
-	n_hci_flush(hdev);
-	return 0;
-}
-
-static int n_hci_tx_wakeup(struct n_hci *n_hci)
-{
-	struct hci_dev *hdev = &n_hci->hdev;
-	
-	if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) {
-		set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-		return 0;
-	}
-
-	BT_DBG("");
-	do {
-		register struct sk_buff *skb;
-		register int len;
-
-		clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-
-		if (!(skb = skb_dequeue(&n_hci->txq)))
-			break;
-
-		len = n_hci->proto->send(n_hci, skb->data, skb->len);
-		n_hci->hdev.stat.byte_tx += len;
-
-		if (len == skb->len) {
-			/* Complete frame was sent */
-
-			switch (skb->pkt_type) {
-			case HCI_COMMAND_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-
-			case HCI_ACLDATA_PKT:
-				hdev->stat.acl_tx++;
-				break;
-
-			case HCI_SCODATA_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-			};
-
-			kfree_skb(skb);
-		} else {
-			/* Subtract sent part and requeue  */
-			skb_pull(skb, len);
-			skb_queue_head(&n_hci->txq, skb);
-		}
-	} while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state));
-	clear_bit(N_HCI_SENDING, &n_hci->tx_state);
+	hci_uart_flush(hdev);
 	return 0;
 }
 
 /* Send frames from HCI layer */
-static int n_hci_send_frame(struct sk_buff *skb)
+static int hci_uart_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
 	struct tty_struct *tty;
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) {
 		BT_ERR("Frame for uknown device (hdev=NULL)");
@@ -207,66 +229,60 @@
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	tty = n_hci->tty;
+	hu = (struct hci_uart *) hdev->driver_data;
+	tty = hu->tty;
 
 	BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	if (n_hci->proto->preq) {
-		skb = n_hci->proto->preq(n_hci, skb);
-		if (!skb)
-			return 0;
-	}
-	
-	skb_queue_tail(&n_hci->txq, skb);
-	n_hci_tx_wakeup(n_hci);
+	hu->proto->enqueue(hu, skb);
+
+	hci_uart_tx_wakeup(hu);
 	return 0;
 }
 
-static void n_hci_destruct(struct hci_dev *hdev)
+static void hci_uart_destruct(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) return;
 
 	BT_DBG("%s", hdev->name);
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	kfree(n_hci);
+	hu = (struct hci_uart *) hdev->driver_data;
+	kfree(hu);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /* ------ LDISC part ------ */
-/* n_hci_tty_open
+/* hci_uart_tty_open
  * 
- *     Called when line discipline changed to N_HCI.
+ *     Called when line discipline changed to HCI_UART.
  *
  * Arguments:
  *     tty    pointer to tty info structure
  * Return Value:    
  *     0 if success, otherwise error code
  */
-static int n_hci_tty_open(struct tty_struct *tty)
+static int hci_uart_tty_open(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *) tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
-	if (n_hci)
+	if (hu)
 		return -EEXIST;
 
-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+	if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
 		BT_ERR("Can't allocate controll structure");
 		return -ENFILE;
 	}
-	memset(n_hci, 0, sizeof(struct n_hci));
+	memset(hu, 0, sizeof(struct hci_uart));
 
-	tty->disc_data = n_hci;
-	n_hci->tty = tty;
+	tty->disc_data = hu;
+	hu->tty = tty;
 
-	spin_lock_init(&n_hci->rx_lock);
-	skb_queue_head_init(&n_hci->txq);
+	spin_lock_init(&hu->rx_lock);
 
 	/* Flush any pending characters in the driver and line discipline */
 	if (tty->ldisc.flush_buffer)
@@ -279,34 +295,34 @@
 	return 0;
 }
 
-/* n_hci_tty_close()
+/* hci_uart_tty_close()
  *
  *    Called when the line discipline is changed to something
  *    else, the tty is closed, or the tty detects a hangup.
  */
-static void n_hci_tty_close(struct tty_struct *tty)
+static void hci_uart_tty_close(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
 	/* Detach from the tty */
 	tty->disc_data = NULL;
 
-	if (n_hci) {
-		struct hci_dev *hdev = &n_hci->hdev;
-		n_hci_close(hdev);
+	if (hu) {
+		struct hci_dev *hdev = &hu->hdev;
+		hci_uart_close(hdev);
 
-		if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			n_hci->proto->close(n_hci);
+		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			hu->proto->close(hu);
 			hci_unregister_dev(hdev);
 		}
-				
+
 		MOD_DEC_USE_COUNT;
 	}
 }
 
-/* n_hci_tty_wakeup()
+/* hci_uart_tty_wakeup()
  *
  *    Callback for transmit wakeup. Called when low level
  *    device driver can accept more send data.
@@ -314,24 +330,25 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    None
  */
-static void n_hci_tty_wakeup( struct tty_struct *tty )
+static void hci_uart_tty_wakeup(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("");
 
-	if (!n_hci)
+	if (!hu)
 		return;
 
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
-	if (tty != n_hci->tty)
+	if (tty != hu->tty)
 		return;
 
-	n_hci_tx_wakeup(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hci_uart_tx_wakeup(hu);
 }
 
-/* n_hci_tty_room()
+/* hci_uart_tty_room()
  * 
  *    Callback function from tty driver. Return the amount of 
  *    space left in the receiver's buffer to decide if remote
@@ -340,12 +357,12 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    number of bytes left in receive buffer
  */
-static int n_hci_tty_room (struct tty_struct *tty)
+static int hci_uart_tty_room (struct tty_struct *tty)
 {
 	return 65536;
 }
 
-/* n_hci_tty_receive()
+/* hci_uart_tty_receive()
  * 
  *     Called by tty low level driver when receive data is
  *     available.
@@ -357,42 +374,42 @@
  *     
  * Return Value:    None
  */
-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	
-	if (!n_hci || tty != n_hci->tty)
+	if (!hu || tty != hu->tty)
 		return;
 
-	if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags))
+	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
 		return;
 	
-	spin_lock(&n_hci->rx_lock);
-	n_hci->proto->recv(n_hci, (void *) data, count);
-	n_hci->hdev.stat.byte_rx += count;
-	spin_unlock(&n_hci->rx_lock);
+	spin_lock(&hu->rx_lock);
+	hu->proto->recv(hu, (void *) data, count);
+	hu->hdev.stat.byte_rx += count;
+	spin_unlock(&hu->rx_lock);
 
 	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
 }
 
-static int n_hci_register_dev(struct n_hci *n_hci)
+static int hci_uart_register_dev(struct hci_uart *hu)
 {
 	struct hci_dev *hdev;
 
 	BT_DBG("");
 
 	/* Initialize and register HCI device */
-	hdev = &n_hci->hdev;
+	hdev = &hu->hdev;
 
 	hdev->type = HCI_UART;
-	hdev->driver_data = n_hci;
+	hdev->driver_data = hu;
 
-	hdev->open  = n_hci_open;
-	hdev->close = n_hci_close;
-	hdev->flush = n_hci_flush;
-	hdev->send  = n_hci_send_frame;
-	hdev->destruct = n_hci_destruct;
+	hdev->open  = hci_uart_open;
+	hdev->close = hci_uart_close;
+	hdev->flush = hci_uart_flush;
+	hdev->send  = hci_uart_send_frame;
+	hdev->destruct = hci_uart_destruct;
 
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device %s", hdev->name);
@@ -402,30 +419,30 @@
 	return 0;
 }
 
-static int n_hci_set_proto(struct n_hci *n_hci, int id)
+static int hci_uart_set_proto(struct hci_uart *hu, int id)
 {
 	struct hci_uart_proto *p;
 	int err;	
 	
-	p = n_hci_get_proto(id);
+	p = hci_uart_get_proto(id);
 	if (!p)
 		return -EPROTONOSUPPORT;
 
-	err = p->open(n_hci);
+	err = p->open(hu);
 	if (err)
 		return err;
 
-	n_hci->proto = p;
+	hu->proto = p;
 
-	err = n_hci_register_dev(n_hci);
+	err = hci_uart_register_dev(hu);
 	if (err) {
-		p->close(n_hci);
+		p->close(hu);
 		return err;
 	}
 	return 0;
 }
 
-/* n_hci_tty_ioctl()
+/* hci_uart_tty_ioctl()
  *
  *    Process IOCTL system call for the tty device.
  *
@@ -438,24 +455,24 @@
  *
  * Return Value:    Command dependent
  */
-static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file,
+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                             unsigned int cmd, unsigned long arg)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	int err = 0;
 
 	BT_DBG("");
 
 	/* Verify the status of the device */
-	if (!n_hci)
+	if (!hu)
 		return -EBADF;
 
 	switch (cmd) {
 	case HCIUARTSETPROTO:
-		if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			err = n_hci_set_proto(n_hci, arg);
+		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			err = hci_uart_set_proto(hu, arg);
 			if (err) {
-				clear_bit(N_HCI_PROTO_SET, &n_hci->flags);
+				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 				return err;
 			}
 			tty->low_latency = 1;
@@ -463,8 +480,8 @@
 			return -EBUSY;
 
 	case HCIUARTGETPROTO:
-		if (test_bit(N_HCI_PROTO_SET, &n_hci->flags))
-			return n_hci->proto->id;
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			return hu->proto->id;
 		return -EUNATCH;
 		
 	default:
@@ -478,15 +495,15 @@
 /*
  * We don't provide read/write/poll interface for user space.
  */
-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
 {
 	return 0;
 }
-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
 {
 	return 0;
 }
-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
 {
 	return 0;
 }
@@ -495,10 +512,14 @@
 int h4_init(void);
 int h4_deinit(void);
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+int bcsp_init(void);
+int bcsp_deinit(void);
+#endif
 
-int __init n_hci_init(void)
+int __init hci_uart_init(void)
 {
-	static struct tty_ldisc n_hci_ldisc;
+	static struct tty_ldisc hci_uart_ldisc;
 	int err;
 
 	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
@@ -507,20 +528,20 @@
 
 	/* Register the tty discipline */
 
-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
-	n_hci_ldisc.name        = "n_hci";
-	n_hci_ldisc.open        = n_hci_tty_open;
-	n_hci_ldisc.close       = n_hci_tty_close;
-	n_hci_ldisc.read        = n_hci_tty_read;
-	n_hci_ldisc.write       = n_hci_tty_write;
-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
-	n_hci_ldisc.poll        = n_hci_tty_poll;
-	n_hci_ldisc.receive_room= n_hci_tty_room;
-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+	memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
+	hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
+	hci_uart_ldisc.name        = "n_hci";
+	hci_uart_ldisc.open        = hci_uart_tty_open;
+	hci_uart_ldisc.close       = hci_uart_tty_close;
+	hci_uart_ldisc.read        = hci_uart_tty_read;
+	hci_uart_ldisc.write       = hci_uart_tty_write;
+	hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
+	hci_uart_ldisc.poll        = hci_uart_tty_poll;
+	hci_uart_ldisc.receive_room= hci_uart_tty_room;
+	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
+	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
 
-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
 		BT_ERR("Can't register HCI line discipline (%d)", err);
 		return err;
 	}
@@ -528,25 +549,31 @@
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_init();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_init();
+#endif
 	
 	return 0;
 }
 
-void n_hci_cleanup(void)
+void hci_uart_cleanup(void)
 {
 	int err;
 
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_deinit();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	if ((err = tty_register_ldisc(N_HCI, NULL)))
 		BT_ERR("Can't unregister HCI line discipline (%d)", err);
 }
 
-module_init(n_hci_init);
-module_exit(n_hci_cleanup);
+module_init(hci_uart_init);
+module_exit(hci_uart_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_uart.h linux-2.4.21-rc3/drivers/bluetooth/hci_uart.h
--- linux-2.4.20/drivers/bluetooth/hci_uart.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_uart.h	2003-05-22 22:06:48.000000000 +0000
@@ -23,10 +23,10 @@
 */
 
 /*
- * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
-#ifndef N_HCI
+#ifndef N_HCI 
 #define N_HCI	15
 #endif
 
@@ -42,19 +42,19 @@
 #define HCI_UART_NCSP	2
 
 #ifdef __KERNEL__
-struct n_hci;
+struct hci_uart;
 
 struct hci_uart_proto {
 	unsigned int id;
-	int (*open)(struct n_hci *n_hci);
-	int (*recv)(struct n_hci *n_hci, void *data, int len);
-	int (*send)(struct n_hci *n_hci, void *data, int len);
-	int (*close)(struct n_hci *n_hci);
-	int (*flush)(struct n_hci *n_hci);
-	struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
+	int (*open)(struct hci_uart *hu);
+	int (*close)(struct hci_uart *hu);
+	int (*flush)(struct hci_uart *hu);
+	int (*recv)(struct hci_uart *hu, void *data, int len);
+	int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
+	struct sk_buff *(*dequeue)(struct hci_uart *hu);
 };
 
-struct n_hci {
+struct hci_uart {
 	struct tty_struct  *tty;
 	struct hci_dev     hdev;
 	unsigned long      flags;
@@ -62,19 +62,20 @@
 	struct hci_uart_proto *proto;
 	void               *priv;
 	
-	struct sk_buff_head txq;
-	unsigned long       tx_state;
-	spinlock_t          rx_lock;
+	struct sk_buff     *tx_skb;
+	unsigned long      tx_state;
+	spinlock_t         rx_lock;
 };
 
-/* N_HCI flag bits */
-#define N_HCI_PROTO_SET		0x00
+/* HCI_UART flag bits */
+#define HCI_UART_PROTO_SET		0
 
 /* TX states  */
-#define N_HCI_SENDING		1
-#define N_HCI_TX_WAKEUP		2
+#define HCI_UART_SENDING		1
+#define HCI_UART_TX_WAKEUP		2
 
 int hci_uart_register_proto(struct hci_uart_proto *p);
 int hci_uart_unregister_proto(struct hci_uart_proto *p);
+int hci_uart_tx_wakeup(struct hci_uart *hu);
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_usb.c linux-2.4.21-rc3/drivers/bluetooth/hci_usb.c
--- linux-2.4.20/drivers/bluetooth/hci_usb.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_usb.c	2003-05-22 22:06:41.000000000 +0000
@@ -1,9 +1,10 @@
 /* 
-   BlueZ - Bluetooth protocol stack for Linux
+   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
    Copyright (C) 2000-2001 Qualcomm Incorporated
-
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
+   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    published by the Free Software Foundation;
@@ -23,20 +24,17 @@
 */
 
 /*
- * BlueZ HCI USB driver.
  * Based on original USB Bluetooth driver for Linux kernel
  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
  *
  * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
  */
-#define VERSION "2.1"
+#define VERSION "2.4"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
-#define __KERNEL_SYSCALLS__
-
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -49,15 +47,13 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
-#include <linux/kmod.h>
 
 #include <linux/usb.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
-#include "hci_usb.h"
 
-#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)
+#include "hci_usb.h"
 
 #ifndef HCI_USB_DEBUG
 #undef  BT_DBG
@@ -80,6 +76,9 @@
 	/* Ericsson with non-standard id */
 	{ USB_DEVICE(0x0bdb, 0x1002) },
 
+	/* Bluetooth Ultraport Module from IBM */
+	{ USB_DEVICE(0x04bf, 0x030a) },
+
 	{ }	/* Terminating entry */
 };
 
@@ -92,109 +91,193 @@
 	{ }	/* Terminating entry */
 };
 
-static void hci_usb_interrupt(struct urb *urb);
+struct _urb *_urb_alloc(int isoc, int gfp)
+{
+	struct _urb *_urb = kmalloc(sizeof(struct _urb) +
+				sizeof(struct iso_packet_descriptor) * isoc, gfp);
+	if (_urb) {
+		memset(_urb, 0, sizeof(*_urb));
+		spin_lock_init(&_urb->urb.lock);
+	}
+	return _urb;
+}
+
+struct _urb *_urb_dequeue(struct _urb_queue *q)
+{
+	struct _urb *_urb = NULL;
+        unsigned long flags;
+        spin_lock_irqsave(&q->lock, flags);
+	{
+		struct list_head *head = &q->head;
+		struct list_head *next = head->next;
+		if (next != head) {
+			_urb = list_entry(next, struct _urb, list);
+			list_del(next); _urb->queue = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&q->lock, flags);
+	return _urb;
+}
+
 static void hci_usb_rx_complete(struct urb *urb);
 static void hci_usb_tx_complete(struct urb *urb);
 
-static struct urb *hci_usb_get_completed(struct hci_usb *husb)
+#define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
+#define __pending_q(husb, type)   (&husb->pending_q[type-1])
+#define __completed_q(husb, type) (&husb->completed_q[type-1])
+#define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
+#define __reassembly(husb, type)  (husb->reassembly[type-1])
+
+static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
 {
-	struct sk_buff *skb;
-	struct urb *urb = NULL;
+	return _urb_dequeue(__completed_q(husb, type)); 
+}
 
-	skb = skb_dequeue(&husb->completed_q);
-	if (skb) {
-		urb = ((struct hci_usb_scb *) skb->cb)->urb;
-		kfree_skb(skb);
-	}
+static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
+{
+	int offset = 0, i;
 
-	BT_DBG("%s urb %p", husb->hdev.name, urb);
-	return urb;
+	BT_DBG("len %d mtu %d", len, mtu);
+
+	for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
+		urb->iso_frame_desc[i].offset = offset;
+		urb->iso_frame_desc[i].length = mtu;
+		BT_DBG("desc %d offset %d len %d", i, offset, mtu);
+	}
+	if (len && i < HCI_MAX_ISOC_FRAMES) {
+		urb->iso_frame_desc[i].offset = offset;
+		urb->iso_frame_desc[i].length = len;
+		BT_DBG("desc %d offset %d len %d", i, offset, len);
+		i++;
+	}
+	urb->number_of_packets = i;
 }
 
-static int hci_usb_enable_intr(struct hci_usb *husb)
+static int hci_usb_intr_rx_submit(struct hci_usb *husb)
 {
+	struct _urb *_urb;
 	struct urb *urb;
-	int pipe, size;
+	int err, pipe, interval, size;
 	void *buf;
 
 	BT_DBG("%s", husb->hdev.name);
 
- 	if (!(urb = usb_alloc_urb(0)))
+        size = husb->intr_in_ep->wMaxPacketSize;
+
+	buf = kmalloc(size, GFP_ATOMIC);
+	if (!buf)
 		return -ENOMEM;
 
-	if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) {
-		usb_free_urb(urb);
+	_urb = _urb_alloc(0, GFP_ATOMIC);
+	if (!_urb) {
+		kfree(buf);
 		return -ENOMEM;
 	}
+	_urb->type = HCI_EVENT_PKT;
+	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
 
-	husb->intr_urb = urb;
+	urb = &_urb->urb;
+	pipe     = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
+	interval = husb->intr_in_ep->bInterval;
+	FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
 	
-        pipe = usb_rcvintpipe(husb->udev, husb->intr_ep);
-        size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe));
-	FILL_INT_URB(urb, husb->udev, pipe, buf, size, 
-			hci_usb_interrupt, husb, husb->intr_interval);
-	
-	return usb_submit_urb(urb);
+	err = usb_submit_urb(urb);
+	if (err) {
+		BT_ERR("%s intr rx submit failed urb %p err %d",
+				husb->hdev.name, urb, err);
+		_urb_unlink(_urb);
+		_urb_free(_urb);
+		kfree(buf);
+	}
+	return err;
 }
 
-static int hci_usb_disable_intr(struct hci_usb *husb)
+static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
 {
-	struct urb *urb = husb->intr_urb;
-	struct sk_buff *skb;
-
-	BT_DBG("%s", husb->hdev.name);
+	struct _urb *_urb;
+	struct urb *urb;
+	int err, pipe, size = HCI_MAX_FRAME_SIZE;
+	void *buf;
 
-	usb_unlink_urb(urb); usb_free_urb(urb);
-	husb->intr_urb = NULL;
+	buf = kmalloc(size, GFP_ATOMIC);
+	if (!buf)
+		return -ENOMEM;
 
-	skb = husb->intr_skb;
-	if (skb) {
-		husb->intr_skb = NULL;
-		kfree_skb(skb);
+	_urb = _urb_alloc(0, GFP_ATOMIC);
+	if (!_urb) {
+		kfree(buf);
+		return -ENOMEM;
 	}
+	_urb->type = HCI_ACLDATA_PKT;
+	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
 
-	return 0;
+	urb  = &_urb->urb;
+	pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
+        FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
+        urb->transfer_flags = USB_QUEUE_BULK;
+
+	BT_DBG("%s urb %p", husb->hdev.name, urb);
+
+	err = usb_submit_urb(urb);
+	if (err) {
+		BT_ERR("%s bulk rx submit failed urb %p err %d",
+				husb->hdev.name, urb, err);
+		_urb_unlink(_urb);
+		_urb_free(_urb);
+		kfree(buf);
+	}
+	return err;
 }
 
-static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb)
+#ifdef CONFIG_BLUEZ_USB_SCO
+static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
 {
-	struct hci_usb_scb *scb;
-	struct sk_buff *skb;
-	int    pipe, size, err;
+	struct _urb *_urb;
+	struct urb *urb;
+	int err, mtu, size;
+	void *buf;
 
-	if (!urb && !(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
+	mtu  = husb->isoc_in_ep->wMaxPacketSize;
+        size = mtu * HCI_MAX_ISOC_FRAMES;
 
-        size = HCI_MAX_FRAME_SIZE;
+	buf = kmalloc(size, GFP_ATOMIC);
+	if (!buf)
+		return -ENOMEM;
 
-	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
-		usb_free_urb(urb);
+	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
+	if (!_urb) {
+		kfree(buf);
 		return -ENOMEM;
 	}
-	
-	BT_DBG("%s urb %p", husb->hdev.name, urb);
+	_urb->type = HCI_SCODATA_PKT;
+	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
 
-	skb->dev = (void *) &husb->hdev;
-	skb->pkt_type = HCI_ACLDATA_PKT;
+	urb = &_urb->urb;
 
-	scb = (struct hci_usb_scb *) skb->cb;
-	scb->urb = urb;
+	urb->context  = husb;
+	urb->dev      = husb->udev;
+	urb->pipe     = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
+	urb->complete = hci_usb_rx_complete;
 
-        pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep);
+	urb->transfer_buffer_length = size;
+	urb->transfer_buffer = buf;
+	urb->transfer_flags  = USB_ISO_ASAP;
 
-        FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb);
-        urb->transfer_flags = USB_QUEUE_BULK;
+	__fill_isoc_desc(urb, size, mtu);
+
+	BT_DBG("%s urb %p", husb->hdev.name, urb);
 
-	skb_queue_tail(&husb->pending_q, skb);
 	err = usb_submit_urb(urb);
 	if (err) {
-		BT_ERR("%s bulk rx submit failed urb %p err %d",
+		BT_ERR("%s isoc rx submit failed urb %p err %d",
 				husb->hdev.name, urb, err);
-		skb_unlink(skb);
-		usb_free_urb(urb);
+		_urb_unlink(_urb);
+		_urb_free(_urb);
+		kfree(buf);
 	}
 	return err;
 }
+#endif
 
 /* Initialize device */
 static int hci_usb_open(struct hci_dev *hdev)
@@ -212,10 +295,14 @@
 
 	write_lock_irqsave(&husb->completion_lock, flags);
 
-	err = hci_usb_enable_intr(husb);
+	err = hci_usb_intr_rx_submit(husb);
 	if (!err) {
-		for (i = 0; i < HCI_MAX_BULK_TX; i++)
-			hci_usb_rx_submit(husb, NULL);
+		for (i = 0; i < HCI_MAX_BULK_RX; i++)
+			hci_usb_bulk_rx_submit(husb);
+
+#ifdef CONFIG_BLUEZ_USB_SCO
+		hci_usb_isoc_rx_submit(husb);
+#endif
 	} else {
 		clear_bit(HCI_RUNNING, &hdev->flags);
 		MOD_DEC_USE_COUNT;
@@ -229,29 +316,52 @@
 static int hci_usb_flush(struct hci_dev *hdev)
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+	int i;
 
 	BT_DBG("%s", hdev->name);
 
-	skb_queue_purge(&husb->cmd_q);
-	skb_queue_purge(&husb->acl_q);
+	for (i=0; i < 4; i++)
+		skb_queue_purge(&husb->transmit_q[i]);
 	return 0;
 }
 
-static inline void hci_usb_unlink_urbs(struct hci_usb *husb)
+static void hci_usb_unlink_urbs(struct hci_usb *husb)
 {
-	struct sk_buff *skb;
-	struct urb *urb;
+	int i;
 
 	BT_DBG("%s", husb->hdev.name);
 
-	while ((skb = skb_dequeue(&husb->pending_q))) {
-		urb = ((struct hci_usb_scb *) skb->cb)->urb;
-		usb_unlink_urb(urb);
-		kfree_skb(skb);
-	}
+	for (i=0; i < 4; i++) {
+		struct _urb *_urb;
+		struct urb *urb;
+
+		/* Kill pending requests */
+		while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
+			urb = &_urb->urb;
+			BT_DBG("%s unlinking _urb %p type %d urb %p", 
+					husb->hdev.name, _urb, _urb->type, urb);
+			usb_unlink_urb(urb);
+			_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
+		}
 
-	while ((urb = hci_usb_get_completed(husb)))
-		usb_free_urb(urb);
+		/* Release completed requests */
+		while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
+			urb = &_urb->urb;
+			BT_DBG("%s freeing _urb %p type %d urb %p",
+					husb->hdev.name, _urb, _urb->type, urb);
+			if (urb->setup_packet)
+				kfree(urb->setup_packet);
+			if (urb->transfer_buffer)
+				kfree(urb->transfer_buffer);
+			_urb_free(_urb);
+		}
+
+		/* Release reassembly buffers */
+		if (husb->reassembly[i]) {
+			kfree_skb(husb->reassembly[i]);
+			husb->reassembly[i] = NULL;
+		}
+	}
 }
 
 /* Close device */
@@ -267,7 +377,6 @@
 
 	write_lock_irqsave(&husb->completion_lock, flags);
 	
-	hci_usb_disable_intr(husb);
 	hci_usb_unlink_urbs(husb);
 	hci_usb_flush(hdev);
 
@@ -277,22 +386,45 @@
 	return 0;
 }
 
+static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
+{
+	struct urb *urb = &_urb->urb;
+	int err;
+
+	BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
+	
+	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
+	err = usb_submit_urb(urb);
+	if (err) {
+		BT_ERR("%s tx submit failed urb %p type %d err %d",
+				husb->hdev.name, urb, _urb->type, err);
+		_urb_unlink(_urb);
+		_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
+	} else
+		atomic_inc(__pending_tx(husb, _urb->type));
+
+	return err;
+}
+
 static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
-	struct hci_usb_scb *scb = (void *) skb->cb;
-	struct urb *urb = hci_usb_get_completed(husb);
+	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
 	struct usb_ctrlrequest *dr;
-	int pipe, err;
-
-	if (!urb && !(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
+	struct urb *urb;
 
-	if (!(dr = kmalloc(sizeof(*dr), GFP_ATOMIC))) {
-		usb_free_urb(urb);
-		return -ENOMEM;
-	}
-	
-	pipe = usb_sndctrlpipe(husb->udev, 0);
+	if (!_urb) {
+	       	_urb = _urb_alloc(0, GFP_ATOMIC);
+	       	if (!_urb)
+			return -ENOMEM;
+		_urb->type = skb->pkt_type;
+
+		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+		if (!dr) {
+			_urb_free(_urb);
+			return -ENOMEM;
+		}
+	} else
+		dr = (void *) _urb->urb.setup_packet;
 
 	dr->bRequestType = HCI_CTRL_REQ;
 	dr->bRequest = 0;
@@ -300,81 +432,111 @@
 	dr->wValue   = 0;
 	dr->wLength  = __cpu_to_le16(skb->len);
 
-	FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr,
-			skb->data, skb->len, hci_usb_tx_complete, skb);
-
-	BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);
-
-	scb->urb = urb;
+	urb = &_urb->urb;
+	FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
+		(void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
 
-	skb_queue_tail(&husb->pending_q, skb);
-	err = usb_submit_urb(urb);
-	if (err) {
-		BT_ERR("%s ctrl tx submit failed urb %p err %d", 
-				husb->hdev.name, urb, err);
-		skb_unlink(skb);
-		usb_free_urb(urb); kfree(dr);
-	}
-	return err;
+	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+	
+	_urb->priv = skb;
+	return __tx_submit(husb, _urb);
 }
 
 static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
-	struct hci_usb_scb *scb = (void *) skb->cb;
-	struct urb *urb = hci_usb_get_completed(husb);
-	int pipe, err;
+	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+	struct urb *urb;
+	int pipe;
 
-	if (!urb && !(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
+	if (!_urb) {
+	       	_urb = _urb_alloc(0, GFP_ATOMIC);
+	       	if (!_urb)
+			return -ENOMEM;
+		_urb->type = skb->pkt_type;
+	}
 
-	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep);
-        
-	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-	              hci_usb_tx_complete, skb);
+	urb  = &_urb->urb;
+	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
+	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, 
+			hci_usb_tx_complete, husb);
 	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
 
-	BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);
+	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
 
-	scb->urb = urb;
+	_urb->priv = skb;
+	return __tx_submit(husb, _urb);
+}
 
-	skb_queue_tail(&husb->pending_q, skb);
-	err = usb_submit_urb(urb);
-	if (err) {
-		BT_ERR("%s bulk tx submit failed urb %p err %d", 
-				husb->hdev.name, urb, err);
-		skb_unlink(skb);
-		usb_free_urb(urb);
+#ifdef CONFIG_BLUEZ_USB_SCO
+static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
+{
+	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+	struct urb *urb;
+	
+	if (!_urb) {
+	       	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
+	       	if (!_urb)
+			return -ENOMEM;
+		_urb->type = skb->pkt_type;
 	}
-	return err;
+
+	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+
+	urb = &_urb->urb;
+	
+	urb->context  = husb;
+	urb->dev      = husb->udev;
+	urb->pipe     = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
+	urb->complete = hci_usb_tx_complete;
+	urb->transfer_flags = USB_ISO_ASAP;
+
+	urb->transfer_buffer = skb->data;
+	urb->transfer_buffer_length = skb->len;
+	
+	__fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
+
+	_urb->priv = skb;
+	return __tx_submit(husb, _urb);
 }
+#endif
 
 static void hci_usb_tx_process(struct hci_usb *husb)
 {
+	struct sk_buff_head *q;
 	struct sk_buff *skb;
 
 	BT_DBG("%s", husb->hdev.name);
 
 	do {
 		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
+
+		/* Process command queue */
+		q = __transmit_q(husb, HCI_COMMAND_PKT);
+		if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
+				(skb = skb_dequeue(q))) {
+			if (hci_usb_send_ctrl(husb, skb) < 0)
+				skb_queue_head(q, skb);
+		}
+
+#ifdef CONFIG_BLUEZ_USB_SCO
+		/* Process SCO queue */
+		q = __transmit_q(husb, HCI_SCODATA_PKT);
+		if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) &&
+				(skb = skb_dequeue(q))) {
+			if (hci_usb_send_isoc(husb, skb) < 0)
+				skb_queue_head(q, skb);
+		}
+#endif
 		
 		/* Process ACL queue */
-		while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING &&
-				(skb = skb_dequeue(&husb->acl_q))) {
+		q = __transmit_q(husb, HCI_ACLDATA_PKT);
+		while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
+				(skb = skb_dequeue(q))) {
 			if (hci_usb_send_bulk(husb, skb) < 0) {
-				skb_queue_head(&husb->acl_q, skb);
+				skb_queue_head(q, skb);
 				break;
 			}
 		}
-
-		/* Process command queue */
-		if (!test_bit(HCI_USB_CTRL_TX, &husb->state) &&
-			(skb = skb_dequeue(&husb->cmd_q)) != NULL) {
-			set_bit(HCI_USB_CTRL_TX, &husb->state);
-			if (hci_usb_send_ctrl(husb, skb) < 0) {
-				skb_queue_head(&husb->cmd_q, skb);
-				clear_bit(HCI_USB_CTRL_TX, &husb->state);
-			}
-		}
 	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
 }
 
@@ -389,7 +551,7 @@
 }
 
 /* Send frames from HCI layer */
-int hci_usb_send_frame(struct sk_buff *skb)
+static int hci_usb_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_usb *husb;
@@ -402,204 +564,207 @@
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
-	husb = (struct hci_usb *) hdev->driver_data;
-
 	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	read_lock(&husb->completion_lock);
+	husb = (struct hci_usb *) hdev->driver_data;
 
 	switch (skb->pkt_type) {
 	case HCI_COMMAND_PKT:
-		skb_queue_tail(&husb->cmd_q, skb);
 		hdev->stat.cmd_tx++;
 		break;
 
 	case HCI_ACLDATA_PKT:
-		skb_queue_tail(&husb->acl_q, skb);
 		hdev->stat.acl_tx++;
 		break;
 
+#ifdef CONFIG_BLUEZ_USB_SCO
 	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+#endif
+
 	default:
 		kfree_skb(skb);
-		break;
+		return 0;
 	}
+
+	read_lock(&husb->completion_lock);
+
+	skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
 	hci_usb_tx_wakeup(husb);
 
 	read_unlock(&husb->completion_lock);
 	return 0;
 }
 
-static void hci_usb_interrupt(struct urb *urb)
+static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
 {
-	struct hci_usb *husb = (void *) urb->context;
-	struct hci_usb_scb *scb;
-	struct sk_buff *skb;
-	hci_event_hdr *eh;
-	__u8 *data = urb->transfer_buffer;
-	int count = urb->actual_length;
-	int len = HCI_EVENT_HDR_SIZE;
-
-	BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count);
-
-	if (!test_bit(HCI_RUNNING, &husb->hdev.flags))
-		return;
-
-	if (urb->status || !count) {
-		BT_DBG("%s intr status %d, count %d", 
-				husb->hdev.name, urb->status, count);
-		return;
-	}
+	BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
 
-	read_lock(&husb->completion_lock);
-	
 	husb->hdev.stat.byte_rx += count;
 
-	if (!(skb = husb->intr_skb)) {
-		/* Start of the frame */
-		if (count < HCI_EVENT_HDR_SIZE)
-			goto bad_len;
+	while (count) {
+		struct sk_buff *skb = __reassembly(husb, type);
+		struct { int expect; } *scb;
+		int len = 0;
+	
+		if (!skb) {
+			/* Start of the frame */
 
-		eh  = (hci_event_hdr *) data;
-		len = eh->plen + HCI_EVENT_HDR_SIZE;
+			switch (type) {
+			case HCI_EVENT_PKT:
+				if (count >= HCI_EVENT_HDR_SIZE) {
+					hci_event_hdr *h = data;
+					len = HCI_EVENT_HDR_SIZE + h->plen;
+				} else
+					return -EILSEQ;
+				break;
 
-		if (count > len)
-			goto bad_len;
+			case HCI_ACLDATA_PKT:
+				if (count >= HCI_ACL_HDR_SIZE) {
+					hci_acl_hdr *h = data;
+					len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
+				} else
+					return -EILSEQ;
+				break;
+#ifdef CONFIG_BLUEZ_USB_SCO
+			case HCI_SCODATA_PKT:
+				if (count >= HCI_SCO_HDR_SIZE) {
+					hci_sco_hdr *h = data;
+					len = HCI_SCO_HDR_SIZE + h->dlen;
+				} else 
+					return -EILSEQ;
+				break;
+#endif
+			}
+			BT_DBG("new packet len %d", len);
+				
+			skb = bluez_skb_alloc(len, GFP_ATOMIC);
+			if (!skb) {
+				BT_ERR("%s no memory for the packet", husb->hdev.name);
+				return -ENOMEM;
+			}
+			skb->dev = (void *) &husb->hdev;
+			skb->pkt_type = type;
+	
+			__reassembly(husb, type) = skb;
 
-		skb = bluez_skb_alloc(len, GFP_ATOMIC);
-		if (!skb) {
-			BT_ERR("%s no memory for event packet", husb->hdev.name);
-			goto done;
+			scb = (void *) skb->cb;
+			scb->expect = len;
+		} else {
+			/* Continuation */
+			scb = (void *) skb->cb;
+			len = scb->expect;
 		}
-		scb = (void *) skb->cb;
 
-		skb->dev = (void *) &husb->hdev;
-		skb->pkt_type = HCI_EVENT_PKT;
+		len = min(len, count);
+		
+		memcpy(skb_put(skb, len), data, len);
 
-		husb->intr_skb = skb;
-		scb->intr_len  = len;
-	} else {
-		/* Continuation */
-		scb = (void *) skb->cb;
-		len = scb->intr_len;
-		if (count > len) {
-			husb->intr_skb = NULL;
-			kfree_skb(skb);
-			goto bad_len;
+		scb->expect -= len;
+		if (!scb->expect) {
+			/* Complete frame */
+			__reassembly(husb, type) = NULL;
+			hci_recv_frame(skb);
 		}
-	}
 
-	memcpy(skb_put(skb, count), data, count);
-	scb->intr_len -= count;
-
-	if (!scb->intr_len) {
-		/* Complete frame */
-		husb->intr_skb = NULL;
-		hci_recv_frame(skb);
+		count -= len; data += len;
 	}
-
-done:
-	read_unlock(&husb->completion_lock);
-	return;
-
-bad_len:
-	BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len);
-	husb->hdev.stat.err_rx++;
-	read_unlock(&husb->completion_lock);
+	return 0;
 }
 
-static void hci_usb_tx_complete(struct urb *urb)
+static void hci_usb_rx_complete(struct urb *urb)
 {
-	struct sk_buff *skb  = (struct sk_buff *) urb->context;
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+	struct _urb *_urb = container_of(urb, struct _urb, urb);
+	struct hci_usb *husb = (void *) urb->context;
+	struct hci_dev *hdev = &husb->hdev;
+	int    err, count = urb->actual_length;
 
-	BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb,
-			urb->status, urb->transfer_flags);
-
-	if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) {
-		kfree(urb->setup_packet);
-		clear_bit(HCI_USB_CTRL_TX, &husb->state);
-	}
+	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
+			_urb->type, urb->status, count, urb->transfer_flags);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
 
 	read_lock(&husb->completion_lock);
-	
-	if (!urb->status)
-		husb->hdev.stat.byte_tx += skb->len;
-	else
-		husb->hdev.stat.err_tx++;
 
-	skb_unlink(skb);
-	skb_queue_tail(&husb->completed_q, skb);
-	hci_usb_tx_wakeup(husb);
-	
+	if (urb->status || !count)
+		goto resubmit;
+
+	if (_urb->type == HCI_SCODATA_PKT) {
+#ifdef CONFIG_BLUEZ_USB_SCO
+		int i;
+		for (i=0; i < urb->number_of_packets; i++) {
+			BT_DBG("desc %d status %d offset %d len %d", i,
+					urb->iso_frame_desc[i].status,
+					urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+	
+			if (!urb->iso_frame_desc[i].status)
+				__recv_frame(husb, _urb->type, 
+					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+		}
+#else
+		;
+#endif
+	} else {
+		err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
+		if (err < 0) { 
+			BT_ERR("%s corrupted packet: type %d count %d",
+					husb->hdev.name, _urb->type, count);
+			hdev->stat.err_rx++;
+		}
+	}
+
+resubmit:
+	if (_urb->type != HCI_EVENT_PKT) {
+		urb->dev = husb->udev;
+		err      = usb_submit_urb(urb);
+		BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
+				_urb->type, err);
+	}
 	read_unlock(&husb->completion_lock);
-	return;
 }
 
-static void hci_usb_rx_complete(struct urb *urb)
+static void hci_usb_tx_complete(struct urb *urb)
 {
-	struct sk_buff *skb  = (struct sk_buff *) urb->context;
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	int status, count = urb->actual_length;
-	hci_acl_hdr *ah;
-	int dlen, size;
+	struct _urb *_urb = container_of(urb, struct _urb, urb);
+	struct hci_usb *husb = (void *) urb->context;
+	struct hci_dev *hdev = &husb->hdev;
 
-	BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb,
-			urb->status, count, urb->transfer_flags);
+	BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
+			urb->status, urb->transfer_flags);
 
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return;
+	atomic_dec(__pending_tx(husb, _urb->type));
 
-	read_lock(&husb->completion_lock);
+	urb->transfer_buffer = NULL;
+	kfree_skb((struct sk_buff *) _urb->priv);
 
-	if (urb->status || !count)
-		goto resubmit;
-
-	husb->hdev.stat.byte_rx += count;
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return;
 
-	ah   = (hci_acl_hdr *) skb->data;
-	dlen = __le16_to_cpu(ah->dlen);
-	size = HCI_ACL_HDR_SIZE + dlen;
-
-	/* Verify frame len and completeness */
-	if (count != size) {
-		BT_ERR("%s corrupted ACL packet: count %d, dlen %d",
-				husb->hdev.name, count, dlen);
-		bluez_dump("hci_usb", skb->data, count);
-		husb->hdev.stat.err_rx++;
-		goto resubmit;
-	}
+	if (!urb->status)
+		hdev->stat.byte_tx += urb->transfer_buffer_length;
+	else
+		hdev->stat.err_tx++;
 
-	skb_unlink(skb);
-	skb_put(skb, count);
-	hci_recv_frame(skb);
+	read_lock(&husb->completion_lock);
 
-	hci_usb_rx_submit(husb, urb);
+	_urb_unlink(_urb);
+	_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
 
-	read_unlock(&husb->completion_lock);
-	return;
-		
-resubmit:
-	urb->dev = husb->udev;
-	status   = usb_submit_urb(urb);
-	BT_DBG("%s URB resubmit status %d", husb->hdev.name, status);
+	hci_usb_tx_wakeup(husb);
+	
 	read_unlock(&husb->completion_lock);
 }
 
 static void hci_usb_destruct(struct hci_dev *hdev)
 {
-	struct hci_usb *husb;
-
-	if (!hdev) return;
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
 
 	BT_DBG("%s", hdev->name);
 
-	husb = (struct hci_usb *) hdev->driver_data;
 	kfree(husb);
 }
 
@@ -662,6 +827,7 @@
 						bulk_out_ep[i] = ep;
 					break;
 
+#ifdef CONFIG_BLUEZ_USB_SCO
 				case USB_ENDPOINT_XFER_ISOC:
 					if (ep->wMaxPacketSize < size)
 						break;
@@ -676,6 +842,7 @@
 					else
 						isoc_out_ep[i] = ep;
 					break;
+#endif
 				}
 			}
 		}
@@ -686,10 +853,12 @@
 		goto done;
 	}
 
+#ifdef CONFIG_BLUEZ_USB_SCO
 	if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
 		BT_DBG("Isoc endpoints not found");
 		isoc_iface = NULL;
 	}
+#endif
 
 	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
 		BT_ERR("Can't allocate: control structure");
@@ -699,35 +868,36 @@
 	memset(husb, 0, sizeof(struct hci_usb));
 
 	husb->udev = udev;
-	husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress;
-	husb->bulk_in_ep  = bulk_in_ep[0]->bEndpointAddress;
-
-	husb->intr_ep = intr_in_ep[0]->bEndpointAddress;
-	husb->intr_interval = intr_in_ep[0]->bInterval;
+	husb->bulk_out_ep = bulk_out_ep[0];
+	husb->bulk_in_ep  = bulk_in_ep[0];
+	husb->intr_in_ep  = intr_in_ep[0];
 
+#ifdef CONFIG_BLUEZ_USB_SCO
 	if (isoc_iface) {
+		BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
 		if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
 			BT_ERR("Can't set isoc interface settings");
 			isoc_iface = NULL;
 		}
 		usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
 		husb->isoc_iface  = isoc_iface;
-
-		husb->isoc_in_ep  = isoc_in_ep[1]->bEndpointAddress;
-		husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress;
+		husb->isoc_in_ep  = isoc_in_ep[isoc_ifnum];
+		husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
 	}
-
-	husb->completion_lock = RW_LOCK_UNLOCKED;
+#endif
 	
-	skb_queue_head_init(&husb->acl_q);
-	skb_queue_head_init(&husb->cmd_q);
-	skb_queue_head_init(&husb->pending_q);
-	skb_queue_head_init(&husb->completed_q);
+	husb->completion_lock = RW_LOCK_UNLOCKED;
+
+	for (i = 0; i < 4; i++) {	
+		skb_queue_head_init(&husb->transmit_q[i]);
+		_urb_queue_init(&husb->pending_q[i]);
+		_urb_queue_init(&husb->completed_q[i]);
+	}
 
 	/* Initialize and register HCI device */
 	hdev = &husb->hdev;
 
-	hdev->type = HCI_USB;
+	hdev->type  = HCI_USB;
 	hdev->driver_data = husb;
 
 	hdev->open  = hci_usb_open;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_usb.h linux-2.4.21-rc3/drivers/bluetooth/hci_usb.h
--- linux-2.4.20/drivers/bluetooth/hci_usb.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/bluetooth/hci_usb.h	2003-05-22 22:06:48.000000000 +0000
@@ -1,9 +1,10 @@
 /* 
-   BlueZ - Bluetooth protocol stack for Linux
+   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
    Copyright (C) 2000-2001 Qualcomm Incorporated
-
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
+   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    published by the Free Software Foundation;
@@ -40,40 +41,96 @@
 #define HCI_MAX_BULK_TX     	4
 #define HCI_MAX_BULK_RX     	1
 
+#define HCI_MAX_ISOC_FRAMES     10
+
+struct _urb_queue {
+	struct list_head head;
+	spinlock_t       lock;
+};
+
+struct _urb {
+	struct list_head  list;
+	struct _urb_queue *queue;
+	int               type;
+	void              *priv;
+	struct urb        urb;
+};
+
+struct _urb *_urb_alloc(int isoc, int gfp);
+
+static inline void _urb_free(struct _urb *_urb)
+{
+	kfree(_urb);
+}
+
+static inline void _urb_queue_init(struct _urb_queue *q)
+{
+	INIT_LIST_HEAD(&q->head);
+	spin_lock_init(&q->lock);
+}
+
+static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
+{
+        unsigned long flags;
+        spin_lock_irqsave(&q->lock, flags);
+	list_add(&_urb->list, &q->head); _urb->queue = q;
+	spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
+{
+        unsigned long flags;
+        spin_lock_irqsave(&q->lock, flags);
+	list_add_tail(&_urb->list, &q->head); _urb->queue = q;
+	spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline void _urb_unlink(struct _urb *_urb)
+{
+	struct _urb_queue *q = _urb->queue;
+        unsigned long flags;
+	if (q) {
+        	spin_lock_irqsave(&q->lock, flags);
+		list_del(&_urb->list); _urb->queue = NULL;
+		spin_unlock_irqrestore(&q->lock, flags);
+	}
+}
+
+struct _urb *_urb_dequeue(struct _urb_queue *q);
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+		        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+			        (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
 struct hci_usb {
 	struct hci_dev		hdev;
 
 	unsigned long		state;
 	
 	struct usb_device 	*udev;
-	struct usb_interface    *isoc_iface;
 	
-	__u8			bulk_out_ep;
-	__u8			bulk_in_ep;
-	__u8			isoc_out_ep;
-	__u8			isoc_in_ep;
-
-	__u8			intr_ep;
-	__u8			intr_interval;
-	struct urb		*intr_urb;
-	struct sk_buff *	intr_skb;
+	struct usb_endpoint_descriptor	*bulk_in_ep;
+	struct usb_endpoint_descriptor	*bulk_out_ep;
+	struct usb_endpoint_descriptor	*intr_in_ep;
+
+	struct usb_interface            *isoc_iface;
+	struct usb_endpoint_descriptor	*isoc_out_ep;
+	struct usb_endpoint_descriptor	*isoc_in_ep;
+
+	struct sk_buff_head	transmit_q[4];
+	struct sk_buff		*reassembly[4]; // Reassembly buffers
 
 	rwlock_t		completion_lock;
-	
-	struct sk_buff_head	cmd_q;	     // TX Commands
-	struct sk_buff_head	acl_q;	     // TX ACLs
-	struct sk_buff_head	pending_q;   // Pending requests
-	struct sk_buff_head	completed_q; // Completed requests
-};
 
-struct hci_usb_scb {
-	struct urb *urb;
-	int    intr_len;
+	atomic_t		pending_tx[4];  // Number of pending requests 
+	struct _urb_queue	pending_q[4];   // Pending requests
+	struct _urb_queue	completed_q[4]; // Completed requests
 };
 
 /* States  */
 #define HCI_USB_TX_PROCESS	1
 #define HCI_USB_TX_WAKEUP	2
-#define HCI_USB_CTRL_TX		3
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/cdrom/cdu31a.c linux-2.4.21-rc3/drivers/cdrom/cdu31a.c
--- linux-2.4.20/drivers/cdrom/cdu31a.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/cdrom/cdu31a.c	2003-05-22 22:06:27.000000000 +0000
@@ -1361,6 +1361,8 @@
 	res_reg[0] = 0;
 	res_reg[1] = 0;
 	*res_size = 0;
+	/* Make sure that bytesleft doesn't exceed the buffer size */
+	if (nblocks > 4) nblocks = 4;
 	bytesleft = nblocks * 512;
 	offset = 0;
 
@@ -1384,9 +1386,9 @@
 			       readahead_buffer + (2048 -
 						   readahead_dataleft),
 			       readahead_dataleft);
-			readahead_dataleft = 0;
 			bytesleft -= readahead_dataleft;
 			offset += readahead_dataleft;
+			readahead_dataleft = 0;
 		} else {
 			/* The readahead will fill the whole buffer, get the data
 			   and return. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Config.in linux-2.4.21-rc3/drivers/char/Config.in
--- linux-2.4.20/drivers/char/Config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/Config.in	2003-05-22 22:06:38.000000000 +0000
@@ -73,6 +73,14 @@
      tristate '    Stallion EasyIO or EC8/32 support' CONFIG_STALLION
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+     if [ "$CONFIG_PDC_CONSOLE" != "y" ]; then
+       bool '  Serial MUX support' CONFIG_SERIAL_MUX CONFIG_SERIAL_NONSTANDARD
+     fi
+     if [ "$CONFIG_SERIAL_MUX" != "y" ]; then
+       bool '  PDC software console support' CONFIG_PDC_CONSOLE CONFIG_SERIAL_NONSTANDARD
+     fi
+   fi
    if [ "$CONFIG_MIPS" = "y" ]; then
      bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
      dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
@@ -147,6 +155,7 @@
       bool '  Support for console on line printer' CONFIG_LP_CONSOLE
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+   dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
 fi
 
 if [ "$CONFIG_PPC64" ] ; then 
@@ -190,6 +199,12 @@
    fi
 fi
 
+tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER
+dep_mbool '  Generate a panic event to all BMCs on a panic' CONFIG_IPMI_PANIC_EVENT $CONFIG_IPMI_HANDLER
+dep_tristate '  Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
+
 mainmenu_option next_comment
 comment 'Watchdog Cards'
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
@@ -197,6 +212,7 @@
    bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
    tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
    tristate '  Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
+   tristate '  ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT
    tristate '  ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT
    tristate '  AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT
    tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
@@ -216,6 +232,7 @@
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    dep_tristate '  SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
+   tristate '  NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
    tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG
    tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  WDT Watchdog timer' CONFIG_WDT
@@ -239,9 +256,10 @@
    fi
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
+dep_tristate 'NatSemi SCx200 GPIO Support' CONFIG_SCx200_GPIO $CONFIG_SCx200
 
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then
-   dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
+   dep_tristate 'AMD 768/8111 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
 fi
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
    dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Makefile linux-2.4.21-rc3/drivers/char/Makefile
--- linux-2.4.20/drivers/char/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/Makefile	2003-05-22 22:06:52.000000000 +0000
@@ -24,7 +24,7 @@
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
-			au1000_gpio.o hp_psaux.o nvram.o
+			au1000_gpio.o hp_psaux.o nvram.o scx200.o
 
 mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
 
@@ -66,6 +66,20 @@
    SERIAL   =
 endif
 
+ifeq ($(ARCH),parisc)
+   ifdef CONFIG_GSC_PS2
+      KEYBD   = hp_psaux.o hp_keyb.o
+   else
+      KEYBD   =
+   endif
+   ifdef CONFIG_SERIAL_MUX
+      CONSOLE += mux.o
+   endif
+   ifdef CONFIG_PDC_CONSOLE
+      CONSOLE += pdc_console.o
+   endif
+endif
+
 ifdef CONFIG_Q40
   KEYBD += q40_keyb.o
   SERIAL = serial.o
@@ -204,6 +218,7 @@
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
+obj-$(CONFIG_TIPAR) += tipar.o
 
 ifeq ($(CONFIG_INPUT),y)
 obj-y += joystick/js.o
@@ -222,6 +237,7 @@
 obj-$(CONFIG_PC110_PAD) += pc110pad.o
 obj-$(CONFIG_MK712_MOUSE) += mk712.o
 obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
@@ -254,6 +270,7 @@
 obj-$(CONFIG_DZ) += dz.o
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o scx200.o
 
 # Only one watchdog can succeed. We probe the hardware watchdog
 # drivers first, then the softdog driver.  This means if your hardware
@@ -277,9 +294,10 @@
 obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
 obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
-#obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
+obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
@@ -289,6 +307,11 @@
   obj-y += mwave/mwave.o
 endif
 
+subdir-$(CONFIG_IPMI_HANDLER) += ipmi
+ifeq ($(CONFIG_IPMI_HANDLER),y)
+  obj-y += ipmi/ipmi.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 fastdep:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agp.h linux-2.4.21-rc3/drivers/char/agp/agp.h
--- linux-2.4.20/drivers/char/agp/agp.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/agp/agp.h	2003-05-22 22:06:42.000000000 +0000
@@ -87,6 +87,7 @@
 	u32 *gatt_table;
 	u32 *gatt_table_real;
 	unsigned long scratch_page;
+	unsigned long scratch_page_real;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
 	u32 mode;
@@ -99,7 +100,6 @@
 	int needs_scratch_page;
 	int aperture_size_idx;
 	int num_aperture_sizes;
-	int num_of_masks;
 	int capndx;
 	int cant_use_aperture;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agpgart_be.c linux-2.4.21-rc3/drivers/char/agp/agpgart_be.c
--- linux-2.4.20/drivers/char/agp/agpgart_be.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/agp/agpgart_be.c	2003-05-22 22:06:27.000000000 +0000
@@ -209,7 +209,6 @@
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] &= ~(0x00000fff);
 			agp_bridge.agp_destroy_page((unsigned long)
 					 phys_to_virt(curr->memory[i]));
 		}
@@ -262,10 +261,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[i] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[i]),
-						  type);
+		new->memory[i] = virt_to_phys((void *) new->memory[i]);
 		new->page_count++;
 	}
 
@@ -311,9 +307,6 @@
 
 int agp_copy_info(agp_kern_info * info)
 {
-	unsigned long page_mask = 0;
-	int i;
-
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
@@ -329,11 +322,7 @@
 	info->max_memory = agp_bridge.max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
 	info->cant_use_aperture = agp_bridge.cant_use_aperture;
-
-	for(i = 0; i < agp_bridge.num_of_masks; i++)
-		page_mask |= agp_bridge.mask_memory(page_mask, i);
-
-	info->page_mask = ~page_mask;
+	info->page_mask = ~0UL;
 	return 0;
 }
 
@@ -731,7 +720,8 @@
 		mem->is_flushed = TRUE;
 	}
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		agp_bridge.gatt_table[j] = mem->memory[i];
+		agp_bridge.gatt_table[j] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 
 	agp_bridge.tlb_flush(mem);
@@ -976,7 +966,8 @@
    	CACHE_FLUSH();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
-			 I810_PTE_BASE + (j * 4), mem->memory[i]);
+			 I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 	}
 	CACHE_FLUSH();
 
@@ -1042,10 +1033,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[0] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[0]),
-						  type);
+		new->memory[0] = virt_to_phys((void *) new->memory[0]);
 		new->page_count = 1;
 	   	new->num_scratch_pages = 1;
 	   	new->type = AGP_PHYS_MEMORY;
@@ -1079,7 +1067,6 @@
 	intel_i810_private.i810_dev = i810_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 2;
 	agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1282,7 +1269,8 @@
 	CACHE_FLUSH();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 
 	CACHE_FLUSH();
 
@@ -1343,7 +1331,7 @@
 			return(NULL);
 		}
 
-		nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+		nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
 		nw->page_count = 1;
 		nw->num_scratch_pages = 1;
 		nw->type = AGP_PHYS_MEMORY;
@@ -1359,7 +1347,6 @@
 	intel_i830_private.i830_dev = i830_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 3;
 	agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1841,7 +1828,6 @@
 static int __init intel_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
 	agp_bridge.size_type = U16_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -1874,7 +1860,6 @@
 static int __init intel_815_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_815_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1907,7 +1892,6 @@
 static int __init intel_820_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 7;
@@ -1940,7 +1924,6 @@
 static int __init intel_830mp_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 4;
@@ -1972,7 +1955,6 @@
 static int __init intel_840_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2005,7 +1987,6 @@
 static int __init intel_845_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2038,7 +2019,6 @@
 static int __init intel_850_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2071,7 +2051,6 @@
 static int __init intel_860_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2191,7 +2170,6 @@
 static int __init via_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = via_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) via_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2305,7 +2283,6 @@
 static int __init sis_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = sis_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2643,7 +2620,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -2689,7 +2667,6 @@
 static int __init amd_irongate_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_irongate_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2790,7 +2767,7 @@
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		addr = mem->memory[i];
+		addr = agp_bridge.mask_memory(mem->memory[i], mem->type);
 
 		tmp = addr;
 		BUG_ON(tmp & 0xffffff0000000ffc);
@@ -3155,7 +3132,6 @@
 static int __init amd_8151_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_8151_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_8151_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3393,7 +3369,6 @@
 static int __init ali_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = ali_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3807,7 +3782,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -3964,7 +3940,6 @@
 	serverworks_private.svrwrks_dev = pdev;
 
 	agp_bridge.masks = serverworks_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) serverworks_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -4362,7 +4337,6 @@
 static int __init hp_zx1_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = hp_zx1_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.dev_private_data = NULL;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.needs_scratch_page = FALSE;
@@ -4485,12 +4459,6 @@
 		"AMD",
 		"761",
 		amd_irongate_setup },
-	{ PCI_DEVICE_ID_AMD_762_0,
-		PCI_VENDOR_ID_AMD,
-		AMD_762,
-		"AMD",
-		"760MP",
-		amd_irongate_setup },
 	{ 0,
 		PCI_VENDOR_ID_AMD,
 		AMD_GENERIC,
@@ -4556,7 +4524,7 @@
 		 INTEL_I845_G,
 		 "Intel",
 		 "i845G",
-		 intel_830mp_setup },
+		 intel_845_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -4714,6 +4682,18 @@
 		"Via",
 		"Apollo Pro KT266",
 		via_generic_setup },
+        { PCI_DEVICE_ID_VIA_8377_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_KT400,
+		"Via",
+		"Apollo Pro KT400",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_P4X333,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_P4X400,
+		"Via",
+		"Apollo P4X400",
+		via_generic_setup },
 	{ 0,
 		PCI_VENDOR_ID_VIA,
 		VIA_GENERIC,
@@ -5077,17 +5057,17 @@
 	}
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
+		unsigned long addr;
+		addr = agp_bridge.agp_alloc_page();
 
-		if (agp_bridge.scratch_page == 0) {
+		if (addr == 0) {
 			printk(KERN_ERR PFX "unable to get memory for "
 			       "scratch page.\n");
 			return -ENOMEM;
 		}
+		agp_bridge.scratch_page_real = virt_to_phys((void *) addr);
 		agp_bridge.scratch_page =
-		    virt_to_phys((void *) agp_bridge.scratch_page);
-		agp_bridge.scratch_page =
-		    agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+		    agp_bridge.mask_memory(agp_bridge.scratch_page_real, 0);
 	}
 
 	size_value = agp_bridge.fetch_size();
@@ -5129,9 +5109,8 @@
 
 err_out:
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 	if (got_gatt)
 		agp_bridge.free_gatt_table();
@@ -5149,9 +5128,8 @@
 	vfree(agp_bridge.key_list);
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/amd768_rng.c linux-2.4.21-rc3/drivers/char/amd768_rng.c
--- linux-2.4.20/drivers/char/amd768_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/amd768_rng.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,11 +1,12 @@
 /*
- 	Hardware driver for the AMD 768 Random Number Generator (RNG)
+ 	Hardware driver for the AMD 768/8111 Random Number Generator (RNG)
 	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
- 
+	(c) Copyright 2002,2003 Andi Kleen, SuSE Labs
+
  	derived from
  
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Please read Documentation/i810_rng.txt for details on use.
@@ -238,13 +239,14 @@
  */
 static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
 
 
-MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek");
-MODULE_DESCRIPTION("AMD 768 Random Number Generator (RNG) driver");
+MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek, Andi Kleen");
+MODULE_DESCRIPTION("AMD 768/8111 Random Number Generator (RNG) driver");
 MODULE_LICENSE("GPL");
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/cyclades.c linux-2.4.21-rc3/drivers/char/cyclades.c
--- linux-2.4.20/drivers/char/cyclades.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/cyclades.c	2003-05-22 22:06:38.000000000 +0000
@@ -4957,7 +4957,7 @@
   struct pci_dev	*pdev = NULL;
   unsigned char		cyy_rev_id;
   unsigned char         cy_pci_irq = 0;
-  uclong		cy_pci_phys0, cy_pci_phys1, cy_pci_phys2;
+  uclong		cy_pci_phys0, cy_pci_phys2;
   uclong		cy_pci_addr0, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan, plx_ver;
   unsigned short        device_id,dev_index = 0;
@@ -4965,8 +4965,7 @@
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   uclong		Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
   unsigned char         Ze_irq[NR_CARDS];
-  struct resource *resource;
-  unsigned long res_start, res_len;
+  struct pci_dev	*Ze_pdev[NR_CARDS];
 
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
@@ -4988,7 +4987,6 @@
                 /* read PCI configuration area */
 		cy_pci_irq = pdev->irq;
 		cy_pci_phys0 = pci_resource_start(pdev, 0);
-		cy_pci_phys1 = pci_resource_start(pdev, 1);
 		cy_pci_phys2 = pci_resource_start(pdev, 2);
 		pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
@@ -5014,14 +5012,11 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
+		if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
+		    printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
 		    continue;
 		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Yctl;
 
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5092,10 +5087,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_pci_nchan/4;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* enable interrupts in the PCI interface */
 		plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
@@ -5175,16 +5167,13 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Zctl, 
-					  "Cyclades-Z");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
-		    continue;
-		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Zctl;
 
+		if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
+			printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
+  			continue;
+  		}
+  
 		if (mailbox == ZE_V1) {
 		    cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
 		    if (ZeIndex == NR_CARDS) {
@@ -5198,6 +5187,7 @@
 			Ze_addr0[ZeIndex] = cy_pci_addr0;
 			Ze_addr2[ZeIndex] = cy_pci_addr2;
 			Ze_irq[ZeIndex] = cy_pci_irq;
+			Ze_pdev[ZeIndex] = pdev;
 			ZeIndex++;
 		    }
 		    i--;
@@ -5282,10 +5272,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5313,12 +5300,14 @@
 	    cy_pci_addr0 = Ze_addr0[0];
 	    cy_pci_addr2 = Ze_addr2[0];
 	    cy_pci_irq = Ze_irq[0];
+	    pdev = Ze_pdev[0];
 	    for (j = 0 ; j < ZeIndex-1 ; j++) {
 		Ze_phys0[j] = Ze_phys0[j+1];
 		Ze_phys2[j] = Ze_phys2[j+1];
 		Ze_addr0[j] = Ze_addr0[j+1];
 		Ze_addr2[j] = Ze_addr2[j+1];
 		Ze_irq[j] = Ze_irq[j+1];
+		Ze_pdev[j] = Ze_pdev[j+1];
 	    }
 	    ZeIndex--;
 		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
@@ -5376,6 +5365,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5812,10 +5802,8 @@
 #endif /* CONFIG_CYZ_INTR */
 	    )
 		free_irq(cy_card[i].irq, &cy_card[i]);
-	    if (cy_card[i].resource) {
-		cy_card[i].resource = NULL;
-		release_region(cy_card[i].res_start, cy_card[i].res_len);
-	    }
+	    if (cy_card[i].pdev)
+	    	pci_release_regions(cy_card[i].pdev);
         }
     }
     if (tmp_buf) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_agpsupport.h linux-2.4.21-rc3/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.20/drivers/char/drm/drm_agpsupport.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_agpsupport.h	2003-05-22 22:06:24.000000000 +0000
@@ -279,8 +279,12 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
 			break;
+		case VIA_APOLLO_P4X400:	head->chipset = "VIA Apollo P4X400";
+			break;
 
 		case SIS_GENERIC:	head->chipset = "SiS";           break;
 		case AMD_GENERIC:	head->chipset = "AMD";           break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_auth.h linux-2.4.21-rc3/drivers/char/drm/drm_auth.h
--- linux-2.4.20/drivers/char/drm/drm_auth.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_auth.h	2003-05-22 22:06:52.000000000 +0000
@@ -63,6 +63,7 @@
 	hash	     = DRM(hash_magic)(magic);
 	entry	     = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
 	if (!entry) return -ENOMEM;
+	memset(entry, 0, sizeof(*entry));
 	entry->magic = magic;
 	entry->priv  = priv;
 	entry->next  = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_ioctl.h linux-2.4.21-rc3/drivers/char/drm/drm_ioctl.h
--- linux-2.4.20/drivers/char/drm/drm_ioctl.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_ioctl.h	2003-05-22 22:06:38.000000000 +0000
@@ -40,8 +40,20 @@
 	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
 		return -EFAULT;
 	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
-	if (dev) p.irq = dev->irq;
-	else	 p.irq = 0;
+	if (!dev) {
+		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}			
+	if (pci_enable_device(dev) != 0) {
+		DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}		
+	p.irq = dev->irq;
+ out:
 	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
 		  p.busnum, p.devnum, p.funcnum, p.irq);
 	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_lists.h linux-2.4.21-rc3/drivers/char/drm/drm_lists.h
--- linux-2.4.20/drivers/char/drm/drm_lists.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_lists.h	2003-05-22 22:06:39.000000000 +0000
@@ -41,7 +41,7 @@
 				    DRM_MEM_BUFLISTS);
 
 	if(!bl->bufs) return -ENOMEM;
-
+	memset(bl->bufs, 0, sizeof(*bl->bufs));
 	bl->count      = count;
 	bl->rp	       = bl->bufs;
 	bl->wp	       = bl->bufs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_scatter.h linux-2.4.21-rc3/drivers/char/drm/drm_scatter.h
--- linux-2.4.20/drivers/char/drm/drm_scatter.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_scatter.h	2003-05-22 22:06:48.000000000 +0000
@@ -93,6 +93,8 @@
 		return -ENOMEM;
 	}
 
+	memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
 	entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
 				     DRM_MEM_PAGES );
 	if ( !entry->busaddr ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_vm.h linux-2.4.21-rc3/drivers/char/drm/drm_vm.h
--- linux-2.4.20/drivers/char/drm/drm_vm.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/drm_vm.h	2003-05-22 22:06:53.000000000 +0000
@@ -406,7 +406,7 @@
 
 	if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
 		vma->vm_flags &= VM_MAYWRITE;
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
 #else
 				/* Ye gads this is ugly.  With more thought
@@ -433,7 +433,7 @@
 	case _DRM_FRAME_BUFFER:
 	case _DRM_REGISTERS:
 		if (VM_OFFSET(vma) >= __pa(high_memory)) {
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 			if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
 				pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_dma.c linux-2.4.21-rc3/drivers/char/drm/mga_dma.c
--- linux-2.4.20/drivers/char/drm/mga_dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/mga_dma.c	2003-05-22 22:06:40.000000000 +0000
@@ -27,7 +27,7 @@
  * Authors:
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_drm.h linux-2.4.21-rc3/drivers/char/drm/mga_drm.h
--- linux-2.4.20/drivers/char/drm/mga_drm.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/mga_drm.h	2003-05-22 22:06:27.000000000 +0000
@@ -26,7 +26,7 @@
  *
  * Authors:
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_state.c linux-2.4.21-rc3/drivers/char/drm/mga_state.c
--- linux-2.4.20/drivers/char/drm/mga_state.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/mga_state.c	2003-05-22 22:06:41.000000000 +0000
@@ -26,7 +26,7 @@
  *
  * Authors:
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/radeon.h linux-2.4.21-rc3/drivers/char/drm/radeon.h
--- linux-2.4.20/drivers/char/drm/radeon.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm/radeon.h	2003-05-22 22:06:52.000000000 +0000
@@ -25,6 +25,7 @@
  *
  * Authors:
  *    Gareth Hughes <gareth@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  */
 
 #ifndef __RADEON_H__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm-4.0/agpsupport.c linux-2.4.21-rc3/drivers/char/drm-4.0/agpsupport.c
--- linux-2.4.20/drivers/char/drm-4.0/agpsupport.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm-4.0/agpsupport.c	2003-05-22 22:06:51.000000000 +0000
@@ -275,6 +275,9 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133"; 
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
+		case VIA_APOLLO_P4X400:	head->chipset = "VIA Apollo P4X400";
 #endif
 
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm-4.0/i810_dma.c linux-2.4.21-rc3/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.20/drivers/char/drm-4.0/i810_dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/drm-4.0/i810_dma.c	2003-05-22 22:06:48.000000000 +0000
@@ -34,6 +34,7 @@
 #include "drmP.h"
 #include "i810_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
+#include <linux/pagemap.h>
 
 /* in case we don't have a 2.3.99-pre6 kernel or later: */
 #ifndef VM_DONTCOPY
@@ -225,14 +226,9 @@
 		if(buf_priv->currently_mapped != I810_BUF_MAPPED) 
 			return -EINVAL;
 		down_write(&current->mm->mmap_sem);
-#if LINUX_VERSION_CODE < 0x020399
-        	retcode = do_munmap((unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
-#else
-        	retcode = do_munmap(current->mm, 
+        	retcode = do_munmap(current->mm,
 				    (unsigned long)buf_priv->virtual, 
 				    (size_t) buf->total);
-#endif
    		up_write(&current->mm->mmap_sem);
 	}
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/efirtc.c linux-2.4.21-rc3/drivers/char/efirtc.c
--- linux-2.4.20/drivers/char/efirtc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/efirtc.c	2003-05-22 22:06:50.000000000 +0000
@@ -40,7 +40,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define EFI_RTC_VERSION		"0.3"
+#define EFI_RTC_VERSION		"0.4"
 
 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
 /*
@@ -315,14 +315,14 @@
 	spin_unlock_irqrestore(&efi_rtc_lock,flags);
 
 	p += sprintf(p,
-		     "Time          : %u:%u:%u.%09u\n"
-		     "Date          : %u-%u-%u\n"
-		     "Daylight      : %u\n",
+		     "Time           : %u:%u:%u.%09u\n"
+		     "Date           : %u-%u-%u\n"
+		     "Daylight       : %u\n",
 		     eft.hour, eft.minute, eft.second, eft.nanosecond, 
 		     eft.year, eft.month, eft.day,
 		     eft.daylight);
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -341,7 +341,7 @@
 		     enabled == 1 ? "yes" : "no",
 		     pending == 1 ? "yes" : "no");
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -375,12 +375,25 @@
 static int __init 
 efi_rtc_init(void)
 {
-	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
+	int ret;
+	struct proc_dir_entry *dir;
 
-	misc_register(&efi_rtc_dev);
+	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
 
-	create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL);
+	ret = misc_register(&efi_rtc_dev);
+	if (ret) {
+		printk(KERN_ERR "efirtc: can't misc_register on minor=%d\n",
+				EFI_RTC_MINOR);
+		return ret;
+	}
 
+	dir = create_proc_read_entry ("driver/efirtc", 0, NULL,
+			              efi_rtc_read_proc, NULL);
+	if (dir == NULL) {
+		printk(KERN_ERR "efirtc: can't create /proc/driver/efirtc.\n");
+		misc_deregister(&efi_rtc_dev);
+		return -1;
+	}
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/epca.c linux-2.4.21-rc3/drivers/char/epca.c
--- linux-2.4.20/drivers/char/epca.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/epca.c	2003-05-22 22:06:48.000000000 +0000
@@ -2023,7 +2023,8 @@
 	    (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
 		shrinkmem = 1;
 	if (bd->type < PCIXEM)
-		request_region((int)bd->port, 4, board_desc[bd->type]);
+		if (!request_region((int)bd->port, 4, board_desc[bd->type]))
+			return;		
 
 	memwinon(bd, 0);
 
@@ -2187,9 +2188,13 @@
 		if (!(ch->tmp_buf))
 		{
 			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
-
+			release_region((int)bd->port, 4);
+			while(i-- > 0)
+				kfree((ch--)->tmp_buf);
+			return;
 		}
-		memset((void *)ch->tmp_buf,0,ch->txbufsize);
+		else 
+			memset((void *)ch->tmp_buf,0,ch->txbufsize);
 	} /* End for each port */
 
 	printk(KERN_INFO 
@@ -3750,7 +3755,7 @@
 
 			case 5:
 				board.port = (unsigned char *)ints[index];
-				if (board.port <= 0)
+				if (ints[index] <= 0)
 				{
 					printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
 					invalid_lilo_config = 1;
@@ -3762,7 +3767,7 @@
 
 			case 6:
 				board.membase = (unsigned char *)ints[index];
-				if (board.membase <= 0)
+				if (ints[index] <= 0)
 				{
 					printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
 					invalid_lilo_config = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/genrtc.c linux-2.4.21-rc3/drivers/char/genrtc.c
--- linux-2.4.20/drivers/char/genrtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/genrtc.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,533 @@
+/*
+ *	Real Time Clock interface for
+ *		- q40 and other m68k machines,
+ *		- HP PARISC machines
+ *		- PowerPC machines
+ *      emulate some RTC irq capabilities in software
+ *
+ *      Copyright (C) 1999 Richard Zidlicky
+ *
+ *	based on Paul Gortmaker's rtc.c device and
+ *           Sam Creasey Generic rtc driver
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/dev/rtc
+ *	pseudo-file for status information.
+ *
+ *	The ioctls can be used to set the interrupt behaviour where
+ *	supported.
+ *
+ *	The /dev/rtc interface will block on reads until an interrupt
+ *	has been received. If a RTC interrupt has already happened,
+ *	it will output an unsigned long and then block. The output value
+ *	contains the interrupt status in the low byte and the number of
+ *	interrupts since the last read in the remaining high bytes. The
+ *	/dev/rtc interface can also be used with the select(2) call.
+ *
+ *	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.
+ *
+
+ *      1.01 fix for 2.3.X                    rz@linux-m68k.org
+ *      1.02 merged with code from genrtc.c   rz@linux-m68k.org
+ *      1.03 make it more portable            zippel@linux-m68k.org
+ *      1.04 removed useless timer code       rz@linux-m68k.org
+ *      1.05 portable RTC_UIE emulation       rz@linux-m68k.org
+ *      1.06 set_rtc_time can return an error trini@kernel.crashing.org
+ *      1.07 ported to HP PARISC (hppa)	      Helge Deller <deller@gmx.de>
+ */
+
+#define RTC_VERSION	"1.07"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/rtc.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
+
+/*
+ *	Bits in gen_rtc_status.
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+
+static unsigned char gen_rtc_status;	/* bitmapped status byte.	*/
+static unsigned long gen_rtc_irq_data;	/* our output to the world	*/
+
+/* months start at 0 now */
+static unsigned char days_in_mo[] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int irq_active;
+
+#ifdef CONFIG_GEN_RTC_X
+struct tq_struct genrtc_task;
+static struct timer_list timer_task;
+
+static unsigned int oldsecs;
+static int lostint;
+static int tt_exp;
+
+static void gen_rtc_timer(unsigned long data);
+
+static volatile int stask_active;              /* schedule_task */
+static volatile int ttask_active;              /* timer_task */
+static int stop_rtc_timers;                    /* don't requeue tasks */
+static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+static void gen_rtc_interrupt(unsigned long arg);
+
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void genrtc_troutine(void *data)
+{
+	unsigned int tmp = get_rtc_ss();
+	
+	if (stop_rtc_timers) {
+		stask_active = 0;
+		return;
+	}
+
+	if (oldsecs != tmp){
+		oldsecs = tmp;
+
+		timer_task.function = gen_rtc_timer;
+		timer_task.expires = jiffies + HZ - (HZ/10);
+		tt_exp=timer_task.expires;
+		ttask_active=1;
+		stask_active=0;
+		add_timer(&timer_task);
+
+		gen_rtc_interrupt(0);
+	} else if (schedule_task(&genrtc_task) == 0)
+		stask_active = 0;
+}
+
+static void gen_rtc_timer(unsigned long data)
+{
+	lostint = get_rtc_ss() - oldsecs ;
+	if (lostint<0) 
+		lostint = 60 - lostint;
+	if (time_after(jiffies, tt_exp))
+		printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n",
+		       jiffies-tt_exp);
+	ttask_active=0;
+	stask_active=1;
+	if ((schedule_task(&genrtc_task) == 0))
+		stask_active = 0;
+}
+
+/* 
+ * call gen_rtc_interrupt function to signal an RTC_UIE,
+ * arg is unused.
+ * Could be invoked either from a real interrupt handler or
+ * from some routine that periodically (eg 100HZ) monitors
+ * whether RTC_SECS changed
+ */
+static void gen_rtc_interrupt(unsigned long arg)
+{
+	/*  We store the status in the low byte and the number of
+	 *	interrupts received since the last read in the remainder
+	 *	of rtc_irq_data.  */
+
+	gen_rtc_irq_data += 0x100;
+	gen_rtc_irq_data &= ~0xff;
+	gen_rtc_irq_data |= RTC_UIE;
+
+	if (lostint){
+		printk("genrtc: system delaying clock ticks?\n");
+		/* increment count so that userspace knows something is wrong */
+		gen_rtc_irq_data += ((lostint-1)<<8);
+		lostint = 0;
+	}
+
+	wake_up_interruptible(&gen_rtc_wait);
+}
+
+/*
+ *	Now all the various file operations that we export.
+ */
+static ssize_t gen_rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+
+	if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
+		return -EAGAIN;
+
+	add_wait_queue(&gen_rtc_wait, &wait);
+	retval = -ERESTARTSYS;
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		data = xchg(&gen_rtc_irq_data, 0);
+		if (data)
+			break;
+		if (signal_pending(current))
+			goto out;
+		schedule();
+	}
+
+	/* first test allows optimizer to nuke this case for 32-bit machines */
+	if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
+		unsigned int uidata = data;
+		retval = put_user(uidata, (unsigned long *)buf);
+	}
+	else {
+		retval = put_user(data, (unsigned long *)buf);
+	}
+	if (!retval)
+		retval = sizeof(unsigned long);
+ out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&gen_rtc_wait, &wait);
+
+	return retval;
+}
+
+static unsigned int gen_rtc_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	poll_wait(file, &gen_rtc_wait, wait);
+	if (gen_rtc_irq_data != 0)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+#endif
+
+/*
+ * Used to disable/enable interrupts, only RTC_UIE supported
+ * We also clear out any old irq data after an ioctl() that
+ * meddles with the interrupt enable/disable bits.
+ */
+
+static inline void gen_clear_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	stop_rtc_timers = 1;
+	if (ttask_active){
+		del_timer_sync(&timer_task);
+		ttask_active = 0;
+	}
+	while (stask_active)
+		schedule();
+
+	spin_lock(&gen_rtc_lock);
+	irq_active = 0;
+	spin_unlock(&gen_rtc_lock);
+#endif
+}
+
+static inline int gen_set_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	spin_lock(&gen_rtc_lock);
+	if ( !irq_active ) {
+		irq_active = 1;
+		stop_rtc_timers = 0;
+		lostint = 0;
+		genrtc_task.routine = genrtc_troutine;
+		oldsecs = get_rtc_ss();
+		init_timer(&timer_task);
+
+		stask_active = 1;
+		if (schedule_task(&genrtc_task) == 0){
+			stask_active = 0;
+		}
+	}
+	spin_unlock(&gen_rtc_lock);
+	gen_rtc_irq_data = 0;
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	struct rtc_time wtime;
+	struct rtc_pll_info pll;
+
+	switch (cmd) {
+
+	case RTC_PLL_GET:
+	    if (get_rtc_pll(&pll))
+	 	    return -EINVAL;
+	    else
+		    return copy_to_user((void *)arg, &pll, sizeof pll) ? -EFAULT : 0;
+
+	case RTC_PLL_SET:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+		if (copy_from_user(&pll, (struct rtc_pll_info*)arg,
+				   sizeof(pll)))
+			return -EFAULT;
+	    return set_rtc_pll(&pll);
+
+	case RTC_UIE_OFF:	/* disable ints from RTC updates.	*/
+		gen_clear_rtc_irq_bit(RTC_UIE);
+		return 0;
+
+	case RTC_UIE_ON:	/* enable ints for RTC updates.	*/
+	        return gen_set_rtc_irq_bit(RTC_UIE);
+
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		/* this doesn't get week-day, who cares */
+		memset(&wtime, 0, sizeof(wtime));
+		get_rtc_time(&wtime);
+
+		return copy_to_user((void *)arg, &wtime, sizeof(wtime)) ? -EFAULT : 0;
+
+	case RTC_SET_TIME:	/* Set the RTC */
+	    {
+		int year;
+		unsigned char leap_yr;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&wtime, (struct rtc_time *)arg,
+				   sizeof(wtime)))
+			return -EFAULT;
+
+		year = wtime.tm_year + 1900;
+		leap_yr = ((!(year % 4) && (year % 100)) ||
+			   !(year % 400));
+
+		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
+			return -EINVAL;
+
+		if (wtime.tm_mday < 0 || wtime.tm_mday >
+		    (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
+			return -EINVAL;
+
+		if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
+		    wtime.tm_min < 0 || wtime.tm_min >= 60 ||
+		    wtime.tm_sec < 0 || wtime.tm_sec >= 60)
+			return -EINVAL;
+
+		return set_rtc_time(&wtime);
+	    }
+	}
+
+	return -EINVAL;
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int gen_rtc_open(struct inode *inode, struct file *file)
+{
+	if (gen_rtc_status & RTC_IS_OPEN)
+		return -EBUSY;
+
+	MOD_INC_USE_COUNT;
+
+	gen_rtc_status |= RTC_IS_OPEN;
+	gen_rtc_irq_data = 0;
+	irq_active = 0;
+
+	return 0;
+}
+
+static int gen_rtc_release(struct inode *inode, struct file *file)
+{
+	/*
+	 * Turn off all interrupts once the device is no longer
+	 * in use and clear the data.
+	 */
+
+	gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
+
+	gen_rtc_status &= ~RTC_IS_OPEN;
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations gen_rtc_fops = {
+	.owner		= THIS_MODULE,
+#ifdef CONFIG_GEN_RTC_X
+	.read		= gen_rtc_read,
+	.poll		= gen_rtc_poll,
+#endif
+	.ioctl		= gen_rtc_ioctl,
+	.open		= gen_rtc_open,
+	.release	= gen_rtc_release,
+};
+
+static struct miscdevice rtc_gen_dev =
+{
+	.minor		= RTC_MINOR,
+	.name		= "rtc",
+	.fops		= &gen_rtc_fops,
+};
+
+static int __init rtc_generic_init(void)
+{
+	int retval;
+
+	printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
+
+	retval = misc_register(&rtc_gen_dev);
+	if(retval < 0)
+		return retval;
+
+#ifdef CONFIG_PROC_FS
+	if((create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL)) == NULL){
+		misc_deregister(&rtc_gen_dev);
+		return -ENOMEM;
+	}
+#endif
+
+	return 0;
+}
+
+static void __exit rtc_generic_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister(&rtc_gen_dev);
+}
+
+module_init(rtc_generic_init);
+module_exit(rtc_generic_exit);
+EXPORT_NO_SYMBOLS;
+
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+static int gen_rtc_proc_output(char *buf)
+{
+	char *p;
+	struct rtc_time tm;
+	unsigned int flags;
+	struct rtc_pll_info pll;
+
+	p = buf;
+
+	flags = get_rtc_time(&tm);
+
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+		     "rtc_epoch\t: %04u\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
+
+	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+
+	p += sprintf(p, "alarm\t\t: ");
+	if (tm.tm_hour <= 24)
+		p += sprintf(p, "%02d:", tm.tm_hour);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_min <= 59)
+		p += sprintf(p, "%02d:", tm.tm_min);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_sec <= 59)
+		p += sprintf(p, "%02d\n", tm.tm_sec);
+	else
+		p += sprintf(p, "**\n");
+
+	p += sprintf(p,
+		     "DST_enable\t: %s\n"
+		     "BCD\t\t: %s\n"
+		     "24hr\t\t: %s\n"
+		     "square_wave\t: %s\n"
+		     "alarm_IRQ\t: %s\n"
+		     "update_IRQ\t: %s\n"
+		     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+		     "batt_status\t: %s\n",
+		     (flags & RTC_DST_EN) ? "yes" : "no",
+		     (flags & RTC_DM_BINARY) ? "no" : "yes",
+		     (flags & RTC_24H) ? "yes" : "no",
+		     (flags & RTC_SQWE) ? "yes" : "no",
+		     (flags & RTC_AIE) ? "yes" : "no",
+		     irq_active ? "yes" : "no",
+		     (flags & RTC_PIE) ? "yes" : "no",
+		     0L /* freq */,
+		     (flags & RTC_BATT_BAD) ? "bad" : "okay");
+	if (!get_rtc_pll(&pll))
+	    p += sprintf(p,
+			 "PLL adjustment\t: %d\n"
+			 "PLL max +ve adjustment\t: %d\n"
+			 "PLL max -ve adjustment\t: %d\n"
+			 "PLL +ve adjustment factor\t: %d\n"
+			 "PLL -ve adjustment factor\t: %d\n"
+			 "PLL frequency\t: %ld\n",
+			 pll.pll_value,
+			 pll.pll_max,
+			 pll.pll_min,
+			 pll.pll_posmult,
+			 pll.pll_negmult,
+			 pll.pll_clock);
+	return p - buf;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	int len = gen_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+	return len;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+
+MODULE_AUTHOR("Richard Zidlicky");
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/i810_rng.c linux-2.4.21-rc3/drivers/char/i810_rng.c
--- linux-2.4.20/drivers/char/i810_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/i810_rng.c	2003-05-22 22:06:42.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Driver Web site:  http://sourceforge.net/projects/gkernel/
@@ -27,6 +27,7 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -243,8 +244,13 @@
 		if (filp->f_flags & O_NONBLOCK)
 			return ret ? : -EAGAIN;
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (current->need_resched)
+		{
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		else
+			udelay(200);
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/Makefile linux-2.4.21-rc3/drivers/char/ipmi/Makefile
--- linux-2.4.20/drivers/char/ipmi/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/Makefile	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile for the ipmi drivers.
+#
+
+O_TARGET	:= ipmi.o
+
+export-objs	:= ipmi_msghandler.o ipmi_watchdog.o
+
+list-multi := ipmi_kcs_drv.o
+ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o
+
+obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
+obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
+obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
+obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+
+include $(TOPDIR)/Rules.make
+
+ipmi_kcs_drv.o:	$(ipmi_kcs_drv-objs)
+	$(LD) -r -o $@ $(ipmi_kcs_drv-objs) 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_devintf.c linux-2.4.21-rc3/drivers/char/ipmi/ipmi_devintf.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_devintf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_devintf.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,532 @@
+/*
+ * ipmi_devintf.c
+ *
+ * Linux device interface for the IPMI message handler.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ipmi.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>
+
+struct ipmi_file_private
+{
+	ipmi_user_t          user;
+	spinlock_t           recv_msg_lock;
+	struct list_head     recv_msgs;
+	struct file          *file;
+	struct fasync_struct *fasync_queue;
+	wait_queue_head_t    wait;
+	struct semaphore     recv_sem;
+};
+
+static void file_receive_handler(struct ipmi_recv_msg *msg,
+				 void                 *handler_data)
+{
+	struct ipmi_file_private *priv = handler_data;
+	int                      was_empty;
+	unsigned long            flags;
+
+	spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+
+	was_empty = list_empty(&(priv->recv_msgs));
+	list_add_tail(&(msg->link), &(priv->recv_msgs));
+
+	if (was_empty) {
+		wake_up_interruptible(&priv->wait);
+		kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
+	}
+
+	spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+}
+
+static unsigned int ipmi_poll(struct file *file, poll_table *wait)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	unsigned int             mask = 0;
+	unsigned long            flags;
+
+	poll_wait(file, &priv->wait, wait);
+
+	spin_lock_irqsave(&priv->recv_msg_lock, flags);
+
+	if (! list_empty(&(priv->recv_msgs)))
+		mask |= (POLLIN | POLLRDNORM);
+
+	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
+
+	return mask;
+}
+
+static int ipmi_fasync(int fd, struct file *file, int on)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      result;
+
+	result = fasync_helper(fd, file, on, &priv->fasync_queue);
+
+	return (result);
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	ipmi_recv_hndl : file_receive_handler
+};
+
+static int ipmi_open(struct inode *inode, struct file *file)
+{
+	int                      if_num = minor(inode->i_rdev);
+	int                      rv;
+	struct ipmi_file_private *priv;
+
+
+	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->file = file;
+
+	rv = ipmi_create_user(if_num,
+			      &ipmi_hndlrs,
+			      priv,
+			      &(priv->user));
+	if (rv) {
+		kfree(priv);
+		return rv;
+	}
+
+	file->private_data = priv;
+
+	spin_lock_init(&(priv->recv_msg_lock));
+	INIT_LIST_HEAD(&(priv->recv_msgs));
+	init_waitqueue_head(&priv->wait);
+	priv->fasync_queue = NULL;
+	sema_init(&(priv->recv_sem), 1);
+
+	return 0;
+}
+
+static int ipmi_release(struct inode *inode, struct file *file)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      rv;
+
+	rv = ipmi_destroy_user(priv->user);
+	if (rv)
+		return rv;
+
+	ipmi_fasync (-1, file, 0);
+
+	/* FIXME - free the messages in the list. */
+	kfree(priv);
+
+	return 0;
+}
+
+static int ipmi_ioctl(struct inode  *inode,
+		      struct file   *file,
+		      unsigned int  cmd,
+		      unsigned long data)
+{
+	int                      rv = -EINVAL;
+	struct ipmi_file_private *priv = file->private_data;
+
+	switch (cmd) 
+	{
+	case IPMICTL_SEND_COMMAND:
+	{
+		struct ipmi_req    req;
+		struct ipmi_addr   addr;
+		unsigned char msgdata[IPMI_MAX_MSG_LENGTH];
+
+		if (copy_from_user(&req, (void *) data, sizeof(req))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		if (req.addr_len > sizeof(struct ipmi_addr))
+		{
+			rv = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&addr, req.addr, req.addr_len)) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_validate_addr(&addr, req.addr_len);
+		if (rv)
+			break;
+
+		if (req.msg.data != NULL) {
+			if (req.msg.data_len > IPMI_MAX_MSG_LENGTH) {
+				rv = -EMSGSIZE;
+				break;
+			}
+
+			if (copy_from_user(&msgdata,
+					   req.msg.data,
+					   req.msg.data_len))
+			{
+				rv = -EFAULT;
+				break;
+			}
+		} else {
+			req.msg.data_len = 0;
+		}
+
+		req.msg.data = msgdata;
+
+		rv = ipmi_request(priv->user,
+				  &addr,
+				  req.msgid,
+				  &(req.msg),
+				  0);
+		break;
+	}
+
+	case IPMICTL_RECEIVE_MSG:
+	case IPMICTL_RECEIVE_MSG_TRUNC:
+	{
+		struct ipmi_recv      rsp;
+		int              addr_len;
+		struct list_head *entry;
+		struct ipmi_recv_msg  *msg;
+		unsigned long    flags;
+		
+
+		rv = 0;
+		if (copy_from_user(&rsp, (void *) data, sizeof(rsp))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		/* We claim a semaphore because we don't want two
+                   users getting something from the queue at a time.
+                   Since we have to release the spinlock before we can
+                   copy the data to the user, it's possible another
+                   user will grab something from the queue, too.  Then
+                   the messages might get out of order if something
+                   fails and the message gets put back onto the
+                   queue.  This semaphore prevents that problem. */
+		down(&(priv->recv_sem));
+
+		/* Grab the message off the list. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		if (list_empty(&(priv->recv_msgs))) {
+			spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+			rv = -EAGAIN;
+			goto recv_err;
+		}
+		entry = priv->recv_msgs.next;
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+
+		addr_len = ipmi_addr_length(msg->addr.addr_type);
+		if (rsp.addr_len < addr_len)
+		{
+			rv = -EINVAL;
+			goto recv_putback_on_err;
+		}
+
+		if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+		rsp.addr_len = addr_len;
+
+		rsp.recv_type = msg->recv_type;
+		rsp.msgid = msg->msgid;
+		rsp.msg.netfn = msg->msg.netfn;
+		rsp.msg.cmd = msg->msg.cmd;
+
+		if (msg->msg.data_len > 0) {
+			if (rsp.msg.data_len < msg->msg.data_len) {
+				rv = -EMSGSIZE;
+				if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
+					msg->msg.data_len = rsp.msg.data_len;
+				} else {
+					goto recv_putback_on_err;
+				}
+			}
+
+			if (copy_to_user(rsp.msg.data,
+					 msg->msg.data,
+					 msg->msg.data_len))
+			{
+				rv = -EFAULT;
+				goto recv_putback_on_err;
+			}
+			rsp.msg.data_len = msg->msg.data_len;
+		} else {
+			rsp.msg.data_len = 0;
+		}
+
+		if (copy_to_user((void *) data, &rsp, sizeof(rsp))) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+
+		up(&(priv->recv_sem));
+		ipmi_free_recv_msg(msg);
+		break;
+
+	recv_putback_on_err:
+		/* If we got an error, put the message back onto
+		   the head of the queue. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		list_add(entry, &(priv->recv_msgs));
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+		up(&(priv->recv_sem));
+		break;
+
+	recv_err:
+		up(&(priv->recv_sem));
+		break;
+	}
+
+	case IPMICTL_REGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_UNREGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec   val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_SET_GETS_EVENTS_CMD:
+	{
+		int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_set_gets_events(priv->user, val);
+		break;
+	}
+
+	case IPMICTL_SET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_address(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_address(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_SET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_LUN(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_LUN(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	}
+  
+	return rv;
+}
+
+
+static struct file_operations ipmi_fops = {
+	owner:   THIS_MODULE,
+	ioctl:   ipmi_ioctl,
+	open:    ipmi_open,
+	release: ipmi_release,
+	fasync:  ipmi_fasync,
+	poll:    ipmi_poll
+};
+
+#define DEVICE_NAME     "ipmidev"
+
+static int ipmi_major = 0;
+MODULE_PARM(ipmi_major, "i");
+
+static devfs_handle_t devfs_handle;
+
+#define MAX_DEVICES 10
+static devfs_handle_t handles[MAX_DEVICES];
+
+static void ipmi_new_smi(int if_num)
+{
+	char name[2];
+
+	if (if_num > MAX_DEVICES)
+		return;
+
+	name[0] = if_num + '0';
+	name[1] = '\0';
+
+	handles[if_num] = devfs_register(devfs_handle, name, DEVFS_FL_NONE,
+					 ipmi_major, if_num,
+					 S_IFCHR | S_IRUSR | S_IWUSR,
+					 &ipmi_fops, NULL);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	if (if_num > MAX_DEVICES)
+		return;
+
+	devfs_unregister(handles[if_num]);
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	new_smi  : ipmi_new_smi,
+	smi_gone : ipmi_smi_gone
+};
+
+static __init int init_ipmi_devintf(void)
+{
+	int rv;
+
+	if (ipmi_major < 0)
+		return -EINVAL;
+
+	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
+	if (rv < 0) {
+		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
+		return rv;
+	}
+
+	if (ipmi_major == 0) {
+		ipmi_major = rv;
+	}
+
+	devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+		unregister_chrdev(ipmi_major, DEVICE_NAME);
+		printk(KERN_WARNING "ipmi: can't register smi watcher");
+		return rv;
+	}
+
+	printk(KERN_INFO "ipmi: device interface at char major %d\n",
+	       ipmi_major);
+
+	return 0;
+}
+module_init(init_ipmi_devintf);
+
+static __exit void cleanup_ipmi(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	devfs_unregister(devfs_handle);
+	unregister_chrdev(ipmi_major, DEVICE_NAME);
+}
+module_exit(cleanup_ipmi);
+#ifndef MODULE
+static __init int ipmi_setup (char *str)
+{
+	int x;
+
+	if (get_option (&str, &x)) {
+		/* ipmi=x sets the major number to x. */
+		ipmi_major = x;
+	} else if (!strcmp(str, "off")) {
+		ipmi_major = -1;
+	}
+
+	return 1;
+}
+#endif
+
+__setup("ipmi=", ipmi_setup);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_intf.c linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_intf.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_intf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_intf.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,1243 @@
+/*
+ * ipmi_kcs_intf.c
+ *
+ * The interface to the IPMI driver for the KCS.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file holds the "policy" for the interface to the KCS state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real KCS state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/ipmi_smi.h>
+#include <asm/io.h>
+#include "ipmi_kcs_sm.h"
+#include <linux/init.h>
+
+/* Measure times between events in the driver. */
+#undef DEBUG_TIMING
+
+#ifdef CONFIG_IPMI_KCS
+/* This forces a dependency to the config file for this option. */
+#endif
+
+enum kcs_intf_state {
+	KCS_NORMAL,
+	KCS_GETTING_FLAGS,
+	KCS_GETTING_EVENTS,
+	KCS_CLEARING_FLAGS,
+	KCS_CLEARING_FLAGS_THEN_SET_IRQ,
+	KCS_GETTING_MESSAGES,
+	KCS_ENABLE_INTERRUPTS1,
+	KCS_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+struct kcs_info
+{
+	ipmi_smi_t          intf;
+	struct kcs_data     *kcs_sm;
+	spinlock_t          kcs_lock;
+	spinlock_t          msg_lock;
+	struct list_head    xmit_msgs;
+	struct list_head    hp_xmit_msgs;
+	struct ipmi_smi_msg *curr_msg;
+	enum kcs_intf_state kcs_state;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic to make sure stuff goes
+	   out. */
+	int                 run_to_completion;
+
+	/* The I/O port of a KCS interface. */
+	int                 port;
+
+	/* zero if no irq; */
+	int                 irq;
+
+	/* The physical and remapped memory addresses of a KCS interface. */
+	unsigned long	    physaddr;
+	unsigned char	    *addr;
+
+	/* The timer for this kcs. */
+	struct timer_list   kcs_timer;
+
+	/* The time (in jiffies) the last timeout occurred at. */
+	unsigned long       last_timeout_jiffies;
+
+	/* Used to gracefully stop the timer without race conditions. */
+	volatile int        stop_operation;
+	volatile int        timer_stopped;
+
+	/* The driver will disable interrupts when it gets into a
+	   situation where it cannot handle messages due to lack of
+	   memory.  Once that situation clears up, it will re-enable
+	   interupts. */
+	int                 interrupt_disabled;
+};
+
+static void deliver_recv_msg(struct kcs_info *kcs_info, struct ipmi_smi_msg *msg)
+{
+	/* Deliver the message to the upper layer with the lock
+           released. */
+	spin_unlock(&(kcs_info->kcs_lock));
+	ipmi_smi_msg_received(kcs_info->intf, msg);
+	spin_lock(&(kcs_info->kcs_lock));
+}
+
+static void return_hosed_msg(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg = kcs_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+			
+	kcs_info->curr_msg = NULL;
+	deliver_recv_msg(kcs_info, msg);
+}
+
+static enum kcs_result start_next_msg(struct kcs_info *kcs_info)
+{
+	int              rv;
+	struct list_head *entry = NULL;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	/* No need to save flags, we aleady have interrupts off and we
+	   already hold the KCS lock. */
+	spin_lock(&(kcs_info->msg_lock));
+	
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(kcs_info->hp_xmit_msgs))) {
+		entry = kcs_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(kcs_info->xmit_msgs))) {
+		entry = kcs_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		kcs_info->curr_msg = NULL;
+		rv = KCS_SM_IDLE;
+	} else {
+		int err;
+
+		list_del(entry);
+		kcs_info->curr_msg = list_entry(entry,
+						struct ipmi_smi_msg,
+						link);
+#ifdef DEBUG_TIMING
+		do_gettimeofday(&t);
+		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+		err = start_kcs_transaction(kcs_info->kcs_sm,
+					   kcs_info->curr_msg->data,
+					   kcs_info->curr_msg->data_size);
+		if (err) {
+			return_hosed_msg(kcs_info);
+		}
+
+		rv = KCS_CALL_WITHOUT_DELAY;
+	}
+	spin_unlock(&(kcs_info->msg_lock));
+
+	return rv;
+}
+
+static void start_enable_irq(struct kcs_info *kcs_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   BMC to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+	kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS1;
+}
+
+static void start_clear_flags(struct kcs_info *kcs_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 3);
+	kcs_info->kcs_state = KCS_CLEARING_FLAGS;
+}
+
+/* When we have a situtaion where we run out of memory and cannot
+   allocate messages, we just leave them in the BMC and run the system
+   polled until we can allocate some memory.  Once we have some
+   memory, we will re-enable the interrupt. */
+static inline void disable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (!kcs_info->interrupt_disabled)) {
+		disable_irq_nosync(kcs_info->irq);
+		kcs_info->interrupt_disabled = 1;
+	}
+}
+
+static inline void enable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (kcs_info->interrupt_disabled)) {
+		enable_irq(kcs_info->irq);
+		kcs_info->interrupt_disabled = 0;
+	}
+}
+
+static void handle_flags(struct kcs_info *kcs_info)
+{
+	if (kcs_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		start_clear_flags(kcs_info);
+		kcs_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+		spin_unlock(&(kcs_info->kcs_lock));
+		ipmi_smi_watchdog_pretimeout(kcs_info->intf);
+		spin_lock(&(kcs_info->kcs_lock));
+	} else if (kcs_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_MESSAGES;
+	} else if (kcs_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_EVENTS;
+	} else {
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+
+	do_gettimeofday(&t);
+	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	switch (kcs_info->kcs_state) {
+	case KCS_NORMAL:
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+		
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		deliver_recv_msg(kcs_info, msg);
+		break;
+		
+	case KCS_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+		unsigned int  len;
+
+		/* We got the flags from the KCS, now handle them. */
+		len = kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			/* Error fetching flags, just give up for
+			   now. */
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else if (len < 3) {
+			/* Hmm, no flags.  That's technically illegal, but
+			   don't use uninitialized data. */
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			kcs_info->msg_flags = msg[3];
+			handle_flags(kcs_info);
+		}
+		break;
+	}
+
+	case KCS_CLEARING_FLAGS:
+	case KCS_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 3);
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_kcs: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (kcs_info->kcs_state == KCS_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(kcs_info);
+		else
+			kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+
+	case KCS_GETTING_EVENTS:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_GETTING_MESSAGES:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			start_kcs_transaction(kcs_info->kcs_sm, msg,3);
+			kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+	}
+}
+
+/* Called on timeouts and events.  Timeouts should pass the elapsed
+   time, interrupts should pass in zero. */
+static enum kcs_result kcs_event_handler(struct kcs_info *kcs_info, int time)
+{
+	enum kcs_result kcs_result;
+
+ restart:
+	/* There used to be a loop here that waited a little while
+	   (around 25us) before giving up.  That turned out to be
+	   pointless, the minimum delays I was seeing were in the 300us
+	   range, which is far too long to wait in an interrupt.  So
+	   we just run until the state machine tells us something
+	   happened or it needs a delay. */
+	kcs_result = kcs_event(kcs_info->kcs_sm, time);
+	time = 0;
+	while (kcs_result == KCS_CALL_WITHOUT_DELAY)
+	{
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+
+	if (kcs_result == KCS_TRANSACTION_COMPLETE)
+	{
+		handle_transaction_done(kcs_info);
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+	else if (kcs_result == KCS_SM_HOSED)
+	{
+		if (kcs_info->curr_msg != NULL) {
+			/* If we were handling a user message, format
+                           a response to send to the upper layer to
+                           tell it about the error. */
+			return_hosed_msg(kcs_info);
+		}
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+
+	/* We prefer handling attn over new messages. */
+	if (kcs_result == KCS_ATTN)
+	{
+		unsigned char msg[2];
+
+		/* Got a attn, send down a get message flags to see
+                   what's causing it.  It would be better to handle
+                   this in the upper layer, but due to the way
+                   interrupts work with the KCS, that's not really
+                   possible. */
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	/* If we are currently idle, try to start the next message. */
+	if (kcs_result == KCS_SM_IDLE) {
+		kcs_result = start_next_msg(kcs_info);
+		if (kcs_result != KCS_SM_IDLE)
+			goto restart;
+        }
+
+	if ((kcs_result == KCS_SM_IDLE)
+	    && (atomic_read(&kcs_info->req_events)))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		atomic_set(&kcs_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	return kcs_result;
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->msg_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+
+	if (kcs_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+
+		/* We have to release the msg lock and claim the kcs
+		   lock in this case, because of race conditions. */
+		spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+		spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+		return;
+	} else {
+		if (priority > 0) {
+			list_add_tail(&(msg->link), &(kcs_info->hp_xmit_msgs));
+		} else {
+			list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+		}
+	}
+	spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if ((kcs_info->kcs_state == KCS_NORMAL)
+	    && (kcs_info->curr_msg == NULL))
+	{
+		start_next_msg(kcs_info);
+	}
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->run_to_completion = i_run_to_completion;
+	if (i_run_to_completion) {
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+	}
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void request_events(void *send_info)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+
+	atomic_set(&kcs_info->req_events, 1);
+}
+
+static int new_user(void *send_info)
+{
+	if (!try_inc_mod_count(THIS_MODULE))
+		return -EBUSY;
+	return 0;
+}
+
+static void user_left(void *send_info)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* Call every 10 ms. */
+#define KCS_TIMEOUT_TIME_USEC	10000
+#define KCS_USEC_PER_JIFFY	(1000000/HZ)
+#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
+#define KCS_SHORT_TIMEOUT_USEC  500 /* .5ms when the SM request a
+                                       short timeout */
+static int initialized = 0;
+
+static void kcs_timeout(unsigned long data)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	enum kcs_result kcs_result;
+	unsigned long   flags;
+	unsigned long   jiffies_now;
+	unsigned long   time_diff;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	if (kcs_info->stop_operation) {
+		kcs_info->timer_stopped = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	jiffies_now = jiffies;
+	time_diff = ((jiffies_now - kcs_info->last_timeout_jiffies)
+		     * KCS_USEC_PER_JIFFY);
+	kcs_result = kcs_event_handler(kcs_info, time_diff);
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->last_timeout_jiffies = jiffies_now;
+
+	if ((kcs_info->irq) && (! kcs_info->interrupt_disabled)) {
+		/* Running with interrupts, only do long timeouts. */
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+		goto do_add_timer;
+	}
+
+	/* If the state machine asks for a short delay, then shorten
+           the timer timeout. */
+#ifdef CONFIG_HIGH_RES_TIMERS
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.sub_expires
+			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
+		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
+			kcs_info->kcs_timer.expires++;
+			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
+		}
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#else
+	/* If requested, take the shortest delay possible */
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.expires = jiffies + 1;
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#endif
+
+ do_add_timer:
+	add_timer(&(kcs_info->kcs_timer));
+}
+
+static void kcs_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if (kcs_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	kcs_event_handler(kcs_info, 0);
+ out:
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	sender:		       sender,
+	request_events:        request_events,
+	new_user:	       new_user,
+	user_left:	       user_left,
+	set_run_to_completion: set_run_to_completion
+};
+
+static unsigned char ipmi_kcs_dev_rev;
+static unsigned char ipmi_kcs_fw_rev_major;
+static unsigned char ipmi_kcs_fw_rev_minor;
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+extern int kcs_dbg;
+static int ipmi_kcs_detect_hardware(unsigned int port,
+				    unsigned char *addr,
+				    struct kcs_data *data)
+{
+	unsigned char   msg[2];
+	unsigned char   resp[IPMI_MAX_MSG_LENGTH];
+	unsigned long   resp_len;
+	enum kcs_result kcs_result;
+
+	/* It's impossible for the KCS status register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+
+	if (port) {
+		if (inb(port+1) == 0xff) return -ENODEV; 
+	} else { 
+		if (readb(addr+1) == 0xff) return -ENODEV; 
+	}
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	start_kcs_transaction(data, msg, 2);
+	
+	kcs_result = kcs_event(data, 0);
+	for (;;)
+	{
+		if (kcs_result == KCS_CALL_WITH_DELAY) {
+			udelay(100);
+			kcs_result = kcs_event(data, 100);
+		}
+		else if (kcs_result == KCS_CALL_WITHOUT_DELAY)
+		{
+			kcs_result = kcs_event(data, 0);
+		}
+		else
+			break;
+	}
+	if (kcs_result == KCS_SM_HOSED) {
+		/* We couldn't get the state machine to run, so whatever's at
+		   the port is probably not an IPMI KCS interface. */
+		return -ENODEV;
+	}
+	/* Otherwise, we got some data. */
+	resp_len = kcs_get_result(data, resp, IPMI_MAX_MSG_LENGTH);
+	if (resp_len < 6)
+		/* That's odd, it should be longer. */
+		return -EINVAL;
+	
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0))
+		/* That's odd, it shouldn't be able to fail. */
+		return -EINVAL;
+	
+	ipmi_kcs_dev_rev = resp[4] & 0xf;
+	ipmi_kcs_fw_rev_major = resp[5] & 0x7f;
+	ipmi_kcs_fw_rev_minor = resp[6];
+	ipmi_version_major = resp[7] & 0xf;
+	ipmi_version_minor = resp[7] >> 4;
+
+	return 0;
+}
+
+/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+   a default IO port, and 1 ACPI/SPMI address.  That sets KCS_MAX_DRIVERS */
+
+#define KCS_MAX_PARMS 4
+#define KCS_MAX_DRIVERS ((KCS_MAX_PARMS * 2) + 2)
+static struct kcs_info *kcs_infos[KCS_MAX_DRIVERS] =
+{ NULL, NULL, NULL, NULL };
+
+#define DEVICE_NAME "ipmi_kcs"
+
+#define DEFAULT_IO_PORT 0xca2
+
+static int kcs_trydefaults = 1;
+static unsigned long kcs_addrs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_ports[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_irqs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+
+MODULE_PARM(kcs_trydefaults, "i");
+MODULE_PARM(kcs_addrs, "1-4l");
+MODULE_PARM(kcs_irqs, "1-4i");
+MODULE_PARM(kcs_ports, "1-4i");
+
+/* Returns 0 if initialized, or negative on an error. */
+static int init_one_kcs(int kcs_port, 
+			int irq, 
+			unsigned long kcs_physaddr,
+			struct kcs_info **kcs)
+{
+	int		rv;
+	struct kcs_info *new_kcs;
+
+	/* Did anything get passed in at all?  Both == zero disables the
+	   driver. */
+
+	if (!(kcs_port || kcs_physaddr)) 
+		return -ENODEV;
+	
+	/* Only initialize a port OR a physical address on this call.
+	   Also, IRQs can go with either ports or addresses. */
+
+	if (kcs_port && kcs_physaddr)
+		return -EINVAL;
+
+	new_kcs = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* So we know not to free it unless we have allocated one. */
+	new_kcs->kcs_sm = NULL;
+
+	new_kcs->addr = NULL;
+	new_kcs->physaddr = kcs_physaddr;
+	new_kcs->port = kcs_port;
+
+	if (kcs_port) {
+		if (request_region(kcs_port, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve port @ 0x%4.4x\n",
+		       	       kcs_port);
+			return -EIO;
+		}
+	} else {
+		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve memory @ 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+		if ((new_kcs->addr = ioremap(kcs_physaddr, 2)) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't remap memory at 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+	}
+
+	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs->kcs_sm) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		rv = -ENOMEM;
+		goto out_err;
+	}
+	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);
+	spin_lock_init(&(new_kcs->kcs_lock));
+	spin_lock_init(&(new_kcs->msg_lock));
+
+	rv = ipmi_kcs_detect_hardware(kcs_port, new_kcs->addr, new_kcs->kcs_sm);
+	if (rv) {
+		if (kcs_port) 
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ port 0x%4.4x\n", 
+			       kcs_port);
+		else
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ addr 0x%lx\n", 
+			       kcs_physaddr);
+		goto out_err;
+	}
+
+	if (irq != 0) {
+		rv = request_irq(irq,
+				 kcs_irq_handler,
+				 SA_INTERRUPT,
+				 DEVICE_NAME,
+				 new_kcs);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: %s unable to claim interrupt %d,"
+			       " running polled\n",
+			       DEVICE_NAME, irq);
+			irq = 0;
+		}
+	}
+	new_kcs->irq = irq;
+
+	INIT_LIST_HEAD(&(new_kcs->xmit_msgs));
+	INIT_LIST_HEAD(&(new_kcs->hp_xmit_msgs));
+	new_kcs->curr_msg = NULL;
+	atomic_set(&new_kcs->req_events, 0);
+	new_kcs->run_to_completion = 0;
+
+	start_clear_flags(new_kcs);
+
+	if (irq) {
+		new_kcs->kcs_state = KCS_CLEARING_FLAGS_THEN_SET_IRQ;
+
+		printk(KERN_INFO 
+		       "ipmi_kcs: Acquiring BMC @ port=0x%x irq=%d\n",
+		       kcs_port, irq);
+
+	} else {
+		if (kcs_port)
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ port=0x%x\n",
+		       	       kcs_port);
+		else
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ addr=0x%lx\n",
+		       	       kcs_physaddr);
+	}
+
+	rv = ipmi_register_smi(&handlers,
+			       new_kcs,
+			       ipmi_version_major,
+			       ipmi_version_minor,
+			       &(new_kcs->intf));
+	if (rv) {
+		free_irq(irq, new_kcs);
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	new_kcs->interrupt_disabled = 0;
+	new_kcs->timer_stopped = 0;
+	new_kcs->stop_operation = 0;
+
+	init_timer(&(new_kcs->kcs_timer));
+	new_kcs->kcs_timer.data = (long) new_kcs;
+	new_kcs->kcs_timer.function = kcs_timeout;
+	new_kcs->last_timeout_jiffies = jiffies;
+	new_kcs->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	add_timer(&(new_kcs->kcs_timer));
+
+	*kcs = new_kcs;
+
+	return 0;
+
+ out_err:
+	if (kcs_port) 
+		release_region (kcs_port, 2);
+	if (new_kcs->addr) 
+		iounmap(new_kcs->addr);
+	if (kcs_physaddr) 
+		release_mem_region(kcs_physaddr, 2);
+	if (new_kcs->kcs_sm)
+		kfree(new_kcs->kcs_sm);
+	kfree(new_kcs);
+	return rv;
+}
+
+#ifdef CONFIG_ACPI
+
+/* Retrieve the base physical address from ACPI tables.  Originally
+   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
+
+#include <linux/acpi.h>
+/* A real hack, but everything's not there yet in 2.4. */
+#define COMPILER_DEPENDENT_UINT64 unsigned long
+#include <../drivers/acpi/include/acpi.h>
+#include <../drivers/acpi/include/actypes.h>
+
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	s16	InterfaceType;
+	s16	SpecificationRevision;
+	u8	InterruptType;
+	u8	GPE;
+	s16	Reserved;
+	u64	GlobalSystemInterrupt;
+	u8	BaseAddress[12];
+	u8	UID[4];
+} __attribute__ ((packed));
+
+static unsigned long acpi_find_bmc(void)
+{
+	acpi_status       status;
+	acpi_table_header *spmi;
+	static unsigned long io_base = 0;
+
+	if (io_base != 0)
+		return io_base;
+
+	status = acpi_get_firmware_table("SPMI", 1,
+			ACPI_LOGICAL_ADDRESSING, &spmi);
+
+	if (status != AE_OK) {
+		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");
+		return 0;
+	}
+
+	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
+			sizeof(io_base));
+	
+	return io_base;
+}
+#endif
+
+static __init int init_ipmi_kcs(void)
+{
+	int		rv = 0;
+	int		pos = 0;
+	int		i = 0;
+#ifdef CONFIG_ACPI
+	unsigned long	physaddr = 0;
+#endif
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	/* First do the "command-line" parameters */
+
+	for (i=0; i < KCS_MAX_PARMS; i++) {
+		rv = init_one_kcs(kcs_ports[i], 
+				  kcs_irqs[i], 
+				  0, 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+
+		rv = init_one_kcs(0, 
+				  kcs_irqs[i], 
+				  kcs_addrs[i], 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+	}
+
+	/* Only try the defaults if enabled and resources are available
+	   (because they weren't already specified above). */
+
+	if (kcs_trydefaults) {
+#ifdef CONFIG_ACPI
+		if ((physaddr = acpi_find_bmc())) {
+			if (!check_mem_region(physaddr, 2)) {
+				rv = init_one_kcs(0, 
+						  0, 
+						  physaddr, 
+						  &(kcs_infos[pos]));
+				if (rv == 0)
+					pos++;
+			}
+		}
+#endif
+		if (!check_region(DEFAULT_IO_PORT, 2)) {
+			rv = init_one_kcs(DEFAULT_IO_PORT, 
+					  0, 
+					  0, 
+					  &(kcs_infos[pos]));
+			if (rv == 0)
+				pos++;
+		}
+	}
+
+	if (kcs_infos[0] == NULL) {
+		printk("ipmi_kcs: Unable to find any KCS interfaces\n");
+		return -ENODEV;
+	} 
+
+	return 0;
+}
+module_init(init_ipmi_kcs);
+
+#ifdef MODULE
+void __exit cleanup_one_kcs(struct kcs_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+
+	if (! to_clean)
+		return;
+
+	/* Tell the timer and interrupt handlers that we are shutting
+	   down. */
+	spin_lock_irqsave(&(to_clean->kcs_lock), flags);
+	spin_lock(&(to_clean->msg_lock));
+
+	to_clean->stop_operation = 1;
+
+	if (to_clean->irq != 0)
+		free_irq(to_clean->irq, to_clean);
+	if (to_clean->port) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ port=0x%x\n",
+		       to_clean->port);
+		release_region (to_clean->port, 2);
+	}
+	if (to_clean->addr) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ addr=0x%lx\n",
+		       to_clean->physaddr);
+		iounmap(to_clean->addr);
+		release_mem_region(to_clean->physaddr, 2);
+	}
+
+	spin_unlock(&(to_clean->msg_lock));
+	spin_unlock_irqrestore(&(to_clean->kcs_lock), flags);
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here.  Hopefully this will be
+	   long enough to avoid problems with interrupts still
+	   running. */
+	schedule_timeout(2);
+	while (!to_clean->timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+
+	initialized = 0;
+
+	kfree(to_clean->kcs_sm);
+	kfree(to_clean);
+}
+
+static __exit void cleanup_ipmi_kcs(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<KCS_MAX_DRIVERS; i++) {
+		cleanup_one_kcs(kcs_infos[i]);
+	}
+}
+module_exit(cleanup_ipmi_kcs);
+#else
+
+/* Unfortunately, cmdline::get_options() only returns integers, not
+   longs.  Since we need ulongs (64-bit physical addresses) parse the 
+   comma-separated list manually.  Arguments can be one of these forms:
+   m0xaabbccddeeff	A physical memory address without an IRQ
+   m0xaabbccddeeff:cc	A physical memory address with an IRQ
+   p0xaabb		An IO port without an IRQ
+   p0xaabb:cc		An IO port with an IRQ
+   nodefaults		Suppress trying the default IO port or ACPI address 
+
+   For example, to pass one IO port with an IRQ, one address, and 
+   suppress the use of the default IO port and ACPI address,
+   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults
+
+   Remember, ipmi_kcs_setup() is passed the string after the equal sign. */
+
+static int __init ipmi_kcs_setup(char *str)
+{
+	unsigned long val;
+	char *cur, *colon;
+	int pos;
+
+	pos = 0;
+	
+	cur = strsep(&str, ",");
+	while ((cur) && (*cur) && (pos < KCS_MAX_PARMS)) {
+		switch (*cur) {
+		case 'n':
+			if (strcmp(cur, "nodefaults") == 0)
+				kcs_trydefaults = 0;
+			else
+				printk(KERN_INFO 
+				       "ipmi_kcs: bad parameter value %s\n",
+				       cur);
+			break;
+		
+		case 'm':
+		case 'p':
+			val = simple_strtoul(cur + 1,
+					     &colon,
+					     0);
+			if (*cur == 'p')
+				kcs_ports[pos] = val;
+			else
+				kcs_addrs[pos] = val;
+			if (*colon == ':') {
+				val = simple_strtoul(colon + 1,
+						     &colon,
+						     0);
+				kcs_irqs[pos] = val;
+			}
+			pos++;
+			break;
+
+		default:
+			printk(KERN_INFO 
+			       "ipmi_kcs: bad parameter value %s\n",
+			       cur);
+		}
+		cur = strsep(&str, ",");
+	}
+
+	return 1;
+}
+__setup("ipmi_kcs=", ipmi_kcs_setup);
+#endif
+
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.c linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_sm.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_sm.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,485 @@
+/*
+ * ipmi_kcs_sm.c
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This state machine is taken from the state machine in the IPMI spec,
+ * pretty much verbatim.  If you have questions about the states, see
+ * that document.
+ */
+
+#include <asm/io.h>
+#include <asm/string.h>		/* Gets rid of memcpy warning */
+
+#include "ipmi_kcs_sm.h"
+
+/* Set this if you want a printout of why the state machine was hosed
+   when it gets hosed. */
+#define DEBUG_HOSED_REASON
+
+/* Print the state machine state on entry every time. */
+#undef DEBUG_STATE
+
+/* The states the KCS driver may be in. */
+enum kcs_states {
+	KCS_IDLE,		/* The KCS interface is currently
+                                   doing nothing. */
+	KCS_START_OP,		/* We are starting an operation.  The
+				   data is in the output buffer, but
+				   nothing has been done to the
+				   interface yet.  This was added to
+				   the state machine in the spec to
+				   wait for the initial IBF. */
+	KCS_WAIT_WRITE_START,	/* We have written a write cmd to the
+				   interface. */
+	KCS_WAIT_WRITE,		/* We are writing bytes to the
+                                   interface. */
+	KCS_WAIT_WRITE_END,	/* We have written the write end cmd
+                                   to the interface, and still need to
+                                   write the last byte. */
+	KCS_WAIT_READ,		/* We are waiting to read data from
+				   the interface. */
+	KCS_ERROR0,		/* State to transition to the error
+				   handler, this was added to the
+				   state machine in the spec to be
+				   sure IBF was there. */
+	KCS_ERROR1,		/* First stage error handler, wait for
+                                   the interface to respond. */
+	KCS_ERROR2,		/* The abort cmd has been written,
+				   wait for the interface to
+				   respond. */
+	KCS_ERROR3,		/* We wrote some data to the
+				   interface, wait for it to switch to
+				   read mode. */
+	KCS_HOSED		/* The hardware failed to follow the
+				   state machine. */
+};
+
+#define MAX_KCS_READ_SIZE 80
+#define MAX_KCS_WRITE_SIZE 80
+
+/* Timeouts in microseconds. */
+#define IBF_RETRY_TIMEOUT 1000000
+#define OBF_RETRY_TIMEOUT 1000000
+#define MAX_ERROR_RETRIES 10
+
+#define IPMI_ERR_MSG_TRUNCATED	0xc6
+#define IPMI_ERR_UNSPECIFIED	0xff
+
+struct kcs_data
+{
+	enum kcs_states state;
+	unsigned int    port;
+	unsigned char	*addr;
+	unsigned char   write_data[MAX_KCS_WRITE_SIZE];
+	int             write_pos;
+	int             write_count;
+	int             orig_write_count;
+	unsigned char   read_data[MAX_KCS_READ_SIZE];
+	int             read_pos;
+	int	        truncated;
+
+	unsigned int  error_retries;
+	long          ibf_timeout;
+	long          obf_timeout;
+};
+
+void init_kcs_data(struct kcs_data *kcs, unsigned int port, unsigned char *addr)
+{
+	kcs->state = KCS_IDLE;
+	kcs->port = port;
+	kcs->addr = addr;
+	kcs->write_pos = 0;
+	kcs->write_count = 0;
+	kcs->orig_write_count = 0;
+	kcs->read_pos = 0;
+	kcs->error_retries = 0;
+	kcs->truncated = 0;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+}
+
+/* Remember, init_one_kcs() insured port and addr can't both be set */
+
+static inline unsigned char read_status(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 1);
+        else
+		return readb(kcs->addr + 1);
+}
+
+static inline unsigned char read_data(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 0);
+        else
+		return readb(kcs->addr + 0);
+}
+
+static inline void write_cmd(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 1);
+        else
+		writeb(data, kcs->addr + 1);
+}
+
+static inline void write_data(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 0);
+        else
+		writeb(data, kcs->addr + 0);
+}
+
+/* Control codes. */
+#define KCS_GET_STATUS_ABORT	0x60
+#define KCS_WRITE_START		0x61
+#define KCS_WRITE_END		0x62
+#define KCS_READ_BYTE		0x68
+
+/* Status bits. */
+#define GET_STATUS_STATE(status) (((status) >> 6) & 0x03)
+#define KCS_IDLE_STATE	0
+#define KCS_READ_STATE	1
+#define KCS_WRITE_STATE	2
+#define KCS_ERROR_STATE	3
+#define GET_STATUS_ATN(status) ((status) & 0x04)
+#define GET_STATUS_IBF(status) ((status) & 0x02)
+#define GET_STATUS_OBF(status) ((status) & 0x01)
+
+
+static inline void write_next_byte(struct kcs_data *kcs)
+{
+	write_data(kcs, kcs->write_data[kcs->write_pos]);
+	(kcs->write_pos)++;
+	(kcs->write_count)--;
+}
+
+static inline void start_error_recovery(struct kcs_data *kcs, char *reason)
+{
+	(kcs->error_retries)++;
+	if (kcs->error_retries > MAX_ERROR_RETRIES) {
+#ifdef DEBUG_HOSED_REASON
+		printk("ipmi_kcs_sm: kcs hosed: %s\n", reason);
+#endif
+		kcs->state = KCS_HOSED;
+	} else {
+		kcs->state = KCS_ERROR0;
+	}
+}
+
+static inline void read_next_byte(struct kcs_data *kcs)
+{
+	if (kcs->read_pos >= MAX_KCS_READ_SIZE) {
+		/* Throw the data away and mark it truncated. */
+		read_data(kcs);
+		kcs->truncated = 1;
+	} else {
+		kcs->read_data[kcs->read_pos] = read_data(kcs);
+		(kcs->read_pos)++;
+	}
+	write_data(kcs, KCS_READ_BYTE);
+}
+
+static inline int check_ibf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (GET_STATUS_IBF(status)) {
+		kcs->ibf_timeout -= time;
+		if (kcs->ibf_timeout < 0) {
+			start_error_recovery(kcs, "IBF not ready in time");
+			kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+			return 1;
+		}
+		return 0;
+	}
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static inline int check_obf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (! GET_STATUS_OBF(status)) {
+		kcs->obf_timeout -= time;
+		if (kcs->obf_timeout < 0) {
+		    start_error_recovery(kcs, "OBF not ready in time");
+		    return 1;
+		}
+		return 0;
+	}
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static void clear_obf(struct kcs_data *kcs, unsigned char status)
+{
+	if (GET_STATUS_OBF(status))
+		read_data(kcs);
+}
+
+static void restart_kcs_transaction(struct kcs_data *kcs)
+{
+	kcs->write_count = kcs->orig_write_count;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_WAIT_WRITE_START;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	write_cmd(kcs, KCS_WRITE_START);
+}
+
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size)
+{
+	if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
+		return -1;
+	}
+
+	if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) {
+		return -2;
+	}
+
+	kcs->error_retries = 0;
+	memcpy(kcs->write_data, data, size);
+	kcs->write_count = size;
+	kcs->orig_write_count = size;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_START_OP;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 0;
+}
+
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length)
+{
+	if (length < kcs->read_pos) {
+		kcs->read_pos = length;
+		kcs->truncated = 1;
+	}
+
+	memcpy(data, kcs->read_data, kcs->read_pos);
+
+	if ((length >= 3) && (kcs->read_pos < 3)) {
+		/* Guarantee that we return at least 3 bytes, with an
+		   error in the third byte if it is too short. */
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		kcs->read_pos = 3;
+	}
+	if (kcs->truncated) {
+		/* Report a truncated error.  We might overwrite
+		   another error, but that's too bad, the user needs
+		   to know it was truncated. */
+		data[2] = IPMI_ERR_MSG_TRUNCATED;
+		kcs->truncated = 0;
+	}
+
+	return kcs->read_pos;
+}
+
+/* This implements the state machine defined in the IPMI manual, see
+   that for details on how this works.  Divide that flowchart into
+   sections delimited by "Wait for IBF" and this will become clear. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time)
+{
+	unsigned char status;
+	unsigned char state;
+
+	status = read_status(kcs);
+
+#ifdef DEBUG_STATE
+	printk("  State = %d, %x\n", kcs->state, status);
+#endif
+	/* All states wait for ibf, so just do it here. */
+	if (!check_ibf(kcs, status, time))
+		return KCS_CALL_WITH_DELAY;
+
+	/* Just about everything looks at the KCS state, so grab that, too. */
+	state = GET_STATUS_STATE(status);
+
+	switch (kcs->state) {
+	case KCS_IDLE:
+		/* If there's and interrupt source, turn it off. */
+		clear_obf(kcs, status);
+
+		if (GET_STATUS_ATN(status))
+			return KCS_ATTN;
+		else
+			return KCS_SM_IDLE;
+
+	case KCS_START_OP:
+		if (state != KCS_IDLE) {
+			start_error_recovery(kcs,
+					     "State machine not idle at start");
+			break;
+		}
+
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_WRITE_START);
+		kcs->state = KCS_WAIT_WRITE_START;
+		break;
+
+	case KCS_WAIT_WRITE_START:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(
+				kcs,
+				"Not in write state at write start");
+			break;
+		}
+		read_data(kcs);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+			kcs->state = KCS_WAIT_WRITE;
+		}
+		break;
+
+	case KCS_WAIT_WRITE:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write");
+			break;
+		}
+		clear_obf(kcs, status);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+		}
+		break;
+		
+	case KCS_WAIT_WRITE_END:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write end");
+			break;
+		}
+		clear_obf(kcs, status);
+		write_next_byte(kcs);
+		kcs->state = KCS_WAIT_READ;
+		break;
+
+	case KCS_WAIT_READ:
+		if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) {
+			start_error_recovery(
+				kcs,
+				"Not in read or idle in read state");
+			break;
+		}
+
+		if (state == KCS_READ_STATE) {
+			if (! check_obf(kcs, status, time))
+				return KCS_CALL_WITH_DELAY;
+			read_next_byte(kcs);
+		} else {
+			/* We don't implement this exactly like the state
+			   machine in the spec.  Some broken hardware
+			   does not write the final dummy byte to the
+			   read register.  Thus obf will never go high
+			   here.  We just go straight to idle, and we
+			   handle clearing out obf in idle state if it
+			   happens to come in. */
+			clear_obf(kcs, status);
+			kcs->orig_write_count = 0;
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+
+	case KCS_ERROR0:
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_GET_STATUS_ABORT);
+		kcs->state = KCS_ERROR1;
+		break;
+
+	case KCS_ERROR1:
+		clear_obf(kcs, status);
+		write_data(kcs, 0);
+		kcs->state = KCS_ERROR2;
+		break;
+		
+	case KCS_ERROR2:
+		if (state != KCS_READ_STATE) {
+			start_error_recovery(kcs,
+					     "Not in read state for error2");
+			break;
+		}
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		write_data(kcs, KCS_READ_BYTE);
+		kcs->state = KCS_ERROR3;
+		break;
+		
+	case KCS_ERROR3:
+		if (state != KCS_IDLE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in idle state for error3");
+			break;
+		}
+
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		if (kcs->orig_write_count) {
+			restart_kcs_transaction(kcs);
+		} else {
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+			
+	case KCS_HOSED:
+		return KCS_SM_HOSED;
+	}
+
+	if (kcs->state == KCS_HOSED) {
+		init_kcs_data(kcs, kcs->port, kcs->addr);
+		return KCS_SM_HOSED;
+	}
+
+	return KCS_CALL_WITHOUT_DELAY;
+}
+
+int kcs_size(void)
+{
+	return sizeof(struct kcs_data);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.h linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_sm.h
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_kcs_sm.h	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ * ipmi_kcs_sm.h
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+struct kcs_data;
+
+void init_kcs_data(struct kcs_data *kcs,
+		   unsigned int    port,
+		   unsigned char   *addr);
+
+/* Start a new transaction in the state machine.  This will return -2
+   if the state machine is not idle, -1 if the size is invalid (to
+   large or too small), or 0 if the transaction is successfully
+   completed. */
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size);
+
+/* Return the results after the transaction.  This will return -1 if
+   the buffer is too small, zero if no transaction is present, or the
+   actual length of the result data. */
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length);
+
+enum kcs_result
+{
+	KCS_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+	KCS_CALL_WITH_DELAY,	/* Delay some before calling again. */
+	KCS_TRANSACTION_COMPLETE, /* A transaction is finished. */
+	KCS_SM_IDLE,		/* The SM is in idle state. */
+	KCS_SM_HOSED,		/* The hardware violated the state machine. */
+	KCS_ATTN		/* The hardware is asserting attn and the
+				   state machine is idle. */
+};
+
+/* Call this periodically (for a polled interface) or upon receiving
+   an interrupt (for a interrupt-driven interface).  If interrupt
+   driven, you should probably poll this periodically when not in idle
+   state.  This should be called with the time that passed since the
+   last call, if it is significant.  Time is in microseconds. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time);
+
+/* Return the size of the KCS structure in bytes. */
+int kcs_size(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_msghandler.c linux-2.4.21-rc3/drivers/char/ipmi/ipmi_msghandler.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_msghandler.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_msghandler.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,1982 @@
+/*
+ * ipmi_msghandler.c
+ *
+ * Incoming and outgoing message routing for an IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+static int ipmi_init_msghandler(void);
+
+static int initialized = 0;
+
+#define MAX_EVENTS_IN_QUEUE	25
+
+/* Don't let a message sit in a queue forever, always time it with at lest
+   the max message timer. */
+#define MAX_MSG_TIMEOUT		60000
+
+struct ipmi_user
+{
+	struct list_head link;
+
+	/* The upper layer that handles receive messages. */
+	struct ipmi_user_hndl *handler;
+	void             *handler_data;
+
+	/* The interface this user is bound to. */
+	ipmi_smi_t intf;
+
+	/* Does this interface receive IPMI events? */
+	int gets_events;
+};
+
+struct cmd_rcvr
+{
+	struct list_head link;
+
+	ipmi_user_t   user;
+	unsigned char netfn;
+	unsigned char cmd;
+};
+
+struct seq_table
+{
+	int                  inuse : 1;
+
+	unsigned long        timeout;
+	unsigned long        orig_timeout;
+	unsigned int         retries_left;
+
+	/* To verify on an incoming send message response that this is
+           the message that the response is for, we keep a sequence id
+           and increment it every time we send a message. */
+	long                 seqid;
+
+	/* This is held so we can properly respond to the message on a
+           timeout, and it is used to hold the temporary data for
+           retransmission, too. */
+	struct ipmi_recv_msg *recv_msg;
+};
+
+/* Store the information in a msgid (long) to allow us to find a
+   sequence table entry from the msgid. */
+#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
+
+#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
+	do {								\
+		seq = ((msgid >> 26) & 0x3f);				\
+		seqid = (msgid & 0x3fffff);				\
+        } while(0)
+
+#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
+
+
+#define IPMI_IPMB_NUM_SEQ	64
+struct ipmi_smi
+{
+	/* The list of upper layers that are using me.  We read-lock
+           this when delivering messages to the upper layer to keep
+           the user from going away while we are processing the
+           message.  This means that you cannot add or delete a user
+           from the receive callback. */
+	rwlock_t                users_lock;
+	struct list_head        users;
+
+	/* The IPMI version of the BMC on the other end. */
+	unsigned char       version_major;
+	unsigned char       version_minor;
+
+	/* This is the lower-layer's sender routine. */
+	struct ipmi_smi_handlers *handlers;
+	void                     *send_info;
+
+	/* A table of sequence numbers for this interface.  We use the
+           sequence numbers for IPMB messages that go out of the
+           interface to match them up with their responses.  A routine
+           is called periodically to time the items in this list. */
+	spinlock_t       seq_lock;
+	struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
+	int curr_seq;
+
+	/* Messages that were delayed for some reason (out of memory,
+           for instance), will go in here to be processed later in a
+           periodic timer interrupt. */
+	spinlock_t       waiting_msgs_lock;
+	struct list_head waiting_msgs;
+
+	/* The list of command receivers that are registered for commands
+	   on this interface. */
+	rwlock_t	 cmd_rcvr_lock;
+	struct list_head cmd_rcvrs;
+
+	/* Events that were queues because no one was there to receive
+           them. */
+	spinlock_t       events_lock; /* For dealing with event stuff. */
+	struct list_head waiting_events;
+	unsigned int     waiting_events_count; /* How many events in queue? */
+
+	/* This will be non-null if someone registers to receive all
+	   IPMI commands (this is for interface emulation).  There
+	   may not be any things in the cmd_rcvrs list above when
+	   this is registered. */
+	ipmi_user_t all_cmd_rcvr;
+
+	/* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
+	   but may be changed by the user. */
+	unsigned char my_address;
+
+	/* My LUN.  This should generally stay the SMS LUN, but just in
+	   case... */
+	unsigned char my_lun;
+};
+
+int
+ipmi_register_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EBUSY;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if ((user->intf->all_cmd_rcvr == NULL)
+	    && (list_empty(&(user->intf->cmd_rcvrs))))
+	{
+		user->intf->all_cmd_rcvr = user;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+int
+ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EINVAL;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if (user->intf->all_cmd_rcvr == user)
+	{
+		user->intf->all_cmd_rcvr = NULL;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+
+#define MAX_IPMI_INTERFACES 4
+static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
+
+/* Used to keep interfaces from going away while operations are
+   operating on interfaces.  Grab read if you are not modifying the
+   interfaces, write if you are. */
+static DECLARE_RWSEM(interfaces_sem);
+
+/* Directly protects the ipmi_interfaces data structure.  This is
+   claimed in the timer interrupt. */
+static spinlock_t interfaces_lock = SPIN_LOCK_UNLOCKED;
+
+/* List of watchers that want to know when smi's are added and
+   deleted. */
+static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static DECLARE_RWSEM(smi_watchers_sem);
+
+int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
+{
+	int i;
+
+	down_read(&interfaces_sem);
+	down_write(&smi_watchers_sem);
+	list_add(&(watcher->link), &smi_watchers);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] != NULL) {
+			watcher->new_smi(i);
+		}
+	}
+	up_write(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
+{
+	down_write(&smi_watchers_sem);
+	list_del(&(watcher->link));
+	up_write(&smi_watchers_sem);
+	return 0;
+}
+
+int
+ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
+{
+	if (addr1->addr_type != addr2->addr_type)
+		return 0;
+
+	if (addr1->channel != addr2->channel)
+		return 0;
+
+	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr1
+		    = (struct ipmi_system_interface_addr *) addr1;
+		struct ipmi_system_interface_addr *smi_addr2
+		    = (struct ipmi_system_interface_addr *) addr2;
+		return (smi_addr1->lun == smi_addr2->lun);
+	}
+
+	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr1
+		    = (struct ipmi_ipmb_addr *) addr1;
+		struct ipmi_ipmb_addr *ipmb_addr2
+		    = (struct ipmi_ipmb_addr *) addr2;
+
+		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
+			&& (ipmb_addr1->lun == ipmb_addr2->lun));
+	}
+
+	return 1;
+}
+
+int ipmi_validate_addr(struct ipmi_addr *addr, int len)
+{
+	if (len < sizeof(struct ipmi_system_interface_addr)) {
+		return -EINVAL;
+	}
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		if (addr->channel != IPMI_BMC_CHANNEL)
+			return -EINVAL;
+		return 0;
+	}
+
+	if ((addr->channel == IPMI_BMC_CHANNEL)
+	    || (addr->channel >= IPMI_NUM_CHANNELS)
+	    || (addr->channel < 0))
+		return -EINVAL;
+
+	if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		if (len < sizeof(struct ipmi_ipmb_addr)) {
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+unsigned int ipmi_addr_length(int addr_type)
+{
+	if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+		return sizeof(struct ipmi_system_interface_addr);
+
+	if ((addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		return sizeof(struct ipmi_ipmb_addr);
+	}
+
+	return 0;
+}
+
+static void deliver_response(struct ipmi_recv_msg *msg)
+{
+    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+}
+
+/* Find the next sequence number not being used and add the given
+   message with the given timeout to the sequence table.  This must be
+   called with the interface's seq_lock held. */
+static int intf_next_seq(ipmi_smi_t           intf,
+			 struct ipmi_recv_msg *recv_msg,
+			 unsigned long        timeout,
+			 int                  retries,
+			 unsigned char        *seq,
+			 long                 *seqid)
+{
+	int          rv = 0;
+	unsigned int i;
+
+	for (i=intf->curr_seq;
+	     (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
+	     i=(i+1)%IPMI_IPMB_NUM_SEQ)
+	{
+		if (! intf->seq_table[i].inuse)
+			break;
+	}
+
+	if (! intf->seq_table[i].inuse) {
+		intf->seq_table[i].recv_msg = recv_msg;
+
+		/* Start with the maximum timeout, when the send response
+		   comes in we will start the real timer. */
+		intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
+		intf->seq_table[i].orig_timeout = timeout;
+		intf->seq_table[i].retries_left = retries;
+		intf->seq_table[i].inuse = 1;
+		intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
+		*seq = i;
+		*seqid = intf->seq_table[i].seqid;
+		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
+	} else {
+		rv = -EAGAIN;
+	}
+	
+	return rv;
+}
+
+/* Return the receive message for the given sequence number and
+   release the sequence number so it can be reused.  Some other data
+   is passed in to be sure the message matches up correctly (to help
+   guard against message coming in after their timeout and the
+   sequence number being reused). */
+static int intf_find_seq(ipmi_smi_t           intf,
+			 unsigned char        seq,
+			 short                channel,
+			 unsigned char        cmd,
+			 unsigned char        netfn,
+			 struct ipmi_addr     *addr,
+			 struct ipmi_recv_msg **recv_msg)
+{
+	int           rv = -ENODEV;
+	unsigned long flags;
+
+	if (seq >= IPMI_IPMB_NUM_SEQ)
+		return -EINVAL;
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	if (intf->seq_table[seq].inuse) {
+		struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
+
+		if ((msg->addr.channel == channel)
+		    && (msg->msg.cmd == cmd)
+		    && (msg->msg.netfn == netfn)
+		    && (ipmi_addr_equal(addr, &(msg->addr))))
+		{
+			*recv_msg = msg;
+			intf->seq_table[seq].inuse = 0;
+			rv = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+
+/* Start the timer for a specific sequence table entry. */
+static int intf_start_seq_timer(ipmi_smi_t           intf,
+				long                 msgid)
+{
+	int           rv = -ENODEV;
+	unsigned long flags;
+	unsigned char seq;
+	unsigned long seqid;
+
+
+	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	/* We do this verification because the user can be deleted
+           while a message is outstanding. */
+	if ((intf->seq_table[seq].inuse)
+	    && (intf->seq_table[seq].seqid == seqid))
+	{
+		struct seq_table *ent = &(intf->seq_table[seq]);
+		ent->timeout = ent->orig_timeout;
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+
+int ipmi_create_user(unsigned int          if_num,
+		     struct ipmi_user_hndl *handler,
+		     void                  *handler_data,
+		     ipmi_user_t           *user)
+{
+	unsigned long flags;
+	ipmi_user_t   new_user;
+	int           rv = 0;
+
+	/* There is no module usecount here, because it's not
+           required.  Since this can only be used by and called from
+           other modules, they will implicitly use this module, and
+           thus this can't be removed unless the other modules are
+           removed. */
+
+	if (handler == NULL)
+		return -EINVAL;
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
+	if (! new_user)
+		return -ENOMEM;
+
+	down_read(&interfaces_sem);
+	if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)
+	{
+		rv = -EINVAL;
+		goto out_unlock;
+	}
+
+	new_user->handler = handler;
+	new_user->handler_data = handler_data;
+	new_user->intf = ipmi_interfaces[if_num];
+	new_user->gets_events = 0;
+
+	rv = new_user->intf->handlers->new_user(new_user->intf->send_info);
+	if (rv)
+		goto out_unlock;
+
+	write_lock_irqsave(&(new_user->intf->users_lock), flags);
+	list_add_tail(&(new_user->link), &(new_user->intf->users));
+	write_unlock_irqrestore(&(new_user->intf->users_lock), flags);
+
+ out_unlock:	
+	if (rv) {
+		kfree(new_user);
+	} else {
+		*user = new_user;
+	}
+
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+static int ipmi_destroy_user_nolock(ipmi_user_t user)
+{
+	int              rv = -ENODEV;
+	ipmi_user_t      t_user;
+	struct list_head *entry, *entry2;
+	int              i;
+	unsigned long    flags;
+
+	/* Find the user and delete them from the list. */
+	list_for_each(entry, &(user->intf->users)) {
+		t_user = list_entry(entry, struct ipmi_user, link);
+		if (t_user == user) {
+			list_del(entry);
+			rv = 0;
+			break;
+		}
+	}
+
+	if (rv) {
+		goto out_unlock;
+	}
+
+	/* Remove the user from the interfaces sequence table. */
+	spin_lock_irqsave(&(user->intf->seq_lock), flags);
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if (user->intf->seq_table[i].inuse
+		    && (user->intf->seq_table[i].recv_msg->user == user))
+		{
+			user->intf->seq_table[i].inuse = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(user->intf->seq_lock), flags);
+
+	/* Remove the user from the command receiver's table. */
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *rcvr;
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if (rcvr->user == user) {
+			list_del(entry);
+			kfree(rcvr);
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+
+	kfree(user);
+
+ out_unlock:
+
+	return rv;
+}
+
+int ipmi_destroy_user(ipmi_user_t user)
+{
+	int           rv;
+	ipmi_smi_t    intf = user->intf;
+	unsigned long flags;
+
+	down_read(&interfaces_sem);
+	write_lock_irqsave(&(intf->users_lock), flags);
+	rv = ipmi_destroy_user_nolock(user);
+	if (!rv)
+		intf->handlers->user_left(intf->send_info);
+		
+	write_unlock_irqrestore(&(intf->users_lock), flags);
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+void ipmi_get_version(ipmi_user_t   user,
+		      unsigned char *major,
+		      unsigned char *minor)
+{
+	*major = user->intf->version_major;
+	*minor = user->intf->version_minor;
+}
+
+void ipmi_set_my_address(ipmi_user_t   user,
+			 unsigned char address)
+{
+	user->intf->my_address = address;
+}
+
+unsigned char ipmi_get_my_address(ipmi_user_t user)
+{
+	return user->intf->my_address;
+}
+
+void ipmi_set_my_LUN(ipmi_user_t   user,
+		     unsigned char LUN)
+{
+	user->intf->my_lun = LUN & 0x3;
+}
+
+unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+{
+	return user->intf->my_lun;
+}
+
+int ipmi_set_gets_events(ipmi_user_t user, int val)
+{
+	unsigned long         flags;
+	struct list_head      *e, *e2;
+	struct ipmi_recv_msg  *msg;
+
+	read_lock(&(user->intf->users_lock));
+	spin_lock_irqsave(&(user->intf->events_lock), flags);
+	user->gets_events = val;
+
+	if (val) {
+		/* Deliver any queued events. */
+		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {
+			msg = list_entry(e, struct ipmi_recv_msg, link);
+			list_del(e);
+			msg->user = user;
+			deliver_response(msg);
+		}
+	}
+	
+	spin_unlock_irqrestore(&(user->intf->events_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return 0;
+}
+
+int ipmi_register_for_cmd(ipmi_user_t   user,
+			  unsigned char netfn,
+			  unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = 0;
+
+
+	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
+	if (! rcvr)
+		return -ENOMEM;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	if (user->intf->all_cmd_rcvr != NULL) {
+		rv = -EBUSY;
+		goto out_unlock;
+	}
+
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *cmp;
+		cmp = list_entry(entry, struct cmd_rcvr, link);
+		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
+			rv = -EBUSY;
+			break;
+		}
+	}
+
+	if (! rv) {
+		rcvr->cmd = cmd;
+		rcvr->netfn = netfn;
+		rcvr->user = user;
+		list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
+	}
+ out_unlock:
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	if (rv)
+		kfree(rcvr);
+
+	return rv;
+}
+
+int ipmi_unregister_for_cmd(ipmi_user_t   user,
+			    unsigned char netfn,
+			    unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = -ENOENT;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+			rv = 0;
+			list_del(entry);
+			kfree(rcvr);
+			break;
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return rv;
+}
+
+static unsigned char
+ipmb_checksum(unsigned char *data, int size)
+{
+	unsigned char csum = 0;
+	
+	for (; size > 0; size--, data++)
+		csum += *data;
+
+	return -csum;
+}
+
+static inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,
+				   struct ipmi_msg       *msg,
+				   struct ipmi_ipmb_addr *ipmb_addr,
+				   long                  msgid,
+				   unsigned char         ipmb_seq,
+				   int                   broadcast,
+				   unsigned char         source_address,
+				   unsigned char         source_lun)
+{
+	int i = broadcast;
+
+	/* Format the IPMB header data. */
+	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
+	smi_msg->data[2] = ipmb_addr->channel;
+	if (broadcast)
+		smi_msg->data[3] = 0;
+	smi_msg->data[i+3] = ipmb_addr->slave_addr;
+	smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
+	smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
+	smi_msg->data[i+6] = source_address;
+	smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
+	smi_msg->data[i+8] = msg->cmd;
+
+	/* Now tack on the data to the message. */
+	if (msg->data_len > 0)
+		memcpy(&(smi_msg->data[i+9]), msg->data,
+		       msg->data_len);
+	smi_msg->data_size = msg->data_len + 9;
+
+	/* Now calculate the checksum and tack it on. */
+	smi_msg->data[i+smi_msg->data_size]
+		= ipmb_checksum(&(smi_msg->data[i+6]),
+				smi_msg->data_size-6);
+
+	/* Add on the checksum size and the offset from the
+	   broadcast. */
+	smi_msg->data_size += 1 + i;
+
+	smi_msg->msgid = msgid;
+}
+
+/* Separate from ipmi_request so that the user does not have to be
+   supplied in certain circumstances (mainly at panic time).  If
+   messages are supplied, they will be freed, even if an error
+   occurs. */
+static inline int i_ipmi_request(ipmi_user_t          user,
+				 ipmi_smi_t           intf,
+				 struct ipmi_addr     *addr,
+				 long                 msgid,
+				 struct ipmi_msg      *msg,
+				 void                 *supplied_smi,
+				 struct ipmi_recv_msg *supplied_recv,
+				 int                  priority,
+				 unsigned char        source_address,
+				 unsigned char        source_lun)
+{
+	int                  rv = 0;
+	struct ipmi_smi_msg  *smi_msg;
+	struct ipmi_recv_msg *recv_msg;
+	unsigned long        flags;
+
+
+	if (supplied_recv) {
+		recv_msg = supplied_recv;
+	} else {
+		recv_msg = ipmi_alloc_recv_msg();
+		if (recv_msg == NULL) {
+			return -ENOMEM;
+		}
+	}
+
+	if (supplied_smi) {
+		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
+	} else {
+		smi_msg = ipmi_alloc_smi_msg();
+		if (smi_msg == NULL) {
+			ipmi_free_recv_msg(recv_msg);
+			return -ENOMEM;
+		}
+	}
+
+	if (addr->channel > IPMI_NUM_CHANNELS) {
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+	recv_msg->user = user;
+	recv_msg->msgid = msgid;
+	/* Store the message to send in the receive message so timeout
+	   responses can get the proper response data. */
+	recv_msg->msg = *msg;
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr;
+
+
+		smi_addr = (struct ipmi_system_interface_addr *) addr;
+		if (smi_addr->lun > 3)
+			return -EINVAL;
+
+		memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
+
+		if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
+		    && ((msg->cmd == IPMI_SEND_MSG_CMD)
+			|| (msg->cmd == IPMI_GET_MSG_CMD)
+			|| (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
+		{
+			/* We don't let the user do these, since we manage
+			   the sequence numbers. */
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
+		smi_msg->data[1] = msg->cmd;
+		smi_msg->msgid = msgid;
+		smi_msg->user_data = recv_msg;
+		if (msg->data_len > 0)
+			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
+		smi_msg->data_size = msg->data_len + 2;
+	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr;
+		unsigned char         ipmb_seq;
+		long                  seqid;
+		int                   broadcast;
+		int                   retries;
+
+		if (addr == NULL) {
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
+		    /* Broadcasts add a zero at the beginning of the
+		       message, but otherwise is the same as an IPMB
+		       address. */
+		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+		    broadcast = 1;
+		    retries = 0; /* Don't retry broadcasts. */
+		} else {
+		    broadcast = 0;
+		    retries = 4;
+		}
+
+		/* 9 for the header and 1 for the checksum, plus
+                   possibly one for the broadcast. */
+		if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		ipmb_addr = (struct ipmi_ipmb_addr *) addr;
+		if (ipmb_addr->lun > 3) {
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
+
+		if (recv_msg->msg.netfn & 0x1) {
+			/* It's a response, so use the user's sequence
+                           from msgid. */
+			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
+					msgid, broadcast,
+					source_address, source_lun);
+		} else {
+			/* It's a command, so get a sequence for it. */
+
+			spin_lock_irqsave(&(intf->seq_lock), flags);
+
+			/* Create a sequence number with a 1 second
+                           timeout and 4 retries. */
+			/* FIXME - magic number for the timeout. */
+			rv = intf_next_seq(intf,
+					   recv_msg,
+					   1000,
+					   retries,
+					   &ipmb_seq,
+					   &seqid);
+			if (rv) {
+				/* We have used up all the sequence numbers,
+				   probably, so abort. */
+				spin_unlock_irqrestore(&(intf->seq_lock),
+						       flags);
+				goto out_err;
+			}
+
+			/* Store the sequence number in the message,
+                           so that when the send message response
+                           comes back we can start the timer. */
+			format_ipmb_msg(smi_msg, msg, ipmb_addr,
+					STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
+					ipmb_seq, broadcast,
+					source_address, source_lun);
+
+			/* Copy the message into the recv message data, so we
+			   can retransmit it later if necessary. */
+			memcpy(recv_msg->msg_data, smi_msg->data,
+			       smi_msg->data_size);
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = smi_msg->data_size;
+
+			/* We don't unlock until here, because we need
+                           to copy the completed message into the
+                           recv_msg before we release the lock.
+                           Otherwise, race conditions may bite us.  I
+                           know that's pretty paranoid, but I prefer
+                           to be correct. */
+			spin_unlock_irqrestore(&(intf->seq_lock), flags);
+		}
+	} else {
+	    /* Unknown address type. */
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+#if DEBUG_MSGING
+	{
+	    int m;
+	    for (m=0; m<smi_msg->data_size; m++)
+		printk(" %2.2x", smi_msg->data[m]);
+	    printk("\n");
+	}
+#endif
+	intf->handlers->sender(intf->send_info, smi_msg, priority);
+
+	return 0;
+
+ out_err:
+	ipmi_free_smi_msg(smi_msg);
+	ipmi_free_recv_msg(recv_msg);
+	return rv;
+}
+
+int ipmi_request(ipmi_user_t      user,
+		 struct ipmi_addr *addr,
+		 long             msgid,
+		 struct ipmi_msg  *msg,
+		 int              priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_supply_msgs(ipmi_user_t          user,
+			     struct ipmi_addr     *addr,
+			     long                 msgid,
+			     struct ipmi_msg      *msg,
+			     void                 *supplied_smi,
+			     struct ipmi_recv_msg *supplied_recv,
+			     int                  priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      supplied_smi,
+			      supplied_recv,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct ipmi_msg  *msg,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      source_address,
+			      source_lun);
+}
+
+int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+		      void		       *send_info,
+		      unsigned char            version_major,
+		      unsigned char            version_minor,
+		      ipmi_smi_t               *intf)
+{
+	int              i, j;
+	int              rv;
+	ipmi_smi_t       new_intf;
+	struct list_head *entry;
+	unsigned int     flags;
+
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);
+	if (!new_intf)
+		return -ENOMEM;
+
+	rv = -ENOMEM;
+
+	down_write(&interfaces_sem);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] == NULL) {
+			new_intf->version_major = version_major;
+			new_intf->version_minor = version_minor;
+			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+			new_intf->my_lun = 2;  /* the SMS LUN. */
+			rwlock_init(&(new_intf->users_lock));
+			INIT_LIST_HEAD(&(new_intf->users));
+			new_intf->handlers = handlers;
+			new_intf->send_info = send_info;
+			spin_lock_init(&(new_intf->seq_lock));
+			for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+				new_intf->seq_table[j].inuse = 0;
+				new_intf->seq_table[j].seqid = 0;
+			}
+			new_intf->curr_seq = 0;
+			spin_lock_init(&(new_intf->waiting_msgs_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_msgs));
+			spin_lock_init(&(new_intf->events_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_events));
+			new_intf->waiting_events_count = 0;
+			rwlock_init(&(new_intf->cmd_rcvr_lock));
+			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
+			new_intf->all_cmd_rcvr = NULL;
+
+			spin_lock_irqsave(&interfaces_lock, flags);
+			ipmi_interfaces[i] = new_intf;
+			spin_unlock_irqrestore(&interfaces_lock, flags);
+
+			rv = 0;
+			*intf = new_intf;
+			break;
+		}
+	}
+
+	/* We convert to a read semaphore here.  It's possible the
+	   interface was removed between the calls, we have to recheck
+	   afterwards. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	if (ipmi_interfaces[i] != new_intf)
+		/* Well, it went away.  Just return. */
+		goto out;
+
+	if (rv == 0) {
+		/* Call all the watcher interfaces to tell them that a
+		   new interface is available. */
+		down_read(&smi_watchers_sem);
+		list_for_each(entry, &smi_watchers) {
+			struct ipmi_smi_watcher *w;
+			w = list_entry(entry, struct ipmi_smi_watcher, link);
+			w->new_smi(i);
+		}
+		up_read(&smi_watchers_sem);
+	}
+
+ out:
+	up_read(&interfaces_sem);
+
+	if (rv)
+		kfree(new_intf);
+
+	return rv;
+}
+
+static void free_recv_msg_list(struct list_head *q)
+{
+	struct list_head     *entry, *entry2;
+	struct ipmi_recv_msg *msg;
+
+	list_for_each_safe(entry, entry2, q) {
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		ipmi_free_recv_msg(msg);
+	}
+}
+
+static void free_cmd_rcvr_list(struct list_head *q)
+{
+	struct list_head *entry, *entry2;
+	struct cmd_rcvr  *rcvr;
+
+	list_for_each_safe(entry, entry2, q) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		list_del(entry);
+		kfree(rcvr);
+	}
+}
+
+static void clean_up_interface_data(ipmi_smi_t intf)
+{
+	int i;
+
+	free_recv_msg_list(&(intf->waiting_msgs));
+	free_recv_msg_list(&(intf->waiting_events));
+	free_cmd_rcvr_list(&(intf->cmd_rcvrs));
+
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if ((intf->seq_table[i].inuse)
+		    && (intf->seq_table[i].recv_msg))
+		{
+			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
+		}	
+	}
+}
+
+int ipmi_unregister_smi(ipmi_smi_t intf)
+{
+	int              rv = -ENODEV;
+	int              i;
+	struct list_head *entry;
+	unsigned int     flags;
+
+	down_write(&interfaces_sem);
+	if (list_empty(&(intf->users)))
+	{
+		for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+			if (ipmi_interfaces[i] == intf) {
+				spin_lock_irqsave(&interfaces_lock, flags);
+				ipmi_interfaces[i] = NULL;
+				clean_up_interface_data(intf);
+				spin_unlock_irqrestore(&interfaces_lock,flags);
+				kfree(intf);
+				rv = 0;
+				goto out_call_watcher;
+			}
+		}
+	} else {
+		rv = -EBUSY;
+	}
+	up_write(&interfaces_sem);
+
+	return rv;
+
+ out_call_watcher:
+	/* Convert to a read semaphore so callbacks don't bite us. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	/* Call all the watcher interfaces to tell them that
+	   an interface is gone. */
+	down_read(&smi_watchers_sem);
+	list_for_each(entry, &smi_watchers) {
+		struct ipmi_smi_watcher *w;
+		w = list_entry(entry,
+			       struct ipmi_smi_watcher,
+			       link);
+		w->smi_gone(i);
+	}
+	up_read(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+static int handle_get_msg_rsp(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct ipmi_ipmb_addr ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	
+	if (msg->rsp_size < 11)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0)
+		/* An error getting the response, just ignore it. */
+		return 0;
+
+	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+	ipmb_addr.slave_addr = msg->rsp[6];
+	ipmb_addr.channel = msg->rsp[3] & 0x0f;
+	ipmb_addr.lun = msg->rsp[7] & 3;
+
+	/* It's a response from a remote entity.  Look up the sequence
+	   number and handle the response. */
+	if (intf_find_seq(intf,
+			  msg->rsp[7] >> 2,
+			  msg->rsp[3] & 0x0f,
+			  msg->rsp[8],
+			  (msg->rsp[4] >> 2) & (~1),
+			  (struct ipmi_addr *) &(ipmb_addr),
+			  &recv_msg))
+	{
+		/* We were unable to find the sequence number,
+		   so just nuke the message. */
+		return 0;
+	}
+
+	memcpy(recv_msg->msg_data,
+	       &(msg->rsp[9]),
+	       msg->rsp_size - 9);
+	/* THe other fields matched, so no need to set them, except
+           for netfn, which needs to be the response that was
+           returned, not the request value. */
+	recv_msg->msg.netfn = msg->rsp[4] >> 2;
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 10;
+	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	deliver_response(recv_msg);
+
+	return 0;
+}
+
+static int handle_get_msg_cmd(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct list_head *entry;
+	struct cmd_rcvr       *rcvr;
+	int              rv = 0;
+	unsigned char    netfn;
+	unsigned char    cmd;
+	ipmi_user_t      user = NULL;
+	struct ipmi_ipmb_addr *ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	if (msg->rsp_size < 10)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	netfn = msg->rsp[4] >> 2;
+	cmd = msg->rsp[8];
+
+	read_lock(&(intf->cmd_rcvr_lock));
+	
+	if (intf->all_cmd_rcvr) {
+		user = intf->all_cmd_rcvr;
+	} else {
+		/* Find the command/netfn. */
+		list_for_each(entry, &(intf->cmd_rcvrs)) {
+			rcvr = list_entry(entry, struct cmd_rcvr, link);
+			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+				user = rcvr->user;
+				break;
+			}
+		}
+	}
+	read_unlock(&(intf->cmd_rcvr_lock));
+
+	if (user == NULL) {
+		/* We didn't find a user, deliver an error response. */
+		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg->data[1] = IPMI_SEND_MSG_CMD;
+		msg->data[2] = msg->rsp[3];
+		msg->data[3] = msg->rsp[6];
+                msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
+		msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
+		msg->data[6] = intf->my_address;
+                /* rqseq/lun */
+                msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
+		msg->data[8] = msg->rsp[8]; /* cmd */
+		msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
+		msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
+		msg->data_size = 11;
+
+		intf->handlers->sender(intf->send_info, msg, 0);
+
+		rv = -1; /* We used the message, so return the value that
+			    causes it to not be freed or queued. */
+	} else {
+		/* Deliver the message to the user. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+		} else {
+			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
+			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+			ipmb_addr->slave_addr = msg->rsp[6];
+			ipmb_addr->lun = msg->rsp[7] & 3;
+			ipmb_addr->channel = msg->rsp[3];
+
+			recv_msg->user = user;
+			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+			recv_msg->msgid = msg->rsp[7] >> 2;
+			recv_msg->msg.netfn = msg->rsp[4] >> 2;
+			recv_msg->msg.cmd = msg->rsp[8];
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = msg->rsp_size - 10;
+			memcpy(recv_msg->msg_data,
+			       &(msg->rsp[9]),
+			       msg->rsp_size - 10);
+			deliver_response(recv_msg);
+		}
+	}
+
+	return rv;
+}
+
+static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
+				     struct ipmi_smi_msg  *msg)
+{
+	struct ipmi_system_interface_addr *smi_addr;
+	
+	recv_msg->msgid = 0;
+	smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
+	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	smi_addr->channel = IPMI_BMC_CHANNEL;
+	smi_addr->lun = msg->rsp[0] & 3;
+	recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
+	recv_msg->msg.netfn = msg->rsp[0] >> 2;
+	recv_msg->msg.cmd = msg->rsp[1];
+	memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 3;
+}
+
+/* This will be called with the intf->users_lock read-locked, so no need
+   to do that here. */
+static int handle_read_event_rsp(ipmi_smi_t          intf,
+				 struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	struct list_head     msgs;
+	struct list_head     *entry, *entry2;
+	ipmi_user_t          user;
+	int                  rv = 0;
+	int                  deliver_count = 0;
+	unsigned long        flags;
+
+	if (msg->rsp_size < 19) {
+		/* Message is too small to be an IPMB event. */
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the event, just ignore it. */
+		return 0;
+	}
+
+	INIT_LIST_HEAD(&msgs);
+
+	spin_lock_irqsave(&(intf->events_lock), flags);
+
+	/* Allocate and fill in one message for every user that is getting
+	   events. */
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->gets_events)
+			continue;
+
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			list_for_each_safe(entry, entry2, &msgs) {
+				recv_msg = list_entry(entry,
+						      struct ipmi_recv_msg,
+						      link);
+				list_del(entry);
+				ipmi_free_recv_msg(recv_msg);
+			}
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		deliver_count++;
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		recv_msg->user = user;
+		list_add_tail(&(recv_msg->link), &msgs);
+	}
+
+	if (deliver_count) {
+		/* Now deliver all the messages. */
+		list_for_each_safe(entry, entry2, &msgs) {
+			recv_msg = list_entry(entry,
+					      struct ipmi_recv_msg,
+					      link);
+			list_del(entry);
+			deliver_response(recv_msg);
+		}
+	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
+		/* No one to receive the message, put it in queue if there's
+		   not already too many things in the queue. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		list_add_tail(&(recv_msg->link), &(intf->waiting_events));
+	} else {
+		/* There's too many things in the queue, discard this
+		   message. */
+		printk(KERN_WARNING "ipmi: Event queue full, discarding an"
+		       " incoming event\n");
+	}
+
+ out:
+	spin_unlock_irqrestore(&(intf->events_lock), flags);
+
+	return rv;
+}
+
+static int handle_bmc_rsp(ipmi_smi_t          intf,
+			  struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	int                  found = 0;
+	struct list_head     *entry;
+
+	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+
+	/* Make sure the user still exists. */
+	list_for_each(entry, &(intf->users)) {
+		if (list_entry(entry, struct ipmi_user, link)
+		    == recv_msg->user)
+		{
+			/* Found it, so we can deliver it */
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* The user for the message went away, so give up. */
+		ipmi_free_recv_msg(recv_msg);
+	} else {
+		struct ipmi_system_interface_addr *smi_addr;
+
+		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+		recv_msg->msgid = msg->msgid;
+		smi_addr = ((struct ipmi_system_interface_addr *)
+			    &(recv_msg->addr));
+		smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+		smi_addr->channel = IPMI_BMC_CHANNEL;
+		smi_addr->lun = msg->rsp[0] & 3;
+		recv_msg->msg.netfn = msg->rsp[0] >> 2;
+		recv_msg->msg.cmd = msg->rsp[1];
+		memcpy(recv_msg->msg_data,
+		       &(msg->rsp[2]),
+		       msg->rsp_size - 2);
+		recv_msg->msg.data = recv_msg->msg_data;
+		recv_msg->msg.data_len = msg->rsp_size - 2;
+		deliver_response(recv_msg);
+	}
+
+	return 0;
+}
+
+/* Handle a new message.  Return 1 if the message should be requeued,
+   0 if the message should be freed, or -1 if the message should not
+   be freed or requeued. */
+static int handle_new_recv_msg(ipmi_smi_t          intf,
+			       struct ipmi_smi_msg *msg)
+{
+	int requeue;
+
+	if (msg->rsp_size < 2) {
+		/* Message is too small to be correct. */
+		requeue = 0;
+	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {
+#if DEBUG_MSGING
+		int m;
+		printk("Response:");
+		for (m=0; m<msg->rsp_size; m++)
+			printk(" %2.2x", msg->rsp[m]);
+		printk("\n");
+#endif
+		/* It's from the receive queue. */
+		if (msg->rsp[4] & 0x04) {
+			/* It's a response, so find the
+			   requesting message and send it up. */
+			requeue = handle_get_msg_rsp(intf, msg);
+		} else {
+			/* It's a command to the SMS from some other
+			   entity.  Handle that. */
+			requeue = handle_get_msg_cmd(intf, msg);
+		}
+	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
+		/* It's an asyncronous event. */
+		requeue = handle_read_event_rsp(intf, msg);
+	} else {
+		/* It's a response from the local BMC. */
+		requeue = handle_bmc_rsp(intf, msg);
+	}
+
+	return requeue;
+}
+
+/* Handle a new message from the lower layer. */
+void ipmi_smi_msg_received(ipmi_smi_t          intf,
+			   struct ipmi_smi_msg *msg)
+{
+	unsigned long flags;
+	int           rv;
+
+
+	/* Lock the user lock so the user can't go away while we are
+	   working on it. */
+	read_lock(&(intf->users_lock));
+
+	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {
+		/* This is the local response to a send, start the
+                   timer for these. */
+		intf_start_seq_timer(intf, msg->msgid);
+		ipmi_free_smi_msg(msg);
+		goto out_unlock;
+	}
+
+	/* To preserve message order, if the list is not empty, we
+           tack this message onto the end of the list. */
+	spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+	if (!list_empty(&(intf->waiting_msgs))) {
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+		goto out_unlock;
+	}
+	spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+		
+	rv = handle_new_recv_msg(intf, msg);
+	if (rv > 0) {
+		/* Could not handle the message now, just add it to a
+                   list to handle later. */
+		spin_lock(&(intf->waiting_msgs_lock));
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+	} else if (rv == 0) {
+		ipmi_free_smi_msg(msg);
+	}
+
+ out_unlock:
+	read_unlock(&(intf->users_lock));
+}
+
+void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
+{
+	struct list_head *entry;
+	ipmi_user_t      user;
+
+	read_lock(&(intf->users_lock));
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->handler->ipmi_watchdog_pretimeout)
+			continue;
+
+		user->handler->ipmi_watchdog_pretimeout(user->handler_data);
+	}
+	read_unlock(&(intf->users_lock));
+}
+
+static void
+handle_msg_timeout(struct ipmi_recv_msg *msg)
+{
+	msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
+	msg->msg.netfn |= 1; /* Convert to a response. */
+	msg->msg.data_len = 1;
+	msg->msg.data = msg->msg_data;
+	deliver_response(msg);
+}
+
+static void
+send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
+		   struct ipmi_smi_msg *smi_msg,
+		   unsigned char seq, long seqid)
+{
+	if (!smi_msg)
+		smi_msg = ipmi_alloc_smi_msg();
+	if (!smi_msg)
+		/* If we can't allocate the message, then just return, we
+		   get 4 retries, so this should be ok. */
+		return;
+
+	memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
+	smi_msg->data_size = recv_msg->msg.data_len;
+	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
+		
+	/* Send the new message.  We send with a zero priority.  It
+	   timed out, I doubt time is that critical now, and high
+	   priority messages are really only for messages to the local
+	   MC, which don't get resent. */
+	intf->handlers->sender(intf->send_info, smi_msg, 0);
+
+#if DEBUG_MSGING
+	{
+		int m;
+		printk("Resend: ");
+		for (m=0; m<smi_msg->data_size; m++)
+			printk(" %2.2x", smi_msg->data[m]);
+		printk("\n");
+	}
+#endif
+}
+
+static void
+ipmi_timeout_handler(long timeout_period)
+{
+	ipmi_smi_t           intf;
+	struct list_head     timeouts;
+	struct ipmi_recv_msg *msg;
+	struct ipmi_smi_msg  *smi_msg;
+	unsigned long        flags;
+	struct list_head     *entry, *entry2;
+	int                  i, j;
+
+	INIT_LIST_HEAD(&timeouts);
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		read_lock(&(intf->users_lock));
+
+		/* See if any waiting messages need to be processed. */
+		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {
+			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);
+			if (! handle_new_recv_msg(intf, smi_msg)) {
+				list_del(entry);
+				ipmi_free_smi_msg(smi_msg);
+			} else {
+				/* To preserve message order, quit if we
+				   can't handle a message. */
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+
+		/* Go through the seq table and find any messages that
+		   have timed out, putting them in the timeouts
+		   list. */
+		spin_lock_irqsave(&(intf->seq_lock), flags);
+		for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+			struct seq_table *ent = &(intf->seq_table[j]);
+			if (!ent->inuse)
+				continue;
+
+			ent->timeout -= timeout_period;
+			if (ent->timeout > 0)
+				continue;
+
+			if (ent->retries_left == 0) {
+				/* The message has used all its retries. */
+				ent->inuse = 0;
+				msg = ent->recv_msg;
+				list_add_tail(&(msg->link), &timeouts);
+			} else {
+				/* More retries, send again. */
+
+				/* Start with the max timer, set to normal
+				   timer after the message is sent. */
+				ent->timeout = MAX_MSG_TIMEOUT;
+				ent->retries_left--;
+				send_from_recv_msg(intf, ent->recv_msg, NULL,
+						   j, ent->seqid);
+			}
+		}
+		spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+		list_for_each_safe(entry, entry2, &timeouts) {
+			msg = list_entry(entry, struct ipmi_recv_msg, link);
+			handle_msg_timeout(msg);
+		}
+
+		read_unlock(&(intf->users_lock));
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static void ipmi_request_event(void)
+{
+	ipmi_smi_t intf;
+	int        i;
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->request_events(intf->send_info);
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static struct timer_list ipmi_timer;
+
+/* Call every 100 ms. */
+#define IPMI_TIMEOUT_TIME	100
+#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+
+/* Request events from the queue every second.  Hopefully, in the
+   future, IPMI will add a way to know immediately if an event is
+   in the queue. */
+#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
+
+static volatile int stop_operation = 0;
+static volatile int timer_stopped = 0;
+static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+
+static void ipmi_timeout(unsigned long data)
+{
+	if (stop_operation) {
+		timer_stopped = 1;
+		return;
+	}
+
+	ticks_to_req_ev--;
+	if (ticks_to_req_ev == 0) {
+		ipmi_request_event();
+		ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+	}
+
+	ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
+
+	ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+}
+
+
+/* FIXME - convert these to slabs. */
+static void free_smi_msg(struct ipmi_smi_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
+{
+	struct ipmi_smi_msg *rv;
+	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_smi_msg;
+	return rv;
+}
+
+static void free_recv_msg(struct ipmi_recv_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+{
+	struct ipmi_recv_msg *rv;
+
+	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_recv_msg;
+	return rv;
+}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+
+static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
+{
+}
+
+static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
+{
+}
+
+static void send_panic_events(void)
+{
+	struct ipmi_msg                   msg;
+	ipmi_smi_t                        intf;
+	unsigned char                     data[8];
+	int                               i;
+	struct ipmi_system_interface_addr addr;
+	struct ipmi_smi_msg               smi_msg;
+	struct ipmi_recv_msg              recv_msg;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+
+	/* Fill in an event telling that we have failed. */
+	msg.netfn = 0x04; /* Sensor or Event. */
+	msg.cmd = 2; /* Platform event command. */
+	msg.data = data;
+	msg.data_len = 8;
+	data[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */
+	data[1] = 0x03; /* This is for IPMI 1.0. */
+	data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
+	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
+	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
+
+	/* These used to have the first three bytes of the panic string,
+	   but not only is that not terribly useful, it's not available
+	   any more. */
+	data[3] = 0;
+	data[6] = 0;
+	data[7] = 0;
+
+	smi_msg.done = dummy_smi_done_handler;
+	recv_msg.done = dummy_recv_done_handler;
+
+	/* For every registered interface, send the event. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+		i_ipmi_request(NULL,
+			       intf,
+			       (struct ipmi_addr *) &addr,
+			       0,
+			       &msg,
+			       &smi_msg,
+			       &recv_msg,
+			       0,
+			       intf->my_address,
+			       intf->my_lun);
+	}
+}
+#endif /* CONFIG_IPMI_PANIC_EVENT */
+
+static int has_paniced = 0;
+
+static int panic_event(struct notifier_block *this,
+		       unsigned long         event,
+                       void                  *ptr)
+{
+	int        i;
+	ipmi_smi_t intf;
+
+	if (has_paniced)
+		return NOTIFY_DONE;
+	has_paniced = 1;
+
+	/* For every registered interface, set it to run to completion. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+	}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	send_panic_events();
+#endif
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	panic_event,
+	NULL,
+	200   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static __init int ipmi_init_msghandler(void)
+{
+	int i;
+
+	if (initialized)
+		return 0;
+
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		ipmi_interfaces[i] = NULL;
+	}
+
+	init_timer(&ipmi_timer);
+	ipmi_timer.data = 0;
+	ipmi_timer.function = ipmi_timeout;
+	ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	initialized = 1;
+
+	printk(KERN_INFO "ipmi: message handler initialized\n");
+
+	return 0;
+}
+
+static __exit void cleanup_ipmi(void)
+{
+	if (!initialized)
+		return;
+
+	notifier_chain_unregister(&panic_notifier_list, &panic_block);
+
+	/* This can't be called if any interfaces exist, so no worry about
+	   shutting down the interfaces. */
+
+	/* Tell the timer to stop, then wait for it to stop.  This avoids
+	   problems with race conditions removing the timer here. */
+	stop_operation = 1;
+	while (!timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	initialized = 0;
+}
+module_exit(cleanup_ipmi);
+
+module_init(ipmi_init_msghandler);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ipmi_alloc_recv_msg);
+EXPORT_SYMBOL(ipmi_create_user);
+EXPORT_SYMBOL(ipmi_destroy_user);
+EXPORT_SYMBOL(ipmi_get_version);
+EXPORT_SYMBOL(ipmi_request);
+EXPORT_SYMBOL(ipmi_request_supply_msgs);
+EXPORT_SYMBOL(ipmi_request_with_source);
+EXPORT_SYMBOL(ipmi_register_smi);
+EXPORT_SYMBOL(ipmi_unregister_smi);
+EXPORT_SYMBOL(ipmi_register_for_cmd);
+EXPORT_SYMBOL(ipmi_unregister_for_cmd);
+EXPORT_SYMBOL(ipmi_smi_msg_received);
+EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
+EXPORT_SYMBOL(ipmi_alloc_smi_msg);
+EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_addr_length);
+EXPORT_SYMBOL(ipmi_validate_addr);
+EXPORT_SYMBOL(ipmi_set_gets_events);
+EXPORT_SYMBOL(ipmi_addr_equal);
+EXPORT_SYMBOL(ipmi_smi_watcher_register);
+EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
+EXPORT_SYMBOL(ipmi_set_my_address);
+EXPORT_SYMBOL(ipmi_get_my_address);
+EXPORT_SYMBOL(ipmi_set_my_LUN);
+EXPORT_SYMBOL(ipmi_get_my_LUN);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_watchdog.c linux-2.4.21-rc3/drivers/char/ipmi/ipmi_watchdog.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_watchdog.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/ipmi/ipmi_watchdog.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,1113 @@
+/*
+ * ipmi_watchdog.c
+ *
+ * A watchdog timer based upon the IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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.
+ *
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/nmi.h>
+#include <linux/reboot.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/apic.h>
+#endif
+
+/*
+ * The IPMI command/response information for the watchdog timer.
+ */
+
+/* values for byte 1 of the set command, byte 2 of the get response. */
+#define WDOG_DONT_LOG		(1 << 7)
+#define WDOG_DONT_STOP_ON_SET	(1 << 6)
+#define WDOG_SET_TIMER_USE(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7)
+#define WDOG_TIMER_USE_BIOS_FRB2	1
+#define WDOG_TIMER_USE_BIOS_POST	2
+#define WDOG_TIMER_USE_OS_LOAD		3
+#define WDOG_TIMER_USE_SMS_OS		4
+#define WDOG_TIMER_USE_OEM		5
+
+/* values for byte 2 of the set command, byte 3 of the get response. */
+#define WDOG_SET_PRETIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0x8f) | (((use) & 0x7) << 4)
+#define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7)
+#define WDOG_PRETIMEOUT_NONE		0
+#define WDOG_PRETIMEOUT_SMI		1
+#define WDOG_PRETIMEOUT_NMI		2
+#define WDOG_PRETIMEOUT_MSG_INT		3
+
+/* Operations that can be performed on a pretimout. */
+#define WDOG_PREOP_NONE		0
+#define WDOG_PREOP_PANIC	1
+#define WDOG_PREOP_GIVE_DATA	2 /* Cause data to be available to
+                                     read.  Doesn't work in NMI
+                                     mode. */
+
+/* Actions to perform on a full timeout. */
+#define WDOG_SET_TIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7)
+#define WDOG_TIMEOUT_NONE		0
+#define WDOG_TIMEOUT_RESET		1
+#define WDOG_TIMEOUT_POWER_DOWN		2
+#define WDOG_TIMEOUT_POWER_CYCLE	3
+
+/* Byte 3 of the get command, byte 4 of the get response is the
+   pre-timeout in seconds. */
+
+/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
+#define WDOG_EXPIRE_CLEAR_BIOS_FRB2	(1 << 1)
+#define WDOG_EXPIRE_CLEAR_BIOS_POST	(1 << 2)
+#define WDOG_EXPIRE_CLEAR_OS_LOAD	(1 << 3)
+#define WDOG_EXPIRE_CLEAR_SMS_OS	(1 << 4)
+#define WDOG_EXPIRE_CLEAR_OEM		(1 << 5)
+
+/* Setting/getting the watchdog timer value.  This is for bytes 5 and
+   6 (the timeout time) of the set command, and bytes 6 and 7 (the
+   timeout time) and 8 and 9 (the current countdown value) of the
+   response.  The timeout value is given in seconds (in the command it
+   is 100ms intervals). */
+#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
+	(byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
+#define WDOG_GET_TIMEOUT(byte1, byte2) \
+	(((byte1) | ((byte2) << 8)) / 10)
+
+#define IPMI_WDOG_RESET_TIMER		0x22
+#define IPMI_WDOG_SET_TIMER		0x24
+#define IPMI_WDOG_GET_TIMER		0x25
+
+/* These are here until the real ones get into the watchdog.h interface. */
+#ifndef WDIOC_GETTIMEOUT
+#define	WDIOC_GETTIMEOUT        _IOW(WATCHDOG_IOCTL_BASE, 20, int)
+#endif
+#ifndef WDIOC_SET_PRETIMEOUT
+#define	WDIOC_SET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 21, int)
+#endif
+#ifndef WDIOC_GET_PRETIMEOUT
+#define	WDIOC_GET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 22, int)
+#endif
+
+static ipmi_user_t watchdog_user = NULL;
+
+/* Default the timeout to 10 seconds. */
+static int timeout = 10;
+
+/* The pre-timeout is disabled by default. */
+static int pretimeout = 0;
+
+/* Default action is to reset the board on a timeout. */
+static unsigned char action_val = WDOG_TIMEOUT_RESET;
+
+static char *action = "reset";
+
+static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
+
+static char *preaction = "pre_none";
+
+static unsigned char preop_val = WDOG_PREOP_NONE;
+
+static char *preop = "preop_none";
+static spinlock_t ipmi_read_lock = SPIN_LOCK_UNLOCKED;
+static char data_to_read = 0;
+static DECLARE_WAIT_QUEUE_HEAD(read_q);
+static struct fasync_struct *fasync_q = NULL;
+static char pretimeout_since_last_heartbeat = 0;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM(pretimeout, "i");
+MODULE_PARM(action, "s");
+MODULE_PARM(preaction, "s");
+MODULE_PARM(preop, "s");
+
+/* Default state of the timer. */
+static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+
+/* If shutting down via IPMI, we ignore the heartbeat. */
+static int ipmi_ignore_heartbeat = 0;
+
+/* Is someone using the watchdog?  Only one user is allowed. */
+static int ipmi_wdog_open = 0;
+
+/* If true, the driver will start running as soon as it is configured
+   and ready. */
+static int start_now = 0;
+
+/* If set to 1, the heartbeat command will set the state to reset and
+   start the timer.  The timer doesn't normally run when the driver is
+   first opened until the heartbeat is set the first time, this
+   variable is used to accomplish this. */
+static int ipmi_start_timer_on_heartbeat = 0;
+
+/* IPMI version of the BMC. */
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+
+static int ipmi_heartbeat(void);
+static void panic_halt_ipmi_heartbeat(void);
+
+
+/* We use a semaphore to make sure that only one thing can send a set
+   timeout at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(set_timeout_lock);
+static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static struct ipmi_smi_msg set_timeout_smi_msg =
+{
+	.done = set_timeout_free_smi
+};
+static struct ipmi_recv_msg set_timeout_recv_msg =
+{
+	.done = set_timeout_free_recv
+};
+ 
+static int i_ipmi_set_timeout(struct ipmi_smi_msg  *smi_msg,
+			      struct ipmi_recv_msg *recv_msg,
+			      int                  *send_heartbeat_now)
+{
+	struct ipmi_msg    msg;
+	unsigned char      data[6];
+	int                rv;
+	struct ipmi_system_interface_addr addr;
+
+
+	*send_heartbeat_now = 0;
+	data[0] = 0;
+	WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
+
+	if ((ipmi_version_major > 1)
+	    || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
+	{
+		/* This is an IPMI 1.5-only feature. */
+		data[0] |= WDOG_DONT_STOP_ON_SET;
+	} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+		/* In ipmi 1.0, setting the timer stops the watchdog, we
+		   need to start it back up again. */
+		*send_heartbeat_now = 1;
+	}
+
+	data[1] = 0;
+	WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
+	if (pretimeout > 0) {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
+	    data[2] = pretimeout;
+	} else {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE);
+	    data[2] = 0; /* No pretimeout. */
+	}
+	data[3] = 0;
+	WDOG_SET_TIMEOUT(data[4], data[5], timeout);
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_SET_TIMER;
+	msg.data = data;
+	msg.data_len = sizeof(data);
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      smi_msg,
+				      recv_msg,
+				      1);
+	if (rv) {
+		printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n",
+		       rv);
+	}
+
+	return rv;
+}
+
+static int ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+
+	/* We can only send one of these at a time. */
+	down(&set_timeout_lock);
+
+	atomic_set(&set_timeout_tofree, 2);
+
+	rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
+				&set_timeout_recv_msg,
+				&send_heartbeat_now);
+	if (rv) {
+		up(&set_timeout_lock);
+	} else {
+		if (send_heartbeat_now)
+			rv = ipmi_heartbeat();
+	}
+
+	return rv;
+}
+
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+}
+static struct ipmi_smi_msg panic_halt_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_recv_msg =
+{
+	.done = dummy_recv_free
+};
+
+/* Special call, doesn't claim any locks.  This is only to be called
+   at panic or halt time, in run-to-completion mode, when the caller
+   is the only CPU and the only thing that will be going IPMI
+   calls. */
+static void panic_halt_ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+	rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
+				&panic_halt_recv_msg,
+				&send_heartbeat_now);
+	if (!rv) {
+		if (send_heartbeat_now)
+			panic_halt_ipmi_heartbeat();
+	}
+}
+
+/* Do a delayed shutdown, with the delay in milliseconds.  If power_off is
+   false, do a reset.  If power_off is true, do a power down.  This is
+   primarily for the IMB code's shutdown. */
+void ipmi_delayed_shutdown(long delay, int power_off)
+{
+	ipmi_ignore_heartbeat = 1;
+	if (power_off) 
+		ipmi_watchdog_state = WDOG_TIMEOUT_POWER_DOWN;
+	else
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+	timeout = delay;
+	ipmi_set_timeout();
+}
+
+/* We use a semaphore to make sure that only one thing can send a
+   heartbeat at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(heartbeat_lock);
+static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock);
+static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static struct ipmi_smi_msg heartbeat_smi_msg =
+{
+	.done = heartbeat_free_smi
+};
+static struct ipmi_recv_msg heartbeat_recv_msg =
+{
+	.done = heartbeat_free_recv
+};
+ 
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
+{
+	.done = dummy_recv_free
+};
+ 
+static int ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	int                               rv;
+	struct ipmi_system_interface_addr addr;
+
+	if (ipmi_ignore_heartbeat) {
+		return 0;
+	}
+
+	if (ipmi_start_timer_on_heartbeat) {
+		ipmi_start_timer_on_heartbeat = 0;
+		ipmi_watchdog_state = action_val;
+		return ipmi_set_timeout();
+	}
+
+	if (pretimeout_since_last_heartbeat) {
+		/* A pretimeout occurred, make sure we set the timeout.
+		   We don't want to set the action, though, we want to
+		   leave that alone (thus it can't be combined with the
+		   above operation. */
+		pretimeout_since_last_heartbeat = 0;
+		return ipmi_set_timeout();
+	}
+
+	down(&heartbeat_lock);
+
+	atomic_set(&heartbeat_tofree, 2);
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
+		up(&heartbeat_lock);
+		return 0;
+	}
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      &heartbeat_smi_msg,
+				      &heartbeat_recv_msg,
+				      1);
+	if (rv) {
+		up(&heartbeat_lock);
+		printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n",
+		       rv);
+		return rv;
+	}
+
+	/* Wait for the heartbeat to be sent. */
+	down(&heartbeat_wait_lock);
+
+	if (heartbeat_recv_msg.msg.data[0] != 0) {
+	    /* Got an error in the heartbeat response.  It was already
+	       reported in ipmi_wdog_msg_handler, but we should return
+	       an error here. */
+	    rv = -EINVAL;
+	}
+
+	up(&heartbeat_lock);
+
+	return rv;
+}
+
+static void panic_halt_ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	struct ipmi_system_interface_addr addr;
+
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+		return;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	ipmi_request_supply_msgs(watchdog_user,
+				 (struct ipmi_addr *) &addr,
+				 0,
+				 &msg,
+				 &panic_halt_heartbeat_smi_msg,
+				 &panic_halt_heartbeat_recv_msg,
+				 1);
+}
+
+static struct watchdog_info ident=
+{
+	0, /* WDIOF_SETTIMEOUT, */
+	1,
+	"IPMI"
+};
+
+static int ipmi_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	int i;
+	int val;
+
+	switch(cmd) {
+	case WDIOC_GETSUPPORT:
+		i = copy_to_user((void*)arg, &ident, sizeof(ident));
+		return i ? -EFAULT : 0;
+
+	case WDIOC_SETTIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		timeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GETTIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &timeout,
+				 sizeof(timeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_SET_PRETIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		pretimeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GET_PRETIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &pretimeout,
+				 sizeof(pretimeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_KEEPALIVE:
+		return ipmi_heartbeat();
+
+	case WDIOC_SETOPTIONS:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		if (val & WDIOS_DISABLECARD)
+		{
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			ipmi_set_timeout();
+			ipmi_start_timer_on_heartbeat = 0;
+		}
+
+		if (val & WDIOS_ENABLECARD)
+		{
+			ipmi_watchdog_state = action_val;
+			ipmi_set_timeout();
+		}
+		return 0;
+
+	case WDIOC_GETSTATUS:
+		val = 0;
+		return copy_to_user((void *) arg, &val, sizeof(val));
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static ssize_t ipmi_write(struct file *file,
+			  const char  *buf,
+			  size_t      len,
+			  loff_t      *ppos)
+{
+	int rv;
+
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (len) {
+		rv = ipmi_heartbeat();
+		if (rv)
+			return rv;
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t ipmi_read(struct file *file,
+			 char        *buf,
+			 size_t      count,
+			 loff_t      *ppos)
+{
+	int          rv = 0;
+	wait_queue_t wait;
+
+	/*  Can't seek (pread) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count <= 0)
+		return 0;
+
+	/* Reading returns if the pretimeout has gone off, and it only does
+	   it once per pretimeout. */
+	spin_lock(&ipmi_read_lock);
+	if (!data_to_read) {
+		if (file->f_flags & O_NONBLOCK) {
+			rv = -EAGAIN;
+			goto out;
+		}
+		
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&read_q, &wait);
+		while (!data_to_read) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock(&ipmi_read_lock);
+			schedule();
+			spin_lock(&ipmi_read_lock);
+		}
+		remove_wait_queue(&read_q, &wait);
+	    
+		if (signal_pending(current)) {
+			rv = -ERESTARTSYS;
+			goto out;
+		}
+	}
+	data_to_read = 0;
+
+ out:
+	spin_unlock(&ipmi_read_lock);
+
+	if (rv == 0) {
+		if (copy_to_user(buf, &data_to_read, 1))
+			rv = -EFAULT;
+		else
+			rv = 1;
+	}
+
+	return rv;
+}
+
+static int ipmi_open(struct inode *ino, struct file *filep)
+{
+        switch (minor(ino->i_rdev))
+        {
+                case WATCHDOG_MINOR:
+                    if (ipmi_wdog_open)
+                        return -EBUSY;
+
+                    ipmi_wdog_open = 1;
+
+		    /* Don't start the timer now, let it start on the
+		       first heartbeat. */
+		    ipmi_start_timer_on_heartbeat = 1;
+                    return(0);
+
+                default:
+                    return (-ENODEV);
+        }
+}
+
+static unsigned int ipmi_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	
+	poll_wait(file, &read_q, wait);
+
+	spin_lock(&ipmi_read_lock);
+	if (data_to_read)
+		mask |= (POLLIN | POLLRDNORM);
+	spin_unlock(&ipmi_read_lock);
+
+	return mask;
+}
+
+static int ipmi_fasync(int fd, struct file *file, int on)
+{
+	int result;
+
+	result = fasync_helper(fd, file, on, &fasync_q);
+
+	return (result);
+}
+
+static int ipmi_close(struct inode *ino, struct file *filep)
+{
+	if (minor(ino->i_rdev)==WATCHDOG_MINOR)
+	{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+		ipmi_set_timeout();
+#endif		
+	        ipmi_wdog_open = 0;
+	}
+
+	ipmi_fasync (-1, filep, 0);
+
+	return 0;
+}
+
+static struct file_operations ipmi_wdog_fops = {
+	.owner   = THIS_MODULE,
+	.read    = ipmi_read,
+	.poll    = ipmi_poll,
+	.write   = ipmi_write,
+	.ioctl   = ipmi_ioctl,
+	.open    = ipmi_open,
+	.release = ipmi_close,
+	.fasync  = ipmi_fasync,
+};
+
+static struct miscdevice ipmi_wdog_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&ipmi_wdog_fops
+};
+
+static DECLARE_RWSEM(register_sem);
+
+static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
+				  void                 *handler_data)
+{
+	if (msg->msg.data[0] != 0) {
+		printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n",
+		       msg->msg.data[0],
+		       msg->msg.cmd);
+	}
+	
+	ipmi_free_recv_msg(msg);
+}
+
+static void ipmi_wdog_pretimeout_handler(void *handler_data)
+{
+	if (preaction_val != WDOG_PRETIMEOUT_NONE) {
+		if (preop_val == WDOG_PREOP_PANIC)
+			panic("Watchdog pre-timeout");
+		else if (preop_val == WDOG_PREOP_GIVE_DATA) {
+			spin_lock(&ipmi_read_lock);
+			data_to_read = 1;
+			wake_up_interruptible(&read_q);
+			kill_fasync(&fasync_q, SIGIO, POLL_IN);
+
+			/* On some machines, the heartbeat will give
+			   an error and not work unless we re-enable
+			   the timer.   So do so. */
+			pretimeout_since_last_heartbeat = 1;
+
+			spin_unlock(&ipmi_read_lock);
+		}
+	}
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	.ipmi_recv_hndl           = ipmi_wdog_msg_handler,
+	.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
+};
+
+static void ipmi_register_watchdog(int ipmi_intf)
+{
+	int rv = -EBUSY;
+
+	down_read(&register_sem);
+	if (watchdog_user)
+		goto out;
+
+	rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
+	if (rv < 0) {
+		printk("IPMI watchdog: Unable to register with ipmi\n");
+		goto out;
+	}
+
+	ipmi_get_version(watchdog_user,
+			 &ipmi_version_major,
+			 &ipmi_version_minor);
+
+	rv = misc_register(&ipmi_wdog_miscdev);
+	if (rv < 0) {
+		ipmi_destroy_user(watchdog_user);
+		watchdog_user = NULL;
+		printk("IPMI watchdog: Unable to register misc device\n");
+	}
+
+ out:
+	up_write(&register_sem);
+
+	if ((start_now) && (rv == 0)) {
+		/* Run from startup, so start the timer now. */
+		start_now = 0; /* Disable this function after first startup. */
+		ipmi_watchdog_state = action_val;
+		ipmi_set_timeout();
+		printk("Starting IPMI Watchdog now!\n");
+	}
+}
+
+#ifdef HAVE_NMI_HANDLER
+static int
+ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
+{
+	/* If no one else handled the NMI, we assume it was the IPMI
+           watchdog. */
+	if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+		panic("IPMI watchdog pre-timeout");
+	return NOTIFY_DONE;
+}
+
+static struct nmi_handler ipmi_nmi_handler =
+{
+	.dev_name = "ipmi_watchdog",
+	.dev_id   = NULL,
+	.handler  = ipmi_nmi,
+	.priority = 0, /* Call us last. */
+};
+#endif
+
+static int wdog_reboot_handler(struct notifier_block *this,
+			       unsigned long         code,
+			       void                  *unused)
+{
+	static int reboot_event_handled = 0;
+
+	if ((watchdog_user) && (!reboot_event_handled)) {
+		/* Make sure we only do this once. */
+		reboot_event_handled = 1;
+
+		if (code == SYS_DOWN || code == SYS_HALT) {
+			/* Disable the WDT if we are shutting down. */
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			panic_halt_ipmi_set_timeout();
+		} else {
+			/* Set a long timer to let the reboot happens, but
+			   reboot if it hangs. */
+			timeout = 120;
+			pretimeout = 0;
+			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+			panic_halt_ipmi_set_timeout();
+		}
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_reboot_notifier = {
+	wdog_reboot_handler,
+	NULL,
+	0
+};
+
+extern int panic_timeout; /* Why isn't this defined anywhere? */
+
+static int wdog_panic_handler(struct notifier_block *this,
+			      unsigned long         event,
+			      void                  *unused)
+{
+	static int panic_event_handled = 0;
+
+	/* On a panic, if we have a panic timeout, make sure that the thing
+	   reboots, even if it hangs during that panic. */
+	if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) {
+		/* Make sure the panic doesn't hang, and make sure we
+		   do this only once. */
+		panic_event_handled = 1;
+	    
+		timeout = panic_timeout + 120;
+		if (timeout > 255)
+			timeout = 255;
+		pretimeout = 0;
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+		panic_halt_ipmi_set_timeout();
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_panic_notifier = {
+	wdog_panic_handler,
+	NULL,
+	150   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static void ipmi_new_smi(int if_num)
+{
+	ipmi_register_watchdog(if_num);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	/* This can never be called, because once the watchdog is
+	   registered, the interface can't go away until the watchdog
+	   is unregistered. */
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	.new_smi  = ipmi_new_smi,
+	.smi_gone = ipmi_smi_gone
+};
+
+static int __init ipmi_wdog_init(void)
+{
+	int rv;
+
+	if (strcmp(action, "reset") == 0) {
+		action_val = WDOG_TIMEOUT_RESET;
+	} else if (strcmp(action, "none") == 0) {
+		action_val = WDOG_TIMEOUT_NONE;
+	} else if (strcmp(action, "power_cycle") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_CYCLE;
+	} else if (strcmp(action, "power_off") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_DOWN;
+	} else {
+		action_val = WDOG_TIMEOUT_RESET;
+		printk("ipmi_watchdog: Unknown action '%s', defaulting to"
+		       " reset\n", action);
+	}
+
+	if (strcmp(preaction, "pre_none") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NONE;
+	} else if (strcmp(preaction, "pre_smi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_SMI;
+#ifdef HAVE_NMI_HANDLER
+	} else if (strcmp(preaction, "pre_nmi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NMI;
+#endif
+	} else if (strcmp(preaction, "pre_int") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_MSG_INT;
+	} else {
+		action_val = WDOG_PRETIMEOUT_NONE;
+		printk("ipmi_watchdog: Unknown preaction '%s', defaulting to"
+		       " none\n", preaction);
+	}
+
+	if (strcmp(preop, "preop_none") == 0) {
+		preop_val = WDOG_PREOP_NONE;
+	} else if (strcmp(preop, "preop_panic") == 0) {
+		preop_val = WDOG_PREOP_PANIC;
+	} else if (strcmp(preop, "preop_give_data") == 0) {
+		preop_val = WDOG_PREOP_GIVE_DATA;
+	} else {
+		action_val = WDOG_PREOP_NONE;
+		printk("ipmi_watchdog: Unknown preop '%s', defaulting to"
+		       " none\n", preop);
+	}
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI) {
+		if (preop_val == WDOG_PREOP_GIVE_DATA) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: Pretimeout op is to give data"
+			       " but NMI pretimeout is enabled, setting"
+			       " pretimeout op to none\n");
+			preop_val = WDOG_PREOP_NONE;
+		}
+#ifdef CONFIG_X86_LOCAL_APIC
+		if (nmi_watchdog == NMI_IO_APIC) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: nmi_watchdog is set to IO APIC"
+			       " mode (value is %d), that is incompatible"
+			       " with using NMI in the IPMI watchdog."
+			       " Disabling IPMI nmi pretimeout.\n",
+			       nmi_watchdog);
+			preaction_val = WDOG_PRETIMEOUT_NONE;
+		} else {
+#endif
+		rv = request_nmi(&ipmi_nmi_handler);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: Can't register nmi handler\n");
+			return rv;
+		}
+#ifdef CONFIG_X86_LOCAL_APIC
+		}
+#endif
+	}
+#endif
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+#ifdef HAVE_NMI_HANDLER
+		if (preaction_val == WDOG_PRETIMEOUT_NMI)
+			release_nmi(&ipmi_nmi_handler);
+#endif
+		printk(KERN_WARNING
+		       "ipmi_watchdog: can't register smi watcher\n");
+		return rv;
+	}
+
+	register_reboot_notifier(&wdog_reboot_notifier);
+	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+
+	printk(KERN_INFO "IPMI watchdog by "
+	       "Corey Minyard (minyard@mvista.com)\n");
+
+	return 0;
+}
+
+#ifdef MODULE
+static void ipmi_unregister_watchdog(void)
+{
+	int rv;
+
+	down_write(&register_sem);
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI)
+		release_nmi(&ipmi_nmi_handler);
+#endif
+
+	notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier);
+	unregister_reboot_notifier(&wdog_reboot_notifier);
+
+	if (! watchdog_user)
+		goto out;
+
+	/* Make sure no one can call us any more. */
+	misc_deregister(&ipmi_wdog_miscdev);
+
+	/*  Disable the timer. */
+	ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+	ipmi_set_timeout();
+
+	/* Wait to make sure the message makes it out.  The lower layer has
+	   pointers to our buffers, we want to make sure they are done before
+	   we release our memory. */
+	while (atomic_read(&set_timeout_tofree)) {
+		schedule_timeout(1);
+	}
+
+	/* Disconnect from IPMI. */
+	rv = ipmi_destroy_user(watchdog_user);
+	if (rv) {
+		printk(KERN_WARNING
+		       "IPMI Watchdog, error unlinking from IPMI: %d\n",
+		       rv);
+	}
+	watchdog_user = NULL;
+
+ out:
+	up_write(&register_sem);
+}
+
+static void __exit ipmi_wdog_exit(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	ipmi_unregister_watchdog();
+}
+module_exit(ipmi_wdog_exit);
+#else
+static int __init ipmi_wdog_setup(char *str)
+{
+	int  val;
+	int  rv;
+	char *option;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val > 0)
+		timeout = val;
+	if (rv == 1)
+		return 1;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val >= 0)
+		pretimeout = val;
+	if (rv == 1)
+		return 1;
+
+	while ((option = strsep(&str, ",")) != NULL) {
+		if (strcmp(option, "reset") == 0) {
+			action = "reset";
+		}
+		else if (strcmp(option, "none") == 0) {
+			action = "none";
+		}
+		else if (strcmp(option, "power_cycle") == 0) {
+			action = "power_cycle";
+		}
+		else if (strcmp(option, "power_off") == 0) {
+			action = "power_off";
+		}
+		else if (strcmp(option, "pre_none") == 0) {
+			preaction = "pre_none";
+		}
+		else if (strcmp(option, "pre_smi") == 0) {
+			preaction = "pre_smi";
+		}
+#ifdef HAVE_NMI_HANDLER
+		else if (strcmp(option, "pre_nmi") == 0) {
+			preaction = "pre_nmi";
+		}
+#endif
+		else if (strcmp(option, "pre_int") == 0) {
+			preaction = "pre_int";
+		}
+		else if (strcmp(option, "start_now") == 0) {
+			start_now = 1;
+		}
+		else if (strcmp(option, "preop_none") == 0) {
+			preop = "preop_none";
+		}
+		else if (strcmp(option, "preop_panic") == 0) {
+			preop = "preop_panic";
+		}
+		else if (strcmp(option, "preop_none") == 0) {
+			preop = "preop_give_data";
+		} else {
+		    printk("Unknown IPMI watchdog option: '%s'\n", option);
+		}
+	}
+
+	return 1;
+}
+__setup("ipmi_wdog=", ipmi_wdog_setup);
+#endif
+
+EXPORT_SYMBOL(ipmi_delayed_shutdown);
+
+module_init(ipmi_wdog_init);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/isicom.c linux-2.4.21-rc3/drivers/char/isicom.c
--- linux-2.4.20/drivers/char/isicom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/isicom.c	2003-05-22 22:06:25.000000000 +0000
@@ -2016,7 +2016,7 @@
 	retval=misc_register(&isiloader_device);
 	if (retval<0) {
 		printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
-		return -EIO;
+		return retval;
 	}
 	
 	if (!isicom_init()) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/joystick/iforce.c linux-2.4.21-rc3/drivers/char/joystick/iforce.c
--- linux-2.4.20/drivers/char/joystick/iforce.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/joystick/iforce.c	2003-05-22 22:06:26.000000000 +0000
@@ -93,6 +93,7 @@
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
 static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
+static signed short btn_avb_tw[] =   { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
 static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
@@ -106,11 +107,15 @@
 	signed short *abs;
 	signed short *ff;
 } iforce_device[] = {
+	{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_avb_tw, abs_wheel, ff_iforce },
+	{ 0x061c, 0xc084, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce },
 	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
+	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce },
 	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 };
 
@@ -1061,11 +1066,15 @@
 }
 
 static struct usb_device_id iforce_usb_ids [] = {
+	{ USB_DEVICE(0x044f, 0xa01c) },		/* Thrustmaster Motor Sport GT */
 	{ USB_DEVICE(0x046d, 0xc281) },		/* Logitech WingMan Force */
 	{ USB_DEVICE(0x046d, 0xc291) },		/* Logitech WingMan Formula Force */
 	{ USB_DEVICE(0x05ef, 0x020a) },		/* AVB Top Shot Pegasus */
 	{ USB_DEVICE(0x05ef, 0x8884) },		/* AVB Mag Turbo Force */
+	{ USB_DEVICE(0x05ef, 0x8888) },		/* AVB Top Shot FFB Racing Wheel */
+	{ USB_DEVICE(0x061c, 0xc084) },         /* ACT LABS Force RS */
 	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/joystick/pcigame.c linux-2.4.21-rc3/drivers/char/joystick/pcigame.c
--- linux-2.4.20/drivers/char/joystick/pcigame.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/joystick/pcigame.c	2003-05-22 22:06:27.000000000 +0000
@@ -195,7 +195,7 @@
 
 int __init pcigame_init(void)
 {
-	pci_module_init(&pcigame_driver);
+	pci_register_driver(&pcigame_driver);
 	/* Needed by other modules */
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/keyboard.c linux-2.4.21-rc3/drivers/char/keyboard.c
--- linux-2.4.20/drivers/char/keyboard.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/keyboard.c	2003-05-22 22:06:41.000000000 +0000
@@ -64,6 +64,7 @@
 void (*kbd_ledfunc)(unsigned int led);
 EXPORT_SYMBOL(handle_scancode);
 EXPORT_SYMBOL(kbd_ledfunc);
+EXPORT_SYMBOL(kbd_refresh_leds);
 
 extern void ctrl_alt_del(void);
 
@@ -94,6 +95,7 @@
 static struct tty_struct **ttytab;
 static struct kbd_struct * kbd = kbd_table;
 static struct tty_struct * tty;
+static unsigned char prev_scancode;
 
 void compute_shiftstate(void);
 
@@ -213,7 +215,17 @@
 	}
 	kbd = kbd_table + fg_console;
 	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
-		put_queue(scancode | up_flag);
+		/*
+		 *	The following is a workaround for hardware
+		 *	which sometimes send the key release event twice 
+		 */
+		unsigned char next_scancode = scancode|up_flag;
+		if (up_flag && next_scancode==prev_scancode) {
+			/* unexpected 2nd release event */
+		} else {
+			prev_scancode=next_scancode;
+			put_queue(next_scancode);
+		}
 		/* we do not return yet, because we want to maintain
 		   the key_down array, so that we have the correct
 		   values when finishing RAW mode or when changing VT's */
@@ -899,9 +911,9 @@
  * Aside from timing (which isn't really that important for
  * keyboard interrupts as they happen often), using the software
  * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen. Not yet
- * used, but this allows for easy and efficient race-condition
- * prevention later on.
+ * this when we don't want any of the above to happen.
+ * This allows for easy and efficient race-condition prevention
+ * for kbd_ledfunc => input_event(dev, EV_LED, ...) => ...
  */
 static void kbd_bh(unsigned long dummy)
 {
@@ -917,6 +929,18 @@
 EXPORT_SYMBOL(keyboard_tasklet);
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
+/*
+ * This allows a newly plugged keyboard to pick the LED state.
+ * We do it in this seemindly backwards fashion to ensure proper locking.
+ * Built-in keyboard does refresh on its own.
+ */
+void kbd_refresh_leds(void)
+{
+	tasklet_disable(&keyboard_tasklet);
+	if (ledstate != 0xff && kbd_ledfunc != NULL) kbd_ledfunc(ledstate);
+	tasklet_enable(&keyboard_tasklet);
+}
+
 typedef void (pm_kbd_func) (void);
 
 pm_callback pm_kbd_request_override = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/mem.c linux-2.4.21-rc3/drivers/char/mem.c
--- linux-2.4.20/drivers/char/mem.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/mem.c	2003-05-22 22:06:47.000000000 +0000
@@ -520,7 +520,91 @@
 	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
-#define mmap_kmem	mmap_mem
+struct page *kmem_vm_nopage(struct vm_area_struct *vma, unsigned long address, int write)
+{
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long kaddr;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+	struct page *page = NULL;
+
+	/* address is user VA; convert to kernel VA of desired page */
+	kaddr = (address - vma->vm_start) + offset;
+	kaddr = VMALLOC_VMADDR(kaddr);
+
+	spin_lock(&init_mm.page_table_lock);
+
+	/* Lookup page structure for kernel VA */
+	pgd = pgd_offset(&init_mm, kaddr);
+	if (pgd_none(*pgd) || pgd_bad(*pgd))
+		goto out;
+	pmd = pmd_offset(pgd, kaddr);
+	if (pmd_none(*pmd) || pmd_bad(*pmd))
+		goto out;
+	ptep = pte_offset(pmd, kaddr);
+	if (!ptep)
+		goto out;
+	pte = *ptep;
+	if (!pte_present(pte))
+		goto out;
+	if (write && !pte_write(pte))
+		goto out;
+	page = pte_page(pte);
+	if (!VALID_PAGE(page)) {
+		page = NULL;
+		goto out;
+	}
+
+	/* Increment reference count on page */
+	get_page(page);
+
+out:
+	spin_unlock(&init_mm.page_table_lock);
+
+	return page;
+}
+
+struct vm_operations_struct kmem_vm_ops = {
+	nopage:		kmem_vm_nopage,
+};
+
+static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+{
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long size = vma->vm_end - vma->vm_start;
+
+	/*
+	 * If the user is not attempting to mmap a high memory address then
+	 * the standard mmap_mem mechanism will work.  High memory addresses
+	 * need special handling, as remap_page_range expects a physically-
+	 * contiguous range of kernel addresses (such as obtained in kmalloc).
+	 */
+	if ((offset + size) < (unsigned long) high_memory)
+		return mmap_mem(file, vma);
+
+	/*
+	 * Accessing memory above the top the kernel knows about or
+	 * through a file pointer that was marked O_SYNC will be
+	 * done non-cached.
+	 */
+	if (noncached_address(offset) || (file->f_flags & O_SYNC))
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Don't do anything here; "nopage" will fill the holes */
+	vma->vm_ops = &kmem_vm_ops;
+
+	/* Don't try to swap out physical pages.. */
+	vma->vm_flags |= VM_RESERVED;
+
+	/*
+	 * Don't dump addresses that are not real memory to a core file.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	return 0;
+}
+
 #define zero_lseek	null_lseek
 #define full_lseek      null_lseek
 #define write_zero	write_null
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/mux.c linux-2.4.21-rc3/drivers/char/mux.c
--- linux-2.4.20/drivers/char/mux.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/mux.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,638 @@
+/*
+** mux.c:
+**      MUX console for the NOVA and K-Class systems.
+**
+**	(c) Copyright 2002 Ryan Bradetich
+**	(c) Copyright 2002 Hewlett-Packard Company
+**
+** 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.
+**
+**
+** This Driver used Christoph Plattner's pdc_console.c as a driver
+** template.
+**
+** This Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+static char *mux_drv_version = "0.1";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+static unsigned long break_pressed;
+#endif
+
+#ifdef CONFIG_GSC
+#include <asm/gsc.h>
+#endif
+
+static unsigned long hpa;
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_MIN_FREE_SIZE 32
+
+#define MUX_FIFO_DRAIN_DELAY 1
+#define MUX_POLL_DELAY (30 * HZ / 1000)
+
+#define IO_COMMAND_REG_OFFSET 0x30
+#define IO_STATUS_REG_OFFSET 0x34
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+#define IO_UCOUNT_REG_OFFSET 0x44
+#define IO_FIFOS_REG_OFFSET 0x48
+
+#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
+
+static int mux_drv_refcount; /* = 0 */
+static struct tty_driver mux_drv_driver;
+static struct async_struct *mux_drv_info;
+static struct timer_list mux_drv_timer;
+
+#define NR_PORTS 1
+static struct tty_struct *mux_drv_table[NR_PORTS];
+static struct termios *mux_drv_termios[NR_PORTS];
+static struct termios *mux_drv_termios_locked[NR_PORTS];
+
+/**
+ * mux_read_fifo - Read chars from the mux fifo.
+ * @info: Ptr to the async structure.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void
+mux_read_fifo(struct async_struct *info)
+{
+	int data;
+	struct tty_struct *tty = info->tty;
+
+	while(1) {
+		data = __raw_readl((unsigned long)info->iomem_base 
+				   + IO_DATA_REG_OFFSET);
+
+		if (MUX_STATUS(data))
+			continue;
+
+		if (MUX_EOFIFO(data))
+			break;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			continue;
+
+		*tty->flip.char_buf_ptr = data & 0xffu;
+		*tty->flip.flag_buf_ptr = 0;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+		if (MUX_BREAK(data) && !break_pressed) {
+ 			break_pressed = jiffies;
+			continue;
+		}
+
+		if(MUX_BREAK(data)) {
+			*tty->flip.flag_buf_ptr = TTY_BREAK;
+		}
+
+		if(break_pressed) {
+			if(time_before(jiffies, break_pressed + HZ * 5)) {
+				handle_sysrq(data & 0xffu, NULL, NULL, NULL);
+				break_pressed = 0;
+				continue; 
+			}
+			break_pressed = 0;
+		}
+#endif
+
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+
+/**
+ * mux_drv_poll - Mux poll function.
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Mux to check for new data.
+ */
+static void
+mux_drv_poll(unsigned long unused)
+{
+	struct async_struct *info = mux_drv_info;
+
+	if(info && info->tty && mux_drv_refcount) {
+		mux_read_fifo(info);
+		info->last_active = jiffies;
+	}
+
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+}
+
+/**
+ * mux_chars_in_buffer - Returns the number of chars present in the outbound fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns the number of chars sitting in the outbound fifo.
+ * [Note: This function is required for the normal_poll function in 
+ *  drivers/char/n_tty.c].
+ */
+static int
+mux_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	return __raw_readl((unsigned long)info->iomem_base 
+			   + IO_DCOUNT_REG_OFFSET);
+}
+
+/**
+ * mux_flush_buffer - Pause until the fifo is empty.
+ * @tty: Ptr to the tty structure.
+ *
+ * Since the mux fifo is self draining, this function just
+ * waits until the fifo has completely drained.
+ */
+static void
+mux_flush_buffer(struct tty_struct *tty)
+{
+	while(mux_chars_in_buffer(tty))
+		mdelay(MUX_FIFO_DRAIN_DELAY);
+}
+
+/**
+ * mux_write_room - How much room is left in the fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns how much room is in the fifo for
+ * writing.
+ */
+static int
+mux_write_room(struct tty_struct *tty)
+{
+	int room = mux_chars_in_buffer(tty);
+	if(room > MUX_FIFO_SIZE)
+		return 0;
+
+	return MUX_FIFO_SIZE - room;
+}
+
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @tty: Ptr to the tty structure.
+ * @from_user: Is the buffer from user space?
+ * @buf: The buffer to write to the mux fifo.
+ * @count: The number of chars to write to the mux fifo.
+ *
+ * This function writes the data from buf to the mux fifo.
+ * [Note: we need the mux_flush_buffer() at the end of the 
+ * function, otherwise the system will wait for LONG_MAX
+ * if the fifo is not empty when the TCSETSW ioctl is called.]
+ */
+static int
+mux_write(struct tty_struct *tty, int from_user,
+	  const unsigned char *buf, int count)
+{
+	int size, len, ret = count;
+	char buffer[MUX_FIFO_SIZE], *buf_p;
+	unsigned long iomem_base = 
+		(unsigned long)((struct async_struct *)tty->driver_data)->iomem_base;
+
+	while (count) {
+		size = mux_write_room(tty);
+		len = (size < count) ? size : count;
+
+		if (from_user) {
+			copy_from_user(buffer, buf, len);
+			buf_p = buffer;
+		} else {
+			buf_p = (char *)buf;
+		}
+
+		count -= len;
+		buf += len;
+
+		if(size < MUX_MIN_FREE_SIZE)
+			mux_flush_buffer(tty);
+
+		while(len--) {
+			__raw_writel(*buf_p++, iomem_base + IO_DATA_REG_OFFSET);
+		}
+	}
+
+	mux_flush_buffer(tty);
+	return ret;
+}
+
+/**
+ * mux_break - Turn break handling on or off.
+ * @tty: Ptr to the tty structure.
+ * @break_state: break value.
+ *
+ * This function must be defined because the send_break() in
+ * drivers/char/tty_io.c requires it.  Currently the Serial Mux
+ * does nothing when this function is called.
+ */
+static void
+mux_break(struct tty_struct *tty, int break_state)
+{
+}
+
+/**
+ * get_serial_info - Return the serial structure to userspace.
+ * @info: Ptr to the async structure.
+ * @retinfo: Ptr to the users space buffer.
+ *
+ * Fill in this serial structure and return it to userspace.
+ */
+static int
+get_serial_info(struct async_struct *info,
+		struct serial_struct *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line = info->line;
+	tmp.port = info->line;
+	tmp.flags = info->flags;
+	tmp.close_delay = info->close_delay;
+	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+}
+
+/**
+ * get_modem_info - Return the modem control and status signals to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns these values to userspace:
+ *      Data Terminal Ready, Carrier Detect, Clear To Send,
+ *      Request To Send.
+ *
+ */
+static int 
+get_modem_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCM_DTR|TIOCM_CAR|TIOCM_CTS|TIOCM_RTS;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * get_lsr_info - Return line status register info to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns empty transmitter to userspace.
+ */
+static int 
+get_lsr_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCSER_TEMT;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * mux_ioctl - Handle driver specific ioctl commands.
+ * @tty: Ptr to the tty structure.
+ * @file: Unused.
+ * @cmd: The ioctl number.
+ * @arg: The ioctl argument.
+ *
+ * This function handles ioctls specific to the Serial MUX driver,
+ * or ioctls that need driver specific information.
+ *
+ */
+static int
+mux_ioctl(struct tty_struct *tty, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return 0;
+
+	case TIOCGSERIAL:
+		return get_serial_info(info, (struct serial_struct *) arg);
+
+	case TIOCSSERIAL:
+		return 0;
+
+	case TIOCSERCONFIG:
+		return 0;
+
+	case TIOCSERGETLSR:
+		return get_lsr_info(info, (unsigned int *) arg);
+
+	case TIOCSERGSTRUCT:
+		if (copy_to_user((struct async_struct *) arg,
+				 info, sizeof (struct async_struct)))
+			return -EFAULT;
+		return 0;
+
+	case TIOCMIWAIT:
+		return 0;
+
+	case TIOCGICOUNT:
+		return 0;
+
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk("TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/**
+ * mux_close - Close the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void
+mux_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	mux_drv_refcount--;
+	if (mux_drv_refcount > 0)
+		return;
+
+	info->flags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	/* XXX CP: make mask for receive !!! */
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	mux_drv_info = NULL;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/**
+ * get_async_struct - Get the async structure.
+ * @line: Minor number of the tty device.
+ * @ret_info: Ptr to the newly allocated async structure.
+ *
+ * Allocate and return an async structure for the specified
+ * tty device line.
+ */
+static int
+get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+
+	info = kmalloc(sizeof (struct async_struct), GFP_KERNEL);
+	if (!info) {
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof (struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = 0;
+	info->flags = 0;
+	info->io_type = 0;
+	info->iomem_base = (void *)(hpa + MUX_OFFSET);
+	info->iomem_reg_shift = 0;
+	info->xmit_fifo_size = MUX_FIFO_SIZE;
+	info->line = line;
+	info->tqueue.routine = NULL;
+	info->tqueue.data = info;
+	info->state = NULL;
+	*ret_info = info;
+	return 0;
+}
+
+/**
+ * mux_open - Open the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ *
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure 
+ * into the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+mux_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval, line;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	mux_drv_info = info;
+	info->tty->low_latency = 0;
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+	mux_drv_refcount++;
+	return 0;
+}
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Sserial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init 
+mux_probe(struct parisc_device *dev)
+{
+	if(hpa) {
+		printk(KERN_INFO "Serial MUX driver already registered, skipping additonal MUXes for now.\n");
+		return 1;
+	}
+
+	init_timer(&mux_drv_timer);
+	mux_drv_timer.function = mux_drv_poll;
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+
+	hpa = dev->hpa;
+	printk(KERN_INFO "Serial MUX driver version %s at 0x%lx\n",
+	       mux_drv_version, hpa);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&mux_drv_driver, 0, sizeof (struct tty_driver));
+	mux_drv_driver.magic = TTY_DRIVER_MAGIC;
+	mux_drv_driver.driver_name = "Serial MUX driver";
+#ifdef CONFIG_DEVFS_FS
+	mux_drv_driver.name = "ttb/%d";
+#else
+	mux_drv_driver.name = "ttyB";
+#endif
+	mux_drv_driver.major = MUX_MAJOR;
+	mux_drv_driver.minor_start = 0;
+	mux_drv_driver.num = NR_PORTS;
+	mux_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	mux_drv_driver.subtype = SERIAL_TYPE_NORMAL;
+	mux_drv_driver.init_termios = tty_std_termios;
+	mux_drv_driver.init_termios.c_cflag =
+	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mux_drv_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	mux_drv_driver.refcount = &mux_drv_refcount;
+	mux_drv_driver.table = mux_drv_table;
+	mux_drv_driver.termios = mux_drv_termios;
+	mux_drv_driver.termios_locked = mux_drv_termios_locked;
+
+	mux_drv_driver.open = mux_open;
+	mux_drv_driver.close = mux_close;
+	mux_drv_driver.write = mux_write;
+	mux_drv_driver.put_char = NULL;
+	mux_drv_driver.flush_chars = NULL;
+	mux_drv_driver.write_room = mux_write_room;
+	mux_drv_driver.chars_in_buffer = mux_chars_in_buffer;
+	mux_drv_driver.flush_buffer = mux_flush_buffer;
+	mux_drv_driver.ioctl = mux_ioctl;
+	mux_drv_driver.throttle = NULL;
+	mux_drv_driver.unthrottle = NULL;
+	mux_drv_driver.set_termios = NULL;
+	mux_drv_driver.stop = NULL;
+	mux_drv_driver.start = NULL;
+	mux_drv_driver.hangup = NULL;
+	mux_drv_driver.break_ctl = mux_break;
+	mux_drv_driver.send_xchar = NULL;
+	mux_drv_driver.wait_until_sent = NULL;
+	mux_drv_driver.read_proc = NULL;
+
+	if (tty_register_driver(&mux_drv_driver))
+		panic("Could not register the serial MUX driver\n");
+
+	return 0;
+}
+
+static struct parisc_device_id mux_tbl[] = {
+	{ HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver mux_driver = {
+	name:		"Serial MUX driver",
+	id_table:	mux_tbl,
+	probe:		mux_probe,
+};
+
+/**
+ * mux_init - Serial MUX initalization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void) 
+{
+	return register_parisc_driver(&mux_driver);
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+	int status = tty_unregister_driver(&mux_drv_driver);
+	if(status) {
+		printk("MUX: failed to unregister the Serial MUX driver (%d)\n", status);
+	}
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/mwave/mwavedd.c linux-2.4.21-rc3/drivers/char/mwave/mwavedd.c
--- linux-2.4.20/drivers/char/mwave/mwavedd.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/mwave/mwavedd.c	2003-05-22 22:06:39.000000000 +0000
@@ -500,7 +500,7 @@
 {
 	int i;
 	int retval = 0;
-	unsigned int resultMiscRegister;
+	int resultMiscRegister;
 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
 
 	memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/n_r3964.c linux-2.4.21-rc3/drivers/char/n_r3964.c
--- linux-2.4.20/drivers/char/n_r3964.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/n_r3964.c	2003-05-22 22:06:52.000000000 +0000
@@ -1364,7 +1364,7 @@
       pHeader->owner = pClient;
    }
 
-   copy_from_user (pHeader->data, data, count); /* We already verified this */
+   __copy_from_user(pHeader->data, data, count); /* We already verified this */
 
    if(pInfo->flags & R3964_DEBUG)
    {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/nvram.c linux-2.4.21-rc3/drivers/char/nvram.c
--- linux-2.4.20/drivers/char/nvram.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/nvram.c	2003-05-22 22:06:41.000000000 +0000
@@ -98,6 +98,8 @@
 #define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
 #define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
 
+#define NVRAM_BYTES		50
+
 /* On Ataris, the checksum is over all bytes except the checksum bytes
  * themselves; these are at the very end */
 #define ATARI_CKS_RANGE_START	0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/pcmcia/serial_cs.c linux-2.4.21-rc3/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.20/drivers/char/pcmcia/serial_cs.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/pcmcia/serial_cs.c	2003-05-22 22:06:46.000000000 +0000
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.128 2001/10/18 12:18:35
+    serial_cs.c 1.138 2002/10/25 06:24:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -28,7 +28,7 @@
     and other provisions required by the GPL.  If you do not delete
     the provisions above, a recipient may use your version of this
     file under either the MPL or the GPL.
-    
+
 ======================================================================*/
 
 #include <linux/module.h>
@@ -69,14 +69,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Enable the speaker? */
-INT_MODULE_PARM(do_sound, 1);
+INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
+INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
 
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -95,6 +95,7 @@
     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
@@ -148,7 +149,7 @@
     client_reg_t client_reg;
     dev_link_t *link;
     int i, ret;
-    
+
     DEBUG(0, "serial_attach()\n");
 
     /* Create new serial device */
@@ -160,7 +161,7 @@
     link->release.function = &serial_release;
     link->release.data = (u_long)link;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts1 = 8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
     if (irq_list[0] == -1)
@@ -169,13 +170,12 @@
 	for (i = 0; i < 4; i++)
 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     if (do_sound) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
 	link->conf.Status = CCSR_AUDIO_ENA;
     }
     link->conf.IntType = INT_MEMORY_AND_IO;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -194,7 +194,7 @@
 	serial_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* serial_attach */
 
@@ -214,7 +214,7 @@
     int ret;
 
     DEBUG(0, "serial_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
@@ -224,17 +224,17 @@
     del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	serial_release((u_long)link);
-    
+
     if (link->handle) {
 	ret = CardServices(DeregisterClient, link->handle);
 	if (ret != CS_SUCCESS)
 	    cs_error(link->handle, DeregisterClient, ret);
     }
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     kfree(info);
-    
+
 } /* serial_detach */
 
 /*====================================================================*/
@@ -243,18 +243,20 @@
 {
     struct serial_struct serial;
     int line;
-    
+
     memset(&serial, 0, sizeof(serial));
     serial.port = port;
     serial.irq = irq;
     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+    if (buggy_uart)
+	serial.flags |= ASYNC_BUGGY_UART;
     line = register_serial(&serial);
     if (line < 0) {
 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
 	return -1;
     }
-    
+
     info->line[info->ndev] = line;
     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
     info->node[info->ndev].major = TTY_MAJOR;
@@ -262,7 +264,7 @@
     if (info->ndev > 0)
 	info->node[info->ndev-1].next = &info->node[info->ndev];
     info->ndev++;
-    
+
     return 0;
 }
 
@@ -313,7 +315,10 @@
 	    return setup_serial(info, port, config.AssignedIRQ);
     }
     link->conf.Vcc = config.Vcc;
-    
+
+    link->io.NumPorts1 = 8;
+    link->io.NumPorts2 = 0;
+
     /* First pass: look for a config entry that looks normal. */
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
@@ -340,7 +345,7 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     /* Second pass: try to find an entry that isn't picky about
        its base address, then try to grab any standard serial port
        address, and finally try to get any free port. */
@@ -352,8 +357,7 @@
 	    for (j = 0; j < 5; j++) {
 		link->io.BasePort1 = base[j];
 		link->io.IOAddrLines = base[j] ? 16 : 3;
-		i = CardServices(RequestIO, link->handle,
-				 &link->io);
+		i = CardServices(RequestIO, link->handle, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
 	}
@@ -365,7 +369,7 @@
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -390,8 +394,12 @@
     u_char buf[256];
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    config_info_t config;
     int i, base2 = 0;
 
+    CardServices(GetConfigurationInfo, handle, &config);
+    link->conf.Vcc = config.Vcc;
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -433,12 +441,12 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
-	return -1;
+	/* At worst, try to configure as a single port */
+	return simple_config(link);
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -454,14 +462,27 @@
 	cs_error(link->handle, RequestConfiguration, i);
 	return -1;
     }
-    
+
+    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+       8 registers are for the UART, the others are extra registers */
+    if (info->manfid == MANFID_OXSEMI) {
+	if (cf->index == 1 || cf->index == 3) {
+	    setup_serial(info, base2, link->irq.AssignedIRQ);
+	    outb(12,link->io.BasePort1+1);
+	} else {
+	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	    outb(12,base2+1);
+	}
+	return 0;
+    }
+
     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
     /* The Nokia cards are not really multiport cards */
     if (info->manfid == MANFID_NOKIA)
 	return 0;
     for (i = 0; i < info->multi-1; i++)
 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-    
+
     return 0;
 }
 
@@ -487,7 +508,7 @@
     int i, last_ret, last_fn;
 
     DEBUG(0, "serial_config(0x%p)\n", link);
-    
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -500,7 +521,7 @@
     }
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -508,8 +529,8 @@
     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-    
-    /* Is this a multiport card? */
+
+    /* Scan list of known multiport card ID's */
     tuple.DesiredTuple = CISTPL_MANFID;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	info->manfid = le16_to_cpu(buf[0]);
@@ -537,15 +558,15 @@
 		info->multi = 2;
 	}
     }
-    
+
     if (info->multi > 1)
 	multi_config(link);
     else
 	simple_config(link);
-    
+
     if (info->ndev == 0)
 	goto failed;
-    
+
     if (info->manfid == MANFID_IBM) {
 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
@@ -562,6 +583,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     serial_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* serial_config */
 
@@ -569,7 +591,7 @@
 
     After a card is removed, serial_release() will unregister the net
     device, and release the PCMCIA configuration.
-    
+
 ======================================================================*/
 
 void serial_release(u_long arg)
@@ -577,7 +599,7 @@
     dev_link_t *link = (dev_link_t *)arg;
     serial_info_t *info = link->priv;
     int i;
-    
+
     DEBUG(0, "serial_release(0x%p)\n", link);
 
     for (i = 0; i < info->ndev; i++) {
@@ -590,7 +612,7 @@
 	CardServices(ReleaseIO, link->handle, &link->io);
 	CardServices(ReleaseIRQ, link->handle, &link->irq);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* serial_release */
@@ -601,7 +623,7 @@
     stuff to run after an event is received.  A CARD_REMOVAL event
     also sets some flags to discourage the serial drivers from
     talking to the ports.
-    
+
 ======================================================================*/
 
 static int serial_event(event_t event, int priority,
@@ -609,9 +631,9 @@
 {
     dev_link_t *link = args->client_data;
     serial_info_t *info = link->priv;
-    
+
     DEBUG(1, "serial_event(0x%06x)\n", event);
-    
+
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
@@ -650,7 +672,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "serial_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
     return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/pdc_console.c linux-2.4.21-rc3/drivers/char/pdc_console.c
--- linux-2.4.20/drivers/char/pdc_console.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/pdc_console.c	2003-05-22 22:06:42.000000000 +0000
@@ -625,7 +625,7 @@
 #else
 	pdc_drv_driver.name = "ttyB";
 #endif
-	pdc_drv_driver.major = PDCCONS_MAJOR;
+	pdc_drv_driver.major = MUX_MAJOR;
 	pdc_drv_driver.minor_start = 0;
 	pdc_drv_driver.num = NR_PORTS;
 	pdc_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/qtronix.c linux-2.4.21-rc3/drivers/char/qtronix.c
--- linux-2.4.20/drivers/char/qtronix.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/qtronix.c	2003-05-22 22:06:41.000000000 +0000
@@ -587,7 +587,12 @@
 
 static int __init psaux_init(void)
 {
-	misc_register(&psaux_mouse);
+	int retval;
+
+	retval = misc_register(&psaux_mouse);
+	if(retval < 0)
+		return retval;
+
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/random.c linux-2.4.21-rc3/drivers/char/random.c
--- linux-2.4.20/drivers/char/random.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/random.c	2003-05-22 22:06:26.000000000 +0000
@@ -1235,10 +1235,8 @@
  * at which point we do a "catastrophic reseeding".
  */
 static inline void xfer_secondary_pool(struct entropy_store *r,
-				       size_t nbytes)
+				       size_t nbytes, __u32 *tmp)
 {
-	__u32	tmp[TMP_BUF_SIZE];
-
 	if (r->entropy_count < nbytes * 8 &&
 	    r->entropy_count < r->poolinfo.POOLBITS) {
 		int nwords = min_t(int,
@@ -1291,7 +1289,7 @@
 		r->entropy_count = r->poolinfo.POOLBITS;
 
 	if (flags & EXTRACT_ENTROPY_SECONDARY)
-		xfer_secondary_pool(r, nbytes);
+		xfer_secondary_pool(r, nbytes, tmp);
 
 	DEBUG_ENT("%s has %d bits, want %d bits\n",
 		  r == sec_random_state ? "secondary" :
@@ -2035,56 +2033,102 @@
 
 /* This should not be decreased so low that ISNs wrap too fast. */
 #define REKEY_INTERVAL	300
-#define HASH_BITS 24
+/*
+ * Bit layout of the tcp sequence numbers (before adding current time):
+ * bit 24-31: increased after every key exchange
+ * bit 0-23: hash(source,dest)
+ *
+ * The implementation is similar to the algorithm described
+ * in the Appendix of RFC 1185, except that
+ * - it uses a 1 MHz clock instead of a 250 kHz clock
+ * - it performs a rekey every 5 minutes, which is equivalent
+ * 	to a (source,dest) tulple dependent forward jump of the
+ * 	clock by 0..2^(HASH_BITS+1)
+ *
+ * Thus the average ISN wraparound time is 68 minutes instead of
+ * 4.55 hours.
+ *
+ * SMP cleanup and lock avoidance with poor man's RCU.
+ * 			Manfred Spraul <manfred@colorfullife.com>
+ * 		
+ */
+#define COUNT_BITS	8
+#define COUNT_MASK	( (1<<COUNT_BITS)-1)
+#define HASH_BITS	24
+#define HASH_MASK	( (1<<HASH_BITS)-1 )
+
+static struct keydata {
+	time_t rekey_time;
+	__u32	count;		// already shifted to the final position
+	__u32	secret[12];
+} ____cacheline_aligned ip_keydata[2];
+
+static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int ip_cnt;
+
+static struct keydata *__check_and_rekey(time_t time)
+{
+	struct keydata *keyptr;
+	spin_lock(&ip_lock);
+	keyptr = &ip_keydata[ip_cnt&1];
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = &ip_keydata[1^(ip_cnt&1)];
+		keyptr->rekey_time = time;
+		get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
+		keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
+		mb();
+		ip_cnt++;
+	}
+	spin_unlock(&ip_lock);
+	return keyptr;
+}
+
+static inline struct keydata *check_and_rekey(time_t time)
+{
+	struct keydata *keyptr = &ip_keydata[ip_cnt&1];
+
+	rmb();
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = __check_and_rekey(time);
+	}
+
+	return keyptr;
+}
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
 				   __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32		hash[12];
+	struct keydata *keyptr;
 
-	/* The procedure is the same as for IPv4, but addresses are longer. */
+	/* The procedure is the same as for IPv4, but addresses are longer.
+	 * Thus we must use twothirdsMD4Transform.
+	 */
 
 	do_gettimeofday(&tv);	/* We need the usecs below... */
+	keyptr = check_and_rekey(tv.tv_sec);
 
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First five words are overwritten below. */
-		get_random_bytes(&secret[5], sizeof(secret)-5*4);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
-
-	memcpy(secret, saddr, 16);
-	secret[4]=(sport << 16) + dport;
-
-	seq = (twothirdsMD4Transform(daddr, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	memcpy(hash, saddr, 16);
+	hash[4]=(sport << 16) + dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32)*7);
 
+	seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK;
+	seq += keyptr->count;
 	seq += tv.tv_usec + tv.tv_sec*1000000;
+
 	return seq;
 }
 
 __u32 secure_ipv6_id(__u32 *daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret, sizeof(secret));
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
-	return twothirdsMD4Transform(daddr, secret);
+	return halfMD4Transform(daddr, keyptr->secret);
 }
 
 #endif
@@ -2093,40 +2137,30 @@
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32	hash[4];
+	struct keydata *keyptr;
 
 	/*
 	 * Pick a random secret every REKEY_INTERVAL seconds.
 	 */
 	do_gettimeofday(&tv);	/* We need the usecs below... */
-
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First three words are overwritten below. */
-		get_random_bytes(&secret[3], sizeof(secret)-12);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
+	keyptr = check_and_rekey(tv.tv_sec);
 
 	/*
 	 *  Pick a unique starting offset for each TCP connection endpoints
 	 *  (saddr, daddr, sport, dport).
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
+	 *  Note that the words are placed into the starting vector, which is 
+	 *  then mixed with a partial MD4 over random data.
 	 */
-	secret[0]=saddr;
-	secret[1]=daddr;
-	secret[2]=(sport << 16) + dport;
-
-	seq = (halfMD4Transform(secret+8, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	hash[0]=saddr;
+	hash[1]=daddr;
+	hash[2]=(sport << 16) + dport;
+	hash[3]=keyptr->secret[11];
 
+	seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
+	seq += keyptr->count;
 	/*
 	 *	As close as possible to RFC 793, which
 	 *	suggests using a 250 kHz clock.
@@ -2148,31 +2182,22 @@
  */
 __u32 secure_ip_id(__u32 daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
+	__u32 hash[4];
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret+1, sizeof(secret)-4);
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
 	/*
 	 *  Pick a unique starting offset for each IP destination.
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
+	 *  The dest ip address is placed in the starting vector,
+	 *  which is then hashed with random data.
 	 */
-	secret[0]=daddr;
+	hash[0] = daddr;
+	hash[1] = keyptr->secret[9];
+	hash[2] = keyptr->secret[10];
+	hash[3] = keyptr->secret[11];
 
-	return halfMD4Transform(secret+8, secret);
+	return halfMD4Transform(hash, keyptr->secret);
 }
 
 #ifdef CONFIG_SYN_COOKIES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/raw.c linux-2.4.21-rc3/drivers/char/raw.c
--- linux-2.4.20/drivers/char/raw.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/raw.c	2003-05-22 22:06:26.000000000 +0000
@@ -170,7 +170,7 @@
 {
 	int minor = minor(inode->i_rdev), err; 
 	struct block_device *b; 
-	if (minor < 1 && minor > 255)
+	if (minor < 1 || minor > 255)
 		return -ENODEV;
 
 	b = raw_devices[minor].binding;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/rio/rioboot.c linux-2.4.21-rc3/drivers/char/rio/rioboot.c
--- linux-2.4.20/drivers/char/rio/rioboot.c	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/rio/rioboot.c	2003-05-22 22:06:39.000000000 +0000
@@ -328,6 +328,7 @@
 
 			if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) {
 				rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n");
+				sysfree( DownCode, rbp->Count );
 				p->RIOError.Error = COPYIN_FAILED;
 				func_exit ();
 				return EFAULT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/rtc.c linux-2.4.21-rc3/drivers/char/rtc.c
--- linux-2.4.20/drivers/char/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/rtc.c	2003-05-22 22:06:41.000000000 +0000
@@ -74,6 +74,7 @@
 #include <asm/system.h>
 
 #ifdef __sparc__
+#include <linux/pci.h>
 #include <asm/ebus.h>
 #ifdef __sparc_v9__
 #include <asm/isa.h>
@@ -383,22 +384,18 @@
 		min = alm_tm.tm_min;
 		sec = alm_tm.tm_sec;
 
-		if (hrs >= 24)
-			hrs = 0xff;
-
-		if (min >= 60)
-			min = 0xff;
-
-		if (sec >= 60)
-			sec = 0xff;
-
 		spin_lock_irq(&rtc_lock);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
-			BIN_TO_BCD(sec);
-			BIN_TO_BCD(min);
-			BIN_TO_BCD(hrs);
+			if (sec < 60) BIN_TO_BCD(sec);
+			else sec = 0xff;
+
+			if (min < 60) BIN_TO_BCD(min);
+			else min = 0xff;
+
+			if (hrs < 24) BIN_TO_BCD(hrs);
+			else hrs = 0xff;
 		}
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200.c linux-2.4.21-rc3/drivers/char/scx200.c
--- linux-2.4.20/drivers/char/scx200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/scx200.c	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,128 @@
+/* linux/drivers/char/scx200.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 support. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/scx200.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Driver");
+MODULE_LICENSE("GPL");
+
+unsigned scx200_gpio_base = 0;
+long scx200_gpio_shadow[2];
+
+spinlock_t scx200_gpio_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t scx200_gpio_config_lock = SPIN_LOCK_UNLOCKED;
+
+u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+{
+	u32 config, new_config;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+
+	outl(index, scx200_gpio_base + 0x20);
+	config = inl(scx200_gpio_base + 0x24);
+
+	new_config = (config & mask) | bits;
+	outl(new_config, scx200_gpio_base + 0x24);
+
+	spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+
+	return config;
+}
+
+void scx200_gpio_dump(unsigned index)
+{
+	u32 config = scx200_gpio_configure(index, ~0, 0);
+	printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
+	
+	if (config & 1) 
+		printk(" OE"); /* output enabled */
+	else
+		printk(" TS"); /* tristate */
+	if (config & 2) 
+		printk(" PP"); /* push pull */
+	else
+		printk(" OD"); /* open drain */
+	if (config & 4) 
+		printk(" PUE"); /* pull up enabled */
+	else
+		printk(" PUD"); /* pull up disabled */
+	if (config & 8) 
+		printk(" LOCKED"); /* locked */
+	if (config & 16) 
+		printk(" LEVEL"); /* level input */
+	else
+		printk(" EDGE"); /* edge input */
+	if (config & 32) 
+		printk(" HI"); /* trigger on rising edge */
+	else
+		printk(" LO"); /* trigger on falling edge */
+	if (config & 64) 
+		printk(" DEBOUNCE"); /* debounce */
+	printk("\n");
+}
+
+int __init scx200_init(void)
+{
+	struct pci_dev *bridge;
+	int bank;
+	unsigned base;
+
+	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+
+	base = pci_resource_start(bridge, 0);
+	printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+	if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+		printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+		return -EBUSY;
+	}
+
+	scx200_gpio_base = base;
+
+	/* read the current values driven on the GPIO signals */
+	for (bank = 0; bank < 2; ++bank)
+		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+
+	return 0;
+}
+
+void __exit scx200_cleanup(void)
+{
+	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_cleanup);
+
+EXPORT_SYMBOL(scx200_gpio_base);
+EXPORT_SYMBOL(scx200_gpio_shadow);
+EXPORT_SYMBOL(scx200_gpio_lock);
+EXPORT_SYMBOL(scx200_gpio_configure);
+EXPORT_SYMBOL(scx200_gpio_dump);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_gpio.c linux-2.4.21-rc3/drivers/char/scx200_gpio.c
--- linux-2.4.20/drivers/char/scx200_gpio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/scx200_gpio.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,154 @@
+/* linux/drivers/char/scx200_gpio.c 
+
+   National Semiconductor SCx200 GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_gpio"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major = 0;		/* default to dynamic major */
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major device number");
+
+static ssize_t scx200_gpio_write(struct file *file, const char *data, 
+				 size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	size_t i;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	for (i = 0; i < len; ++i) {
+		char c;
+		if (get_user(c, data+i))
+			return -EFAULT;
+		switch (c)
+		{
+		case '0': 
+			scx200_gpio_set(m, 0); 
+			break;
+		case '1': 
+			scx200_gpio_set(m, 1); 
+			break;
+		case 'O':
+			printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
+			scx200_gpio_configure(m, ~1, 1);
+			break;
+		case 'o':
+			printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
+			scx200_gpio_configure(m, ~1, 0);
+			break;
+		case 'T':
+			printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
+			scx200_gpio_configure(m, ~2, 2);
+			break;
+		case 't':
+			printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
+			scx200_gpio_configure(m, ~2, 0);
+			break;
+		case 'P':
+			printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
+			scx200_gpio_configure(m, ~4, 4);
+			break;
+		case 'p':
+			printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
+			scx200_gpio_configure(m, ~4, 0);
+			break;
+		}
+	}
+
+	return len;
+}
+
+static ssize_t scx200_gpio_read(struct file *file, char *buf,
+				size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	int value;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	value = scx200_gpio_get(m);
+	if (put_user(value ? '1' : '0', buf))
+		return -EFAULT;
+	
+	return 1;
+}
+
+static int scx200_gpio_open(struct inode *inode, struct file *file)
+{
+	unsigned m = minor(inode->i_rdev);
+	if (m > 63)
+		return -EINVAL;
+	return 0;
+}
+
+static int scx200_gpio_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static struct file_operations scx200_gpio_fops = {
+	.owner   = THIS_MODULE,
+	.write   = scx200_gpio_write,
+	.read    = scx200_gpio_read,
+	.open    = scx200_gpio_open,
+	.release = scx200_gpio_release,
+};
+
+static int __init scx200_gpio_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	r = register_chrdev(major, NAME, &scx200_gpio_fops);
+	if (r < 0) {
+		printk(KERN_ERR NAME ": unable to register character device\n");
+		return r;
+	}
+	if (!major) {
+		major = r;
+		printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+	}
+
+	return 0;
+}
+
+static void __exit scx200_gpio_cleanup(void)
+{
+	unregister_chrdev(major, NAME);
+}
+
+module_init(scx200_gpio_init);
+module_exit(scx200_gpio_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_wdt.c linux-2.4.21-rc3/drivers/char/scx200_wdt.c
--- linux-2.4.20/drivers/char/scx200_wdt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/scx200_wdt.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,277 @@
+/* linux/drivers/char/scx200_wdt.c 
+
+   National Semiconductor SCx200 Watchdog support
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Som code taken from:
+   National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+   (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.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 the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The author(s) of this software shall not be held liable for damages
+   of any nature resulting due to the use of this software. This
+   software is provided AS-IS with no warranties. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+#define CONFIG_WATCHDOG_NOWAYOUT 0
+#endif
+
+static int margin = 60;		/* in seconds */
+MODULE_PARM(margin, "i");
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
+MODULE_PARM(nowayout, "i");
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+static u16 wdto_restart;
+static struct semaphore open_semaphore;
+static unsigned expect_close;
+
+/* Bits of the WDCNFG register */
+#define W_ENABLE 0x00fa		/* Enable watchdog */
+#define W_DISABLE 0x0000	/* Disable watchdog */
+
+/* The scaling factor for the timer, this depends on the value of W_ENABLE */
+#define W_SCALE (32768/1024)
+
+static void scx200_wdt_ping(void)
+{
+	outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
+}
+
+static void scx200_wdt_update_margin(void)
+{
+	printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+	wdto_restart = margin * W_SCALE;
+}
+
+static void scx200_wdt_enable(void)
+{
+	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", 
+	       wdto_restart);
+
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+
+	scx200_wdt_ping();
+}
+
+static void scx200_wdt_disable(void)
+{
+	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+		
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+}
+
+static int scx200_wdt_open(struct inode *inode, struct file *file)
+{
+        /* only allow one at a time */
+        if (down_trylock(&open_semaphore))
+                return -EBUSY;
+	scx200_wdt_enable();
+	expect_close = 0;
+
+	return 0;
+}
+
+static int scx200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (!expect_close) {
+		printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
+	} else if (!nowayout) {
+		scx200_wdt_disable();
+	}
+        up(&open_semaphore);
+
+	return 0;
+}
+
+static int scx200_wdt_notify_sys(struct notifier_block *this, 
+				      unsigned long code, void *unused)
+{
+        if (code == SYS_HALT || code == SYS_POWER_OFF)
+		if (!nowayout)
+			scx200_wdt_disable();
+
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block scx200_wdt_notifier =
+{
+        notifier_call: scx200_wdt_notify_sys
+};
+
+static ssize_t scx200_wdt_write(struct file *file, const char *data, 
+				     size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* check for a magic close character */
+	if (len) 
+	{
+		size_t i;
+
+		scx200_wdt_ping();
+
+		expect_close = 0;
+		for (i = 0; i < len; ++i) {
+			char c;
+			if (get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+
+		return len;
+	}
+
+	return 0;
+}
+
+static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		.identity = "NatSemi SCx200 Watchdog",
+		.firmware_version = 1, 
+		.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+	};
+	int new_margin;
+	
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user((struct watchdog_info *)arg, &ident, 
+				sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int *)arg))
+			return -EFAULT;
+		return 0;
+	case WDIOC_KEEPALIVE:
+		scx200_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int *)arg))
+			return -EFAULT;
+		if (new_margin < 1)
+			return -EINVAL;
+		margin = new_margin;
+		scx200_wdt_update_margin();
+		scx200_wdt_ping();
+	case WDIOC_GETTIMEOUT:
+		if (put_user(margin, (int *)arg))
+			return -EFAULT;
+		return 0;
+	}
+}
+
+static struct file_operations scx200_wdt_fops = {
+	.owner	 = THIS_MODULE,
+	.write   = scx200_wdt_write,
+	.ioctl   = scx200_wdt_ioctl,
+	.open    = scx200_wdt_open,
+	.release = scx200_wdt_release,
+};
+
+static struct miscdevice scx200_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name  = NAME,
+	.fops  = &scx200_wdt_fops,
+};
+
+static int __init scx200_wdt_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+
+	/* First check that this really is a NatSemi SCx200 CPU */
+	if ((pci_find_device(PCI_VENDOR_ID_NS, 
+			     PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			     NULL)) == NULL)
+		return -ENODEV;
+
+	/* More sanity checks, verify that the configuration block is there */
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, 
+			    SCx200_WDT_SIZE, 
+			    "NatSemi SCx200 Watchdog")) {
+		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		return -EBUSY;
+	}
+
+	scx200_wdt_update_margin();
+	scx200_wdt_disable();
+
+	sema_init(&open_semaphore, 1);
+
+	r = misc_register(&scx200_wdt_miscdev);
+	if (r)
+		return r;
+
+	r = register_reboot_notifier(&scx200_wdt_notifier);
+        if (r) {
+                printk(KERN_ERR NAME ": unable to register reboot notifier");
+		misc_deregister(&scx200_wdt_miscdev);
+                return r;
+        }
+
+	return 0;
+}
+
+static void __exit scx200_wdt_cleanup(void)
+{
+        unregister_reboot_notifier(&scx200_wdt_notifier);
+	misc_deregister(&scx200_wdt_miscdev);
+	release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		       SCx200_WDT_SIZE);
+}
+
+module_init(scx200_wdt_init);
+module_exit(scx200_wdt_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/serial.c linux-2.4.21-rc3/drivers/char/serial.c
--- linux-2.4.20/drivers/char/serial.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/serial.c	2003-05-22 22:06:40.000000000 +0000
@@ -842,10 +842,15 @@
 		if (status & UART_LSR_DR)
 			receive_chars(info, &status, regs);
 		check_modem_status(info);
+#ifdef CONFIG_MELAN
 		if ((status & UART_LSR_THRE) ||
 			/* for buggy ELAN processors */
 			((iir & UART_IIR_ID) == UART_IIR_THRI))
 			transmit_chars(info, 0);
+#else
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#endif
 
 	next:
 		info = info->next_port;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.c linux-2.4.21-rc3/drivers/char/sonypi.c
--- linux-2.4.20/drivers/char/sonypi.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/sonypi.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,7 +1,9 @@
-/* 
+/*
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -31,12 +33,17 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/input.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -50,7 +57,8 @@
 static int fnkeyinit; /* = 0 */
 static int camera; /* = 0 */
 static int compat; /* = 0 */
-static int nojogdial; /* = 0 */
+static int useinput = 1;
+static unsigned long mask = 0xffffffff;
 
 /* Inits the queue */
 static inline void sonypi_initq(void) {
@@ -110,29 +118,14 @@
         return result;
 }
 
-static void sonypi_ecrset(u8 addr, u8 value) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x81, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(value, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-}
-
-static u8 sonypi_ecrget(u8 addr) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x80, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	return inb_p(SONYPI_DATA_IOPORT);
-}
-
-static u16 sonypi_ecrget16(u8 addr) {
-	return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
+static int ec_read16(u8 addr, u16 *value) {
+	u8 val_lb, val_hb;
+	if (ec_read(addr, &val_lb))
+		return -1;
+	if (ec_read(addr + 1, &val_hb))
+		return -1;
+	*value = val_lb | (val_hb << 8);
+	return 0;
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -159,14 +152,17 @@
 }
 
 static void __devinit sonypi_type2_srs(void) {
-	sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8);
-	sonypi_ecrset(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF);
-	sonypi_ecrset(SONYPI_SIRQ,  sonypi_device.bits);
+	if (ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ,  sonypi_device.bits))
+		printk(KERN_WARNING "ec_write failed\n");
 	udelay(10);
 }
 
 /* Disables the device - this comes from the AML code in the ACPI bios */
-static void __devexit sonypi_type1_dis(void) {
+static void sonypi_type1_dis(void) {
 	u32 v;
 
 	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
@@ -178,16 +174,19 @@
 	outl(v, SONYPI_IRQ_PORT);
 }
 
-static void __devexit sonypi_type2_dis(void) {
-	sonypi_ecrset(SONYPI_SHIB, 0);
-	sonypi_ecrset(SONYPI_SLOB, 0);
-	sonypi_ecrset(SONYPI_SIRQ, 0);
+static void sonypi_type2_dis(void) {
+	if (ec_write(SONYPI_SHIB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ, 0))
+		printk(KERN_WARNING "ec_write failed\n");
 }
 
 static u8 sonypi_call1(u8 dev) {
 	u8 v1, v2;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
 	v1 = inb_p(sonypi_device.ioport2);
 	v2 = inb_p(sonypi_device.ioport1);
@@ -197,9 +196,9 @@
 static u8 sonypi_call2(u8 dev, u8 fn) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -208,11 +207,11 @@
 static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(v, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -234,7 +233,7 @@
 /* Set brightness, hue etc */
 static void sonypi_set(u8 fn, u8 v) {
 	
-	wait_on_command(0, sonypi_call3(0x90, fn, v));
+	wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
 }
 
 /* Tests if the camera is ready */
@@ -308,85 +307,51 @@
 /* Interrupt handler: some event is available */
 void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
 	u8 v1, v2, event = 0;
-	int i;
-	u8 sonypi_jogger_ev, sonypi_fnkey_ev;
-	u8 sonypi_capture_ev, sonypi_bluetooth_ev;
-	u8 sonypi_pkey_ev;
-
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
-		sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
-		sonypi_pkey_ev = nojogdial ? SONYPI_TYPE2_PKEY_EV 
-					   : SONYPI_TYPE1_PKEY_EV;
-	}
-	else {
-		sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
-		sonypi_pkey_ev = SONYPI_TYPE1_PKEY_EV;
-	}
+	int i, j;
 
 	v1 = inb_p(sonypi_device.ioport1);
 	v2 = inb_p(sonypi_device.ioport2);
 
-	if ((v2 & sonypi_pkey_ev) == sonypi_pkey_ev) {
-		for (i = 0; sonypi_pkeyev[i].event; i++)
-			if (sonypi_pkeyev[i].data == v1) {
-				event = sonypi_pkeyev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) {
-		for (i = 0; sonypi_joggerev[i].event; i++)
-			if (sonypi_joggerev[i].data == v1) {
-				event = sonypi_joggerev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
-		for (i = 0; sonypi_captureev[i].event; i++)
-			if (sonypi_captureev[i].data == v1) {
-				event = sonypi_captureev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_fnkey_ev) == sonypi_fnkey_ev) {
-		for (i = 0; sonypi_fnkeyev[i].event; i++)
-			if (sonypi_fnkeyev[i].data == v1) {
-				event = sonypi_fnkeyev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
-		for (i = 0; sonypi_blueev[i].event; i++)
-			if (sonypi_blueev[i].data == v1) {
-				event = sonypi_blueev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & SONYPI_BACK_EV) == SONYPI_BACK_EV) {
-		for (i = 0; sonypi_backev[i].event; i++)
-			if (sonypi_backev[i].data == v1) {
-				event = sonypi_backev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & SONYPI_LID_EV) == SONYPI_LID_EV) {
-		for (i = 0; sonypi_lidev[i].event; i++)
-			if (sonypi_lidev[i].data == v1) {
-				event = sonypi_lidev[i].event;
+	if (verbose > 1)
+		printk(KERN_INFO 
+		       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
+
+	for (i = 0; sonypi_eventtypes[i].model; i++) {
+		if (sonypi_device.model != sonypi_eventtypes[i].model)
+			continue;
+		if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data)
+			continue;
+		if (! (mask & sonypi_eventtypes[i].mask))
+			continue;
+		for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
+			if (v1 == sonypi_eventtypes[i].events[j].data) {
+				event = sonypi_eventtypes[i].events[j].event;
 				goto found;
 			}
+		}
 	}
+
 	if (verbose)
 		printk(KERN_WARNING 
 		       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
 	return;
 
 found:
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		struct input_dev *jog_dev = &sonypi_device.jog_dev;
+		if (event == SONYPI_EVENT_JOGDIAL_PRESSED)
+			input_report_key(jog_dev, BTN_MIDDLE, 1);
+		else if (event == SONYPI_EVENT_ANYBUTTON_RELEASED)
+			input_report_key(jog_dev, BTN_MIDDLE, 0);
+		else if ((event == SONYPI_EVENT_JOGDIAL_UP) ||
+			 (event == SONYPI_EVENT_JOGDIAL_UP_PRESSED))
+			input_report_rel(jog_dev, REL_WHEEL, 1);
+		else if ((event == SONYPI_EVENT_JOGDIAL_DOWN) ||
+			 (event == SONYPI_EVENT_JOGDIAL_DOWN_PRESSED))
+			input_report_rel(jog_dev, REL_WHEEL, -1);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
 	sonypi_pushq(event);
 }
 
@@ -542,90 +507,140 @@
 	down(&sonypi_device.lock);
 	switch (cmd) {
 	case SONYPI_IOCGBRT:
-		val8 = sonypi_ecrget(0x96);
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_LCD_LIGHT, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCSBRT:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
-		sonypi_ecrset(0x96, val8);
+		if (ec_write(SONYPI_LCD_LIGHT, val8))
+			ret = -EIO;
 		break;
 	case SONYPI_IOCGBAT1CAP:
-		val16 = sonypi_ecrget16(0xb2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT1REM:
-		val16 = sonypi_ecrget16(0xa2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2CAP:
-		val16 = sonypi_ecrget16(0xba);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2REM:
-		val16 = sonypi_ecrget16(0xaa);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBATFLAGS:
-		val8 = sonypi_ecrget(0x81) & 0x07;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		val8 &= 0x07;
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBLUE:
 		val8 = sonypi_device.bluetooth_power;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 			ret = -EFAULT;
-			goto out;
-		}
 		break;
 	case SONYPI_IOCSBLUE:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
 		sonypi_setbluetoothpower(val8);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-out:
 	up(&sonypi_device.lock);
 	return ret;
 }
 
 static struct file_operations sonypi_misc_fops = {
-	owner:		THIS_MODULE,
-	read:		sonypi_misc_read,
-	poll:		sonypi_misc_poll,
-	open:		sonypi_misc_open,
-	release:	sonypi_misc_release,
-	fasync: 	sonypi_misc_fasync,
-	ioctl:		sonypi_misc_ioctl,
+	.owner		= THIS_MODULE,
+	.read		= sonypi_misc_read,
+	.poll		= sonypi_misc_poll,
+	.open		= sonypi_misc_open,
+	.release	= sonypi_misc_release,
+	.fasync		= sonypi_misc_fasync,
+	.ioctl		= sonypi_misc_ioctl,
 };
 
 struct miscdevice sonypi_misc_device = {
 	-1, "sonypi", &sonypi_misc_fops
 };
 
+#ifdef CONFIG_PM
+static int sonypi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
+	static int old_camera_power;
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+		if (camera) {
+			old_camera_power = sonypi_device.camera_power;
+			sonypi_camera_off();
+		}
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_dis();
+		else
+			sonypi_type1_dis();
+#ifndef CONFIG_ACPI
+		/* disable ACPI mode */
+		if (fnkeyinit)
+			outb(0xf1, 0xb2);
+#endif
+		break;
+	case PM_RESUME:
+#ifndef CONFIG_ACPI
+		/* Enable ACPI mode to get Fn key events */
+		if (fnkeyinit)
+			outb(0xf0, 0xb2);
+#endif
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_srs();
+		else
+			sonypi_type1_srs();
+		sonypi_call1(0x82);
+		sonypi_call2(0x81, 0xff);
+		if (compat)
+			sonypi_call1(0x92); 
+		else
+			sonypi_call1(0x82);
+		if (camera && old_camera_power)
+			sonypi_camera_on();
+		break;
+	}
+	return 0;
+}
+#endif
+
 static int __devinit sonypi_probe(struct pci_dev *pcidev) {
 	int i, ret;
 	struct sonypi_ioport_list *ioport_list;
@@ -694,7 +709,7 @@
 		goto out3;
 	}
 
-#if !defined(CONFIG_ACPI)
+#ifndef CONFIG_ACPI
 	/* Enable ACPI mode to get Fn key events */
 	if (fnkeyinit)
 		outb(0xf0, 0xb2);
@@ -716,15 +731,16 @@
 	       SONYPI_DRIVER_MAJORVERSION,
 	       SONYPI_DRIVER_MINORVERSION);
 	printk(KERN_INFO "sonypi: detected %s model, "
-	       "verbose = %s, fnkeyinit = %s, camera = %s, "
-	       "compat = %s, nojogdial = %s\n",
+	       "verbose = %d, fnkeyinit = %s, camera = %s, "
+	       "compat = %s, mask = 0x%08lx, useinput = %s\n",
 	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 			"type1" : "type2",
-	       verbose ? "on" : "off",
+	       verbose,
 	       fnkeyinit ? "on" : "off",
 	       camera ? "on" : "off",
 	       compat ? "on" : "off",
-	       nojogdial ? "on" : "off");
+	       mask,
+	       useinput ? "on" : "off");
 	printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
 	       sonypi_device.irq, 
 	       sonypi_device.ioport1, sonypi_device.ioport2);
@@ -732,6 +748,29 @@
 		printk(KERN_INFO "sonypi: device allocated minor is %d\n",
 		       sonypi_misc_device.minor);
 
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		/* Initialize the Input Drivers: */
+		sonypi_device.jog_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+		sonypi_device.jog_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+		sonypi_device.jog_dev.relbit[0] = BIT(REL_WHEEL);
+		sonypi_device.jog_dev.name = (char *) kmalloc(
+			sizeof(SONYPI_INPUTNAME), GFP_KERNEL);
+		sprintf(sonypi_device.jog_dev.name, SONYPI_INPUTNAME);
+		sonypi_device.jog_dev.idbus = BUS_ISA;
+		sonypi_device.jog_dev.idvendor = PCI_VENDOR_ID_SONY;
+	  
+		input_register_device(&sonypi_device.jog_dev);
+		printk(KERN_INFO "%s installed at input event device #%d.\n", 
+			sonypi_device.jog_dev.name,
+			sonypi_device.jog_dev.number);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
+
+#ifdef CONFIG_PM
+	sonypi_device.pm = pm_register(PM_PCI_DEV, 0, sonypi_pm_callback);
+#endif
+
 	return 0;
 
 out3:
@@ -743,14 +782,27 @@
 }
 
 static void __devexit sonypi_remove(void) {
+
+#ifdef CONFIG_PM
+	pm_unregister(sonypi_device.pm);
+#endif
+
 	sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+	
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		input_unregister_device(&sonypi_device.jog_dev);
+		kfree(sonypi_device.jog_dev.name);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
+
 	if (camera)
 		sonypi_camera_off();
 	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 		sonypi_type2_dis();
 	else
 		sonypi_type1_dis();
-#if !defined(CONFIG_ACPI)
+#ifndef CONFIG_ACPI
 	/* disable ACPI mode */
 	if (fnkeyinit)
 		outb(0xf1, 0xb2);
@@ -780,7 +832,7 @@
 
 #ifndef MODULE
 static int __init sonypi_setup(char *str)  {
-	int ints[7];
+	int ints[8];
 
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 	if (ints[0] <= 0) 
@@ -800,7 +852,10 @@
 	compat = ints[5];
 	if (ints[0] == 5)
 		goto out;
-	nojogdial = ints[6];
+	mask = ints[6];
+	if (ints[0] == 6)
+		goto out;
+	useinput = ints[7];
 out:
 	return 1;
 }
@@ -812,7 +867,7 @@
 module_init(sonypi_init_module);
 module_exit(sonypi_cleanup_module);
 
-MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
 MODULE_LICENSE("GPL");
 
@@ -827,7 +882,9 @@
 MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
 MODULE_PARM(compat,"i");
 MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
-MODULE_PARM(nojogdial, "i");
-MODULE_PARM_DESC(nojogdial, "set this if you have a Vaio without a jogdial (like the fx series)");
+MODULE_PARM(mask, "i");
+MODULE_PARM_DESC(mask, "set this to the mask of event you want to enable (see doc)");
+MODULE_PARM(useinput, "i");
+MODULE_PARM_DESC(useinput, "if you have a jogdial, set this if you would like it to use the modern Linux Input Driver system");
 
 EXPORT_SYMBOL(sonypi_camera_command);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.h linux-2.4.21-rc3/drivers/char/sonypi.h
--- linux-2.4.20/drivers/char/sonypi.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/sonypi.h	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -35,10 +37,17 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	13
+#define SONYPI_DRIVER_MINORVERSION	18
 
+#define SONYPI_DEVICE_MODEL_TYPE1	1
+#define SONYPI_DEVICE_MODEL_TYPE2	2
+
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/input.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
 #include "linux/sonypi.h"
 
 /* type1 models use those */
@@ -54,6 +63,20 @@
 #define SONYPI_SHIB			0x9d
 #define SONYPI_TYPE2_REGION_SIZE	0x20
 
+/* battery / brightness addresses */
+#define SONYPI_BAT_FLAGS	0x81
+#define SONYPI_LCD_LIGHT	0x96
+#define SONYPI_BAT1_PCTRM	0xa0
+#define SONYPI_BAT1_LEFT	0xa2
+#define SONYPI_BAT1_MAXRT	0xa4
+#define SONYPI_BAT2_PCTRM	0xa8
+#define SONYPI_BAT2_LEFT	0xaa
+#define SONYPI_BAT2_MAXRT	0xac
+#define SONYPI_BAT1_MAXTK	0xb0
+#define SONYPI_BAT1_FULL	0xb2
+#define SONYPI_BAT2_MAXTK	0xb8
+#define SONYPI_BAT2_FULL	0xba
+
 /* ioports used for brightness and type2 events */
 #define SONYPI_DATA_IOPORT	0x62
 #define SONYPI_CST_IOPORT	0x66
@@ -131,34 +154,47 @@
 #define SONYPI_CAMERA_REVISION 			8
 #define SONYPI_CAMERA_ROMVERSION 		9
 
-/* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV		0x10
-#define SONYPI_TYPE2_JOGGER_EV		0x08
-#define SONYPI_TYPE1_CAPTURE_EV		0x60
-#define SONYPI_TYPE2_CAPTURE_EV		0x08
-#define SONYPI_TYPE1_FNKEY_EV		0x20
-#define SONYPI_TYPE2_FNKEY_EV		0x08
-#define SONYPI_TYPE1_BLUETOOTH_EV	0x30
-#define SONYPI_TYPE2_BLUETOOTH_EV	0x08
-#define SONYPI_TYPE1_PKEY_EV		0x40
-#define SONYPI_TYPE2_PKEY_EV		0x08
-#define SONYPI_BACK_EV			0x08
-#define SONYPI_LID_EV			0x38
+/* Event masks */
+#define SONYPI_JOGGER_MASK			0x00000001
+#define SONYPI_CAPTURE_MASK			0x00000002
+#define SONYPI_FNKEY_MASK			0x00000004
+#define SONYPI_BLUETOOTH_MASK			0x00000008
+#define SONYPI_PKEY_MASK			0x00000010
+#define SONYPI_BACK_MASK			0x00000020
+#define SONYPI_HELP_MASK			0x00000040
+#define SONYPI_LID_MASK				0x00000080
+#define SONYPI_ZOOM_MASK			0x00000100
+#define SONYPI_THUMBPHRASE_MASK			0x00000200
+#define SONYPI_MEYE_MASK			0x00000400
+#define SONYPI_MEMORYSTICK_MASK			0x00000800
 
 struct sonypi_event {
 	u8	data;
 	u8	event;
 };
 
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+	{ 0, 0 }
+};
+
 /* The set of possible jogger events  */
 static struct sonypi_event sonypi_joggerev[] = {
 	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
 	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
 	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
 	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
 	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
-	{ 0x00, SONYPI_EVENT_JOGDIAL_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible capture button events */
@@ -166,8 +202,7 @@
 	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
 	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
 	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
-	{ 0x00, SONYPI_EVENT_CAPTURE_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible fnkeys events */
@@ -192,7 +227,8 @@
 	{ 0x33, SONYPI_EVENT_FNKEY_F },
 	{ 0x34, SONYPI_EVENT_FNKEY_S },
 	{ 0x35, SONYPI_EVENT_FNKEY_B },
-	{ 0x00, 0x00 }
+	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
+	{ 0, 0 }
 };
 
 /* The set of possible program key events */
@@ -200,7 +236,7 @@
 	{ 0x01, SONYPI_EVENT_PKEY_P1 },
 	{ 0x02, SONYPI_EVENT_PKEY_P2 },
 	{ 0x04, SONYPI_EVENT_PKEY_P3 },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible bluetooth events */
@@ -208,21 +244,84 @@
 	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
 	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
 	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
 	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
 	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
+
 /* The set of possible lid events */
 static struct sonypi_event sonypi_lidev[] = {
 	{ 0x51, SONYPI_EVENT_LID_CLOSED },
 	{ 0x50, SONYPI_EVENT_LID_OPENED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+	{ 0x00, SONYPI_EVENT_MEYE_FACE },
+	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+	{ 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+	{ 0, 0 }
+};
+
+struct sonypi_eventtypes {
+	int			model;
+	u8			data;
+	unsigned long		mask;
+	struct sonypi_event *	events;
+} sonypi_eventtypes[] = {
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BACK_MASK, sonypi_backev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_ZOOM_MASK, sonypi_zoomev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+
+	{ 0, 0, 0, 0 }
 };
 
 #define SONYPI_BUF_SIZE	128
@@ -236,8 +335,8 @@
 	unsigned char buf[SONYPI_BUF_SIZE];
 };
 
-#define SONYPI_DEVICE_MODEL_TYPE1	1
-#define SONYPI_DEVICE_MODEL_TYPE2	2
+/* The name of the Jog Dial for the input device drivers */
+#define SONYPI_INPUTNAME	"Sony VAIO Jog Dial"
 
 struct sonypi_device {
 	struct pci_dev *dev;
@@ -252,15 +351,56 @@
 	struct sonypi_queue queue;
 	int open_count;
 	int model;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	struct input_dev jog_dev;
+#endif
+#ifdef CONFIG_PM
+	struct pm_dev *pm;
+#endif
 };
 
-#define wait_on_command(quiet, command) { \
-	unsigned int n = 10000; \
+#define ITERATIONS_LONG		10000
+#define ITERATIONS_SHORT	10
+
+#define wait_on_command(quiet, command, iterations) { \
+	unsigned int n = iterations; \
 	while (--n && (command)) \
 		udelay(1); \
 	if (!n && (verbose || !quiet)) \
-		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \
+		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+}
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#if (ACPI_CA_VERSION > 0x20021121)
+#define USE_ACPI
+#endif
+#endif /* CONFIG_ACPI */
+
+#ifndef USE_ACPI
+extern int verbose;
+
+static inline int ec_write(u8 addr, u8 value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x81, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(value, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	return 0;
+}
+
+static inline int ec_read(u8 addr, u8 *value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x80, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	*value = inb_p(SONYPI_DATA_IOPORT);
+	return 0;
 }
+#endif /* ! USE_ACPI */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sx.c linux-2.4.21-rc3/drivers/char/sx.c
--- linux-2.4.20/drivers/char/sx.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/sx.c	2003-05-22 22:06:41.000000000 +0000
@@ -1734,8 +1734,10 @@
 				if (copy_from_user(tmp, (char *)data + i, 
 						   (i + SX_CHUNK_SIZE >
 						    nbytes) ? nbytes - i :
-						   	      SX_CHUNK_SIZE))
+						   	      SX_CHUNK_SIZE)) {
+					kfree (tmp);
 					return -EFAULT;
+				}
 				memcpy_toio    ((char *) (board->base2 + offset + i), tmp, 
 				                (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
 			}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/tipar.c linux-2.4.21-rc3/drivers/char/tipar.c
--- linux-2.4.20/drivers/char/tipar.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/tipar.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,538 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar - low level driver for handling a parallel link cable designed
+ * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Various fixes & clean-up from the Linux Kernel Mailing List
+ * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
+ */
+
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport
+ * abstraction layer.
+ *
+ * If this driver is built into the kernel, you can configure it using the
+ * kernel command-line.  For example:
+ *
+ *      tipar=timeout,delay       (set timeout and delay)
+ *
+ * If the driver is loaded as a module, similar functionality is available
+ * using module parameters.  The equivalent of the above commands would be:
+ *
+ *      # insmod tipar timeout=15 delay=10
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Usually, parallel cables were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ *      tipar0             0x378
+ *      tipar1             0x278
+ *      tipar2             0x3bc
+ *
+ *
+ * This driver, by default, binds tipar devices according to parport and
+ * the minor number.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <linux/devfs_fs_kernel.h>	/* DevFs support */
+#include <linux/parport.h>	/* Our code depend on parport */
+
+/*
+ * TI definitions
+ */
+#include <linux/ticable.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.18"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
+#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
+#define DRIVER_LICENSE "GPL"
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if LINUX_VERSION_CODE < VERSION(2,5,0)
+# define minor(x) MINOR(x)
+# define need_resched() (current->need_resched)
+#endif
+
+/* ----- global variables --------------------------------------------- */
+
+struct tipar_struct {
+	struct pardevice *dev;	/* Parport device entry */
+};
+
+#define PP_NO 3
+static struct tipar_struct table[PP_NO];
+
+static int delay = IO_DELAY;	/* inter-bit delay in microseconds */
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+static unsigned int tp_count;	/* tipar count */
+static unsigned long opened;	/* opened devices */
+
+/* --- macros for parport access -------------------------------------- */
+
+#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
+#define r_str(x)        (parport_read_status(table[(x)].dev->port))
+#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
+#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
+
+/* --- setting states on the D-bus with the right timing: ------------- */
+
+static inline void
+outbyte(int value, int minor)
+{
+	w_dtr(minor, value);
+}
+
+static inline int
+inbyte(int minor)
+{
+	return (r_str(minor));
+}
+
+static inline void
+init_ti_parallel(int minor)
+{
+	outbyte(3, minor);
+}
+
+/* ----- global defines ----------------------------------------------- */
+
+#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define WAIT(x)  { \
+  if (time_before((x), jiffies)) return -1; \
+  if (need_resched()) schedule(); }
+
+/* ----- D-bus bit-banging functions ---------------------------------- */
+
+/* D-bus protocol (45kbit/s max):
+                    1                 0                      0
+       _______        ______|______    __________|________    __________
+Red  :        ________      |      ____          |        ____
+       _        ____________|________      ______|__________       _____
+White:  ________            |        ______      |          _______
+*/
+
+/* Try to transmit a byte on the specified port (-1 if error). */
+static int
+put_ti_parallel(int minor, unsigned char data)
+{
+	int bit;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		if (data & 1) {
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x10);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+		} else {
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x20);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+		}
+
+		data >>= 1;
+		udelay(delay);
+
+		if (need_resched())
+			schedule();
+	}
+
+	return 0;
+}
+
+/* Receive a byte on the specified port or -1 if error. */
+static int
+get_ti_parallel(int minor)
+{
+	int bit;
+	unsigned char v, data = 0;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		START(max);
+		do {
+			WAIT(max);
+		} while ((v = inbyte(minor) & 0x30) == 0x30);
+
+		if (v == 0x10) {
+			data = (data >> 1) | 0x80;
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+			outbyte(3, minor);
+		} else {
+			data = data >> 1;
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+			outbyte(3, minor);
+		}
+
+		udelay(delay);
+		if (need_resched())
+			schedule();
+	}
+
+	return (int) data;
+}
+
+/* Try to detect a parallel link cable on the specified port */
+static int
+probe_ti_parallel(int minor)
+{
+	int i;
+	int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+
+	for (i = 3; i >= 0; i--) {
+		outbyte(3, minor);
+		outbyte(i, minor);
+		udelay(delay);
+		/*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
+		if ((inbyte(minor) & 0x30) != seq[i]) {
+			outbyte(3, minor);
+			return -1;
+		}
+	}
+
+	outbyte(3, minor);
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int
+tipar_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	if (test_and_set_bit(minor, &opened))
+		return -EBUSY;
+
+	parport_claim_or_block(table[minor].dev);
+	init_ti_parallel(minor);
+	parport_release(table[minor].dev);
+
+	return 0;
+}
+
+static int
+tipar_close(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	clear_bit(minor, &opened);
+
+	return 0;
+}
+
+static ssize_t
+tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t n;
+
+	parport_claim_or_block(table[minor].dev);
+
+	for (n = 0; n < count; n++) {
+		unsigned char b;
+
+		if (get_user(b, buf + n)) {
+			n = -EFAULT;
+			goto out;
+		}
+
+		if (put_ti_parallel(minor, b) == -1) {
+			init_ti_parallel(minor);
+			n = -ETIMEDOUT;
+			goto out;
+		}
+	}
+      out:
+	parport_release(table[minor].dev);
+	return n;
+}
+
+static ssize_t
+tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	int b = 0;
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t retval = 0;
+	ssize_t n = 0;
+
+	if (count == 0)
+		return 0;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	parport_claim_or_block(table[minor].dev);
+
+	while (n < count) {
+		b = get_ti_parallel(minor);
+		if (b == -1) {
+			init_ti_parallel(minor);
+			retval = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (put_user(b, ((unsigned char *) buf) + n)) {
+				retval = -EFAULT;
+				break;
+			} else
+				retval = ++n;
+		}
+
+		/* Non-blocking mode : try again ! */
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		/* Signal pending, try again ! */
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		if (need_resched())
+			schedule();
+	}
+
+      out:
+	parport_release(table[minor].dev);
+	return retval;
+}
+
+static int
+tipar_ioctl(struct inode *inode, struct file *file,
+	    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case IOCTL_TIPAR_DELAY:
+	  delay = (int)arg;    //get_user(delay, &arg);
+	  break;
+	case IOCTL_TIPAR_TIMEOUT:
+	  timeout = (int)arg;  //get_user(timeout, &arg);
+	  break;
+	default:
+		retval = -ENOTTY;
+		break;
+	}
+
+	return retval;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tipar_fops = {
+	owner:THIS_MODULE,
+	llseek:no_llseek,
+	read:tipar_read,
+	write:tipar_write,
+	ioctl:tipar_ioctl,
+	open:tipar_open,
+	release:tipar_close,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init
+tipar_setup(char *str)
+{
+	int ints[2];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+		if (ints[0] > 1) {
+			delay = ints[2];
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * Register our module into parport.
+ * Pass also 2 callbacks functions to parport: a pre-emptive function and an
+ * interrupt handler function (unused).
+ * Display a message such "tipar0: using parport0 (polling)".
+ */
+static int
+tipar_register(int nr, struct parport *port)
+{
+	char name[8];
+
+	/* Register our module into parport */
+	table[nr].dev = parport_register_device(port, "tipar",
+						NULL, NULL, NULL, 0,
+						(void *) &table[nr]);
+
+	if (table[nr].dev == NULL)
+		return 1;
+
+	/* Use devfs, tree: /dev/ticables/par/[0..2] */
+	sprintf(name, "%d", nr);
+	printk
+	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
+	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
+	devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
+		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
+		       &tipar_fops, NULL);
+
+	/* Display informations */
+	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
+	       (port->irq ==
+		PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
+
+	if (probe_ti_parallel(nr) != -1)
+		printk("tipar%d: link cable found !\n", nr);
+	else
+		printk("tipar%d: link cable not found.\n", nr);
+
+	return 0;
+}
+
+static void
+tipar_attach(struct parport *port)
+{
+	if (tp_count == PP_NO) {
+		printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
+		return;
+	}
+
+	if (!tipar_register(tp_count, port))
+		tp_count++;
+}
+
+static void
+tipar_detach(struct parport *port)
+{
+	/* Nothing to do */
+}
+
+static struct parport_driver tipar_driver = {
+	"tipar",
+	tipar_attach,
+	tipar_detach,
+	NULL
+};
+
+int __init
+tipar_init_module(void)
+{
+	printk("tipar: parallel link cable driver, version %s\n",
+	       DRIVER_VERSION);
+
+	if (devfs_register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
+		printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs with tree: /dev/ticables/par/[0..2] */
+	devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
+
+	if (parport_register_driver(&tipar_driver)) {
+		printk("tipar: unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void __exit
+tipar_cleanup_module(void)
+{
+	unsigned int i;
+
+	/* Unregistering module */
+	parport_unregister_driver(&tipar_driver);
+
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(TIPAR_MAJOR, "tipar");
+
+	for (i = 0; i < PP_NO; i++) {
+		if (table[i].dev == NULL)
+			continue;
+		parport_unregister_device(table[i].dev);
+	}
+
+	printk("tipar: module unloaded !\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup("tipar=", tipar_setup);
+module_init(tipar_init_module);
+module_exit(tipar_cleanup_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM(delay, "i");
+MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/tty_io.c linux-2.4.21-rc3/drivers/char/tty_io.c
--- linux-2.4.20/drivers/char/tty_io.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/tty_io.c	2003-05-22 22:06:48.000000000 +0000
@@ -127,12 +127,6 @@
 extern struct tty_driver pts_driver[];	/* Unix98 pty slaves;  for /dev/ptmx */
 #endif
 
-/*
- * redirect is the pseudo-tty that console output
- * is redirected to if asked by TIOCCONS.
- */
-struct tty_struct * redirect;
-
 static void initialize_tty_struct(struct tty_struct *tty);
 
 static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
@@ -427,6 +421,8 @@
 	release:	tty_release,
 };
 
+static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
+static struct file *redirect;
 /*
  * This can be called by the "eventd" kernel thread.  That is process synchronous,
  * but doesn't hold any locks, so we need to make sure we have the appropriate
@@ -436,6 +432,7 @@
 {
 	struct tty_struct *tty = (struct tty_struct *) data;
 	struct file * cons_filp = NULL;
+	struct file *f = NULL;
 	struct task_struct *p;
 	struct list_head *l;
 	int    closecount = 0, n;
@@ -445,6 +442,15 @@
 
 	/* inuse_filps is protected by the single kernel lock */
 	lock_kernel();
+
+	spin_lock(&redirect_lock);
+	if (redirect && redirect->private_data == tty) {
+		f = redirect;
+		redirect = NULL;
+	}
+	spin_unlock(&redirect_lock);
+	if (f)
+		fput(f);
 	
 	check_tty_count(tty, "do_tty_hangup");
 	file_list_lock();
@@ -743,11 +749,7 @@
 {
 	int is_console;
 	struct tty_struct * tty;
-	struct inode *inode;
-
-	/* Can't seek (pwrite) on ttys.  */
-	if (ppos != &file->f_pos)
-		return -ESPIPE;
+	struct inode *inode = file->f_dentry->d_inode;
 
 	/*
 	 *      For now, we redirect writes from /dev/console as
@@ -757,10 +759,28 @@
 	is_console = (inode->i_rdev == SYSCONS_DEV ||
 		      inode->i_rdev == CONSOLE_DEV);
 
-	if (is_console && redirect)
-		tty = redirect;
-	else
-		tty = (struct tty_struct *)file->private_data;
+	if (is_console) {
+		struct file *p = NULL;
+
+		spin_lock(&redirect_lock);
+		if (redirect) {
+			get_file(redirect);
+			p = redirect;
+		}
+		spin_unlock(&redirect_lock);
+
+		if (p) {
+			ssize_t res = p->f_op->write(p, buf, count, ppos);
+			fput(p);
+			return res;
+		}
+	}
+
+	/* Can't seek (pwrite) on ttys.  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	tty = (struct tty_struct *)file->private_data;
 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
 		return -EIO;
 	if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags)))
@@ -1223,7 +1243,7 @@
 	/*
 	 * If _either_ side is closing, make sure there aren't any
 	 * processes that still think tty or o_tty is their controlling
-	 * tty.  Also, clear redirect if it points to either tty.
+	 * tty.
 	 */
 	if (tty_closing || o_tty_closing) {
 		struct task_struct *p;
@@ -1234,9 +1254,6 @@
 				p->tty = NULL;
 		}
 		read_unlock(&tasklist_lock);
-
-		if (redirect == tty || (o_tty && redirect == o_tty))
-			redirect = NULL;
 	}
 
 	/* check whether both sides are closing ... */
@@ -1515,19 +1532,29 @@
 	return 0;
 }
 
-static int tioccons(struct inode *inode,
-	struct tty_struct *tty, struct tty_struct *real_tty)
+static int tioccons(struct inode *inode, struct file *file)
 {
 	if (inode->i_rdev == SYSCONS_DEV ||
 	    inode->i_rdev == CONSOLE_DEV) {
+		struct file *f;
 		if (!suser())
 			return -EPERM;
+		spin_lock(&redirect_lock);
+		f = redirect;
 		redirect = NULL;
+		spin_unlock(&redirect_lock);
+		if (f)
+			fput(f);
 		return 0;
 	}
-	if (redirect)
+	spin_lock(&redirect_lock);
+	if (redirect) {
+		spin_unlock(&redirect_lock);
 		return -EBUSY;
-	redirect = real_tty;
+	}
+	get_file(file);
+	redirect = file;
+	spin_unlock(&redirect_lock);
 	return 0;
 }
 
@@ -1747,7 +1774,7 @@
 		case TIOCSWINSZ:
 			return tiocswinsz(tty, real_tty, (struct winsize *) arg);
 		case TIOCCONS:
-			return tioccons(inode, tty, real_tty);
+			return real_tty!=tty ? -EINVAL : tioccons(inode, file);
 		case FIONBIO:
 			return fionbio(file, (int *) arg);
 		case TIOCEXCL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/wdt285.c linux-2.4.21-rc3/drivers/char/wdt285.c
--- linux-2.4.20/drivers/char/wdt285.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-rc3/drivers/char/wdt285.c	2003-05-22 22:06:38.000000000 +0000
@@ -179,10 +179,15 @@
 
 static int __init footbridge_watchdog_init(void)
 {
+	int retval;
+
 	if (machine_is_netwinder())
 		return -ENODEV;
 
-	misc_register(&watchdog_miscdev);
+	retval = misc_register(&watchdog_miscdev);
+	if(retval < 0)
+		return retval;
+
 	printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", 
 	       soft_margin);
 	if (machine_is_cats())
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/dino.c linux-2.4.21-rc3/drivers/gsc/dino.c
--- linux-2.4.20/drivers/gsc/dino.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/gsc/dino.c	2003-05-22 22:06:53.000000000 +0000
@@ -436,7 +436,7 @@
 	if (mask) {
 		if (--ilr_loop > 0)
 			goto ilr_again;
-		printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
+		printk("Dino %lx: IRQ base %d, stuck IRQ lines? 0x%x\n", dino_dev->hba.base_addr, dino_dev->dino_region->data.irqbase, mask);
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/lasi.c linux-2.4.21-rc3/drivers/gsc/lasi.c
--- linux-2.4.20/drivers/gsc/lasi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/gsc/lasi.c	2003-05-22 22:06:40.000000000 +0000
@@ -26,7 +26,7 @@
 #include <asm/gsc.h>
 #include <asm/hardware.h>
 #include <asm/led.h>
-
+#include <asm/pdc.h>
 #include "busdevice.h"
 
 
@@ -77,7 +77,10 @@
 
 	/* Resets */
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
-	gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
+	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
+		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
 	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_kbd.c linux-2.4.21-rc3/drivers/hil/hil_kbd.c
--- linux-2.4.20/drivers/hil/hil_kbd.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hil/hil_kbd.c	2003-05-22 22:06:24.000000000 +0000
@@ -431,9 +431,9 @@
 
 
 struct serio_dev hil_kbd_serio_dev = {
-	connect:	hil_kbd_connect,
-	disconnect:	hil_kbd_disconnect,
-	interrupt:	hil_kbd_interrupt
+	.connect =	hil_kbd_connect,
+	.disconnect =	hil_kbd_disconnect,
+	.interrupt =	hil_kbd_interrupt
 };
 
 static int __init hil_kbd_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_ptr.c linux-2.4.21-rc3/drivers/hil/hil_ptr.c
--- linux-2.4.20/drivers/hil/hil_ptr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hil/hil_ptr.c	2003-05-22 22:06:52.000000000 +0000
@@ -386,9 +386,9 @@
 
 
 struct serio_dev hil_ptr_serio_dev = {
-	connect: hil_ptr_connect,
-	disconnect: hil_ptr_disconnect,
-	interrupt: hil_ptr_interrupt
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
 };
 
 static int __init hil_ptr_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hilkbd.c linux-2.4.21-rc3/drivers/hil/hilkbd.c
--- linux-2.4.20/drivers/hil/hilkbd.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hil/hilkbd.c	2003-05-22 22:06:48.000000000 +0000
@@ -348,9 +348,9 @@
 MODULE_DEVICE_TABLE(parisc, hil_tbl);
 
 static struct parisc_driver hil_driver = {
-	name:		"HIL",
-	id_table:	hil_tbl,
-	probe:		hil_init_chip,
+	.name =		"HIL",
+	.id_table =	hil_tbl,
+	.probe =	hil_init_chip,
 };
 #endif /* CONFIG_PARISC */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc.c linux-2.4.21-rc3/drivers/hil/hp_sdc.c
--- linux-2.4.20/drivers/hil/hp_sdc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hil/hp_sdc.c	2003-05-22 22:06:38.000000000 +0000
@@ -745,10 +745,10 @@
 
 static struct parisc_device_id hp_sdc_tbl[] = {
 	{
-		hw_type:	HPHW_FIO, 
-		hversion_rev:	HVERSION_REV_ANY_ID,
-		hversion:	HVERSION_ANY_ID,
-		sversion:	0x73, 
+		.hw_type =	HPHW_FIO, 
+		.hversion_rev =	HVERSION_REV_ANY_ID,
+		.hversion =	HVERSION_ANY_ID,
+		.sversion =	0x73, 
 	 },
 	{ 0, }
 };
@@ -758,9 +758,9 @@
 static int __init hp_sdc_init(struct parisc_device *d);
 
 static struct parisc_driver hp_sdc_driver = {
-	name:		"HP SDC",
-	id_table:	hp_sdc_tbl,
-	probe:		hp_sdc_init,
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init,
 };
 
 static int __init hp_sdc_init(struct parisc_device *d)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc_rtc.c linux-2.4.21-rc3/drivers/hil/hp_sdc_rtc.c
--- linux-2.4.20/drivers/hil/hp_sdc_rtc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hil/hp_sdc_rtc.c	2003-05-22 22:06:47.000000000 +0000
@@ -674,20 +674,20 @@
 }
 
 static struct file_operations hp_sdc_rtc_fops = {
-        owner:          THIS_MODULE,
-        llseek:         hp_sdc_rtc_llseek,
-        read:           hp_sdc_rtc_read,
-        poll:           hp_sdc_rtc_poll,
-        ioctl:          hp_sdc_rtc_ioctl,
-        open:           hp_sdc_rtc_open,
-        release:        hp_sdc_rtc_release,
-        fasync:         hp_sdc_rtc_fasync,
+        .owner =	THIS_MODULE,
+        .llseek =	hp_sdc_rtc_llseek,
+        .read =		hp_sdc_rtc_read,
+        .poll =		hp_sdc_rtc_poll,
+        .ioctl =	hp_sdc_rtc_ioctl,
+        .open =		hp_sdc_rtc_open,
+        .release =	hp_sdc_rtc_release,
+        .fasync =	hp_sdc_rtc_fasync,
 };
 
 static struct miscdevice hp_sdc_rtc_dev = {
-        minor:		RTC_MINOR,
-        name:		"rtc",
-        fops:		&hp_sdc_rtc_fops
+        .minor =	RTC_MINOR,
+        .name =		"rtc",
+        .fops =		&hp_sdc_rtc_fops
 };
 
 static int __init hp_sdc_rtc_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/Makefile linux-2.4.21-rc3/drivers/hotplug/Makefile
--- linux-2.4.20/drivers/hotplug/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/Makefile	2003-05-22 22:06:27.000000000 +0000
@@ -29,9 +29,6 @@
 
 ifdef CONFIG_HOTPLUG_PCI_ACPI
   EXTRA_CFLAGS	+= -D_LINUX -I$(CURDIR)/../acpi
-  ifdef CONFIG_ACPI_DEBUG
-    EXTRA_CFLAGS += -DACPI_DEBUG -Wno-unused
-  endif
 endif
 
 acpiphp_objs		:=	acpiphp_core.o	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp.h linux-2.4.21-rc3/drivers/hotplug/acpiphp.h
--- linux-2.4.20/drivers/hotplug/acpiphp.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/acpiphp.h	2003-05-22 22:06:25.000000000 +0000
@@ -97,17 +97,17 @@
 
 #define dbg(format, arg...)					\
 	do {							\
-		if (debug)					\
-			printk (KERN_DEBUG "%s: " format "\n",	\
+		if (acpiphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
 				MY_NAME , ## arg); 		\
 	} while (0)
-#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
-#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
-#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
 #define SLOT_MAGIC	0x67267322
 /* name size which is used for entries in pcihpfs */
-#define SLOT_NAME_SIZE	16		/* ACPIxxxx */
+#define SLOT_NAME_SIZE	32		/* ACPI{_SUN}-{BUS}:{DEV} */
 
 struct acpiphp_bridge;
 struct acpiphp_slot;
@@ -122,8 +122,6 @@
 	struct hotplug_slot	*hotplug_slot;
 	struct list_head	slot_list;
 
-	/* if there are multiple corresponding ACPI slot objects,
-	   this points to one of them */
 	struct acpiphp_slot	*acpi_slot;
 };
 
@@ -175,8 +173,6 @@
 	/* PCI-to-PCI bridge device */
 	struct pci_dev *pci_dev;
 
-	struct pci_ops *pci_ops;
-
 	/* ACPI 2.0 _HPP parameters */
 	struct hpp_param hpp;
 
@@ -200,7 +196,6 @@
 	struct acpiphp_bridge *bridge;	/* parent */
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
-	struct acpiphp_func *func;	/* functions */
 	struct semaphore crit_sect;
 
 	u32		id;		/* slot id (serial #) for hotplug core */
@@ -213,7 +208,7 @@
 
 
 /**
- * struct acpiphp_func - PCI slot information
+ * struct acpiphp_func - PCI function information
  *
  * PCI function information for each object in ACPI namespace
  * typically 8 objects per slot (i.e. for each PCI function)
@@ -319,4 +314,7 @@
 extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
 extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
 
+/* variables */
+extern int acpiphp_debug;
+
 #endif /* _ACPIPHP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_core.c linux-2.4.21-rc3/drivers/hotplug/acpiphp_core.c
--- linux-2.4.20/drivers/hotplug/acpiphp_core.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/acpiphp_core.c	2003-05-22 22:06:51.000000000 +0000
@@ -50,12 +50,14 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
+static int debug;
+int acpiphp_debug;
+
 /* local variables */
-static int debug = 1;			/* XXX set to 0 after debug */
 static int num_slots;
 
-#define DRIVER_VERSION	"0.3"
-#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>"
 #define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -72,17 +74,21 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
 static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	enable_slot:		enable_slot,
-	disable_slot:		disable_slot,
-	set_attention_status:	set_attention_status,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.hardware_test		= hardware_test,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_latch_status	= get_latch_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_max_bus_speed	= get_max_bus_speed,
+	.get_cur_bus_speed	= get_cur_bus_speed,
 };
 
 
@@ -90,15 +96,15 @@
 static inline int slot_paranoia_check (struct slot *slot, const char *function)
 {
 	if (!slot) {
-		dbg("%s - slot == NULL", function);
+		dbg("%s - slot == NULL\n", function);
 		return -1;
 	}
 	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
+		dbg("%s - bad magic number for slot\n", function);
 		return -1;
 	}
 	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
+		dbg("%s - slot->hotplug_slot == NULL!\n", function);
 		return -1;
 	}
 	return 0;
@@ -106,16 +112,16 @@
 
 
 static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{ 
+{
 	struct slot *slot;
 
 	if (!hotplug_slot) {
-		dbg("%s - hotplug_slot == NULL", function);
+		dbg("%s - hotplug_slot == NULL\n", function);
 		return NULL;
 	}
 
 	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
+	if (slot_paranoia_check(slot, function))
                 return NULL;
 	return slot;
 }
@@ -130,16 +136,16 @@
  */
 static int enable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
 
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* enable the specified slot */
-	retval = acpiphp_enable_slot (slot->acpi_slot);
+	retval = acpiphp_enable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -154,16 +160,16 @@
  */
 static int disable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
 
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot (slot->acpi_slot);
+	retval = acpiphp_disable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -180,8 +186,8 @@
 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
 {
 	int retval = 0;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	switch (status) {
 		case 0:
@@ -208,15 +214,15 @@
  */
 static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	err ("No hardware tests are defined for this driver");
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	err("No hardware tests are defined for this driver\n");
 	retval = -ENODEV;
 
 	return retval;
@@ -234,15 +240,15 @@
  */
 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_power_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -258,8 +264,8 @@
 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
 	int retval = 0;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	*value = hotplug_slot->info->attention_status;
 
@@ -278,15 +284,15 @@
  */
 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_latch_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -303,20 +309,48 @@
  */
 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_adapter_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	return retval;
 }
 
 
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
 static int init_acpi (void)
 {
 	int retval;
@@ -335,13 +369,6 @@
 }
 
 
-static void exit_acpi (void)
-{
-	/* deallocate internal data structures etc. */
-	acpiphp_glue_exit();
-}
-
-
 /**
  * make_slot_name - make a slot name that appears in pcihpfs
  * @slot: slot to name
@@ -349,7 +376,10 @@
  */
 static void make_slot_name (struct slot *slot)
 {
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
+		 slot->acpi_slot->sun,
+		 slot->acpi_slot->bridge->bus,
+		 slot->acpi_slot->device);
 }
 
 /**
@@ -363,31 +393,31 @@
 	int i;
 
 	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
 		if (!slot)
 			return -ENOMEM;
 		memset(slot, 0, sizeof(struct slot));
 
-		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
 		if (!slot->hotplug_slot) {
-			kfree (slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+		memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
 
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
 		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
 
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
 		if (!slot->hotplug_slot->name) {
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
 
@@ -397,26 +427,27 @@
 		slot->hotplug_slot->private = slot;
 		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
 
-		slot->acpi_slot = get_slot_from_id (i);
+		slot->acpi_slot = get_slot_from_id(i);
 		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
 		slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
 		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
 		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
-		make_slot_name (slot);
+		make_slot_name(slot);
 
-		retval = pci_hp_register (slot->hotplug_slot);
+		retval = pci_hp_register(slot->hotplug_slot);
 		if (retval) {
-			err ("pci_hp_register failed with error %d", retval);
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot->name);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			err("pci_hp_register failed with error %d\n", retval);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot->name);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return retval;
 		}
 
 		/* add slot to our internal list */
-		list_add (&slot->slot_list, &slot_list);
+		list_add(&slot->slot_list, &slot_list);
+		info("Slot [%s] registered\n", slot->hotplug_slot->name);
 	}
 
 	return retval;
@@ -425,17 +456,17 @@
 
 static void cleanup_slots (void)
 {
-	struct list_head *tmp;
+	struct list_head *tmp, *n;
 	struct slot *slot;
 
-	list_for_each (tmp, &slot_list) {
-		slot = list_entry (tmp, struct slot, slot_list);
-		list_del (&slot->slot_list);
-		pci_hp_deregister (slot->hotplug_slot);
-		kfree (slot->hotplug_slot->info);
-		kfree (slot->hotplug_slot->name);
-		kfree (slot->hotplug_slot);
-		kfree (slot);
+	list_for_each_safe (tmp, n, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot->name);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
 	}
 
 	return;
@@ -446,6 +477,10 @@
 {
 	int retval;
 
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	acpiphp_debug = debug;
+
 	/* read all the ACPI info from the system */
 	retval = init_acpi();
 	if (retval)
@@ -455,7 +490,6 @@
 	if (retval)
 		return retval;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
 	return 0;
 }
 
@@ -463,7 +497,8 @@
 static void __exit acpiphp_exit(void)
 {
 	cleanup_slots();
-	exit_acpi();
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
 }
 
 module_init(acpiphp_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_glue.c linux-2.4.21-rc3/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.20/drivers/hotplug/acpiphp_glue.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/acpiphp_glue.c	2003-05-22 22:06:40.000000000 +0000
@@ -39,12 +39,10 @@
 
 static LIST_HEAD(bridge_list);
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_glue"
 
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void handle_hotplug_event_func (acpi_handle, u32, void *);
-static struct pci_ops *default_ops;
 
 /*
  * initialization & terminatation routines
@@ -90,8 +88,6 @@
 static acpi_status
 is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
 {
-	acpi_status status;
-	acpi_handle tmp;
 	int *count = (int *)context;
 
 	if (is_ejectable(handle)) {
@@ -157,7 +153,7 @@
 	for (slot = bridge->slots; slot; slot = slot->next)
 		if (slot->device == device) {
 			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!");
+				warn("sibling found, but _SUN doesn't match!\n");
 			break;
 		}
 
@@ -181,7 +177,7 @@
 
 		bridge->nr_slots++;
 
-		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d",
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
 		    slot->bridge->bus, slot->device, slot->sun);
 	}
 
@@ -206,7 +202,7 @@
 					     newfunc);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 		return status;
 	}
 
@@ -306,21 +302,21 @@
 			switch (resource_type) {
 			case ACPI_MEMORY_RANGE:
 				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: prefetchable memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->p_mem_head;
 					bridge->p_mem_head = res;
 				} else {
-					dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->mem_head;
@@ -328,22 +324,22 @@
 				}
 				break;
 			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: io 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->io_head;
 				bridge->io_head = res;
 				break;
 			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: bus number %d - %d\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->bus_head;
@@ -360,10 +356,9 @@
 	acpiphp_resource_sort_and_combine(&bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->bus_head);
-#if 1
-	info("ACPI _CRS resource:");
+
+	dbg("ACPI _CRS resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -372,7 +367,7 @@
 {
 	const struct list_head *l;
 
-	list_for_each(l, list) {
+	list_for_each (l, list) {
 		struct pci_bus *b = pci_bus_b(l);
 		if (b->number == bus)
 			return b;
@@ -386,7 +381,7 @@
 		}
 	}
 
-	return 0;
+	return NULL;
 }
 
 
@@ -397,7 +392,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	acpi_object *package;
 	int i;
@@ -425,7 +421,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		dbg("_HPP evaluation failed");
+		dbg("_HPP evaluation failed\n");
 		return;
 	}
 
@@ -433,13 +429,13 @@
 
 	if (!package || package->type != ACPI_TYPE_PACKAGE ||
 	    package->package.count != 4 || !package->package.elements) {
-		err("invalid _HPP object; ignoring");
+		err("invalid _HPP object; ignoring\n");
 		goto err_exit;
 	}
 
 	for (i = 0; i < 4; i++) {
 		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
-			err("invalid _HPP parameter type; ignoring");
+			err("invalid _HPP parameter type; ignoring\n");
 			goto err_exit;
 		}
 	}
@@ -449,7 +445,7 @@
 	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
 	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
 
-	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
 	    bridge->hpp.cache_line_size,
 	    bridge->hpp.latency_timer,
 	    bridge->hpp.enable_SERR,
@@ -484,15 +480,13 @@
 					     bridge);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 	}
 
 	list_add(&bridge->list, &bridge_list);
 
-#if 1
-	dbg("Bridge resource:");
+	dbg("Bridge resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -503,7 +497,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	struct acpiphp_bridge *bridge;
 
@@ -519,7 +514,6 @@
 	bridge->bus = bus;
 
 	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -545,7 +539,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to decode bridge resources");
+		err("failed to decode bridge resources\n");
 		kfree(bridge);
 		return;
 	}
@@ -565,17 +559,15 @@
 /* allocate and initialize PCI-to-PCI bridge data structure */
 static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn)
 {
-	acpi_status status;
 	struct acpiphp_bridge *bridge;
 	u8 tmp8;
 	u16 tmp16;
-	u32 tmp;
 	u64 base64, limit64;
 	u32 base, limit, base32u, limit32u;
 
 	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
 	if (bridge == NULL) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
 
@@ -587,18 +579,17 @@
 
 	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
 	if (!bridge->pci_dev) {
-		err("Can't get pci_dev");
+		err("Can't get pci_dev\n");
 		kfree(bridge);
 		return;
 	}
 
 	bridge->pci_bus = bridge->pci_dev->subordinate;
 	if (!bridge->pci_bus) {
-		err("This is not a PCI-to-PCI bridge!");
+		err("This is not a PCI-to-PCI bridge!\n");
 		kfree(bridge);
 		return;
 	}
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -621,10 +612,10 @@
 		limit = ((limit << 8) & 0xf000) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("16bit I/O range: %04x-%04x",
+		dbg("16bit I/O range: %04x-%04x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
@@ -635,18 +626,18 @@
 		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit I/O range: %08x-%08x",
+		dbg("32bit I/O range: %08x-%08x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
 	case 0x0f:
-		dbg("I/O space unsupported");
+		dbg("I/O space unsupported\n");
 		break;
 	default:
-		warn("Unknown I/O range type");
+		warn("Unknown I/O range type\n");
 	}
 
 	/* Memory resources (mandatory for P2P bridge) */
@@ -656,10 +647,10 @@
 	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
 	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 	if (!bridge->mem_head) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
-	dbg("32bit Memory range: %08x-%08x",
+	dbg("32bit Memory range: %08x-%08x\n",
 	    (u32)bridge->mem_head->base,
 	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
 
@@ -675,10 +666,10 @@
 		limit = ((limit & 0xfff0) << 16) | 0xfffff;
 		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit Prefetchable memory range: %08x-%08x",
+		dbg("32bit Prefetchable memory range: %08x-%08x\n",
 		    (u32)bridge->p_mem_head->base,
 		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
 		break;
@@ -690,10 +681,10 @@
 
 		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
 		    (u32)(bridge->p_mem_head->base >> 32),
 		    (u32)(bridge->p_mem_head->base & 0xffffffff),
 		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
@@ -702,7 +693,7 @@
 	case 0x0f:
 		break;
 	default:
-		warn("Unknown prefetchale memory type");
+		warn("Unknown prefetchale memory type\n");
 	}
 
 	init_bridge_misc(bridge);
@@ -719,7 +710,6 @@
 	unsigned long tmp;
 	int seg, bus, device, function;
 	struct pci_dev *dev;
-	u32 val;
 
 	/* get PCI address */
 	seg = (*segbus >> 8) & 0xff;
@@ -731,7 +721,7 @@
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
 		return AE_OK;
 	}
 
@@ -748,7 +738,7 @@
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
+		dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name);
 		add_p2p_bridge(handle, seg, bus, device, function);
 	}
 
@@ -763,14 +753,13 @@
 	unsigned long tmp;
 	int seg, bus;
 	acpi_handle dummy_handle;
-	int sta = -1;
 
 	/* if the bridge doesn't have _STA, we assume it is always there */
 	status = acpi_get_handle(handle, "_STA", &dummy_handle);
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
 		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			dbg("%s: _STA evaluation failure\n", __FUNCTION__);
 			return 0;
 		}
 		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
@@ -789,13 +778,13 @@
 	if (ACPI_SUCCESS(status)) {
 		bus = tmp;
 	} else {
-		warn("can't get bus number, assuming 0");
+		warn("can't get bus number, assuming 0\n");
 		bus = 0;
 	}
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI host-bus bridge with hot-pluggable slots");
+		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
 		add_host_bridge(handle, seg, bus);
 		return 0;
 	}
@@ -807,7 +796,7 @@
 				     find_p2p_bridge, &tmp, NULL);
 
 	if (ACPI_FAILURE(status))
-		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
 
 	return 0;
 }
@@ -820,21 +809,23 @@
 	acpi_status status;
 	acpi_device_info info;
 	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	status = acpi_get_object_info(handle, &info);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
+		dbg("%s: failed to get bridge information\n", __FUNCTION__);
 		return AE_OK;		/* continue */
 	}
 
 	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
 
-	/* TBD check _CID also */
-	if (strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
-
+	/* TBD use acpi_get_devices() API */
+	if (info.current_status &&
+	    (info.valid & ACPI_VALID_HID) &&
+	    strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
 		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("checking PCI-hotplug capable bridges under [%s]", objname);
+		dbg("checking PCI-hotplug capable bridges under [%s]\n", objname);
 		add_bridges(handle);
 	}
 	return AE_OK;
@@ -852,15 +843,15 @@
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed", __FUNCTION__);
+				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -890,27 +881,27 @@
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS3) {
-			dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed", __FUNCTION__);
+				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
 		}
 	}
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_EJ0) {
-			dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
@@ -920,7 +911,7 @@
 
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed", __FUNCTION__);
+				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -946,7 +937,6 @@
  */
 static int enable_device (struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	u8 bus;
 	struct pci_dev dev0, *dev;
 	struct pci_bus *child;
@@ -961,7 +951,7 @@
 	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
 	if (dev) {
 		/* This case shouldn't happen */
-		err("pci_dev structure already exists.");
+		err("pci_dev structure already exists.\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -981,7 +971,7 @@
 	dev = pci_scan_slot (&dev0);
 
 	if (!dev) {
-		err("No new device found");
+		err("No new device found\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -993,7 +983,7 @@
 	}
 
 	/* associate pci_dev to our representation */
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		func->pci_dev = pci_find_slot(slot->bridge->bus,
@@ -1010,10 +1000,8 @@
 
 	slot->flags |= SLOT_ENABLED;
 
-#if 1
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	return retval;
@@ -1028,20 +1016,19 @@
 	int retval = 0;
 	struct acpiphp_func *func;
 	struct list_head *l;
-	acpi_status status;
 
 	/* is this slot already disabled? */
 	if (!(slot->flags & SLOT_ENABLED))
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->pci_dev) {
 			if (acpiphp_unconfigure_function(func) == 0) {
 				func->pci_dev = NULL;
 			} else {
-				err("failed to unconfigure device");
+				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
@@ -1070,12 +1057,11 @@
 {
 	acpi_status status;
 	unsigned long sta = 0;
-	int fn;
 	u32 dvid;
 	struct list_head *l;
 	struct acpiphp_func *func;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_STA) {
@@ -1083,11 +1069,9 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			pci_read_config_dword_nodev(default_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
-						    PCI_VENDOR_ID, &dvid);
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, func->function),
+					PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				sta = ACPI_STA_ALL;
 				break;
@@ -1106,7 +1090,7 @@
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_bridge structure
  *
@@ -1117,7 +1101,8 @@
 {
 	struct acpiphp_bridge *bridge;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	bridge = (struct acpiphp_bridge *)context;
 
@@ -1126,28 +1111,28 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1156,7 +1141,7 @@
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_func structure
  *
@@ -1167,7 +1152,8 @@
 {
 	struct acpiphp_func *func;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1176,29 +1162,29 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_enable_slot(func->slot);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(func->slot->bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		acpiphp_disable_slot(func->slot);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1215,17 +1201,12 @@
 	if (list_empty(&pci_root_buses))
 		return -1;
 
-	/* set default pci_ops for configuration space operation */
-	default_ops = pci_bus_b(pci_root_buses.next)->ops;
-	if (!default_ops)
-		return -1;
-
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 				     ACPI_UINT32_MAX, find_host_bridge,
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status)) {
-		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1240,19 +1221,19 @@
  */
 void acpiphp_glue_exit (void)
 {
-	struct list_head *node, *shead, *l, *n;
+	struct list_head *l1, *l2, *n1, *n2;
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot, *next;
 	struct acpiphp_func *func;
 	acpi_status status;
 
-	list_for_each(node, &bridge_list) {
-		bridge = (struct acpiphp_bridge *)node;
+	list_for_each_safe (l1, n1, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)l1;
 		slot = bridge->slots;
 		while (slot) {
 			next = slot->next;
-			list_for_each_safe(l, n, &slot->funcs) {
-				func = list_entry(l, struct acpiphp_func, sibling);
+			list_for_each_safe (l2, n2, &slot->funcs) {
+				func = list_entry(l2, struct acpiphp_func, sibling);
 				acpiphp_free_resource(&func->io_head);
 				acpiphp_free_resource(&func->mem_head);
 				acpiphp_free_resource(&func->p_mem_head);
@@ -1261,7 +1242,7 @@
 								    ACPI_SYSTEM_NOTIFY,
 								    handle_hotplug_event_func);
 				if (ACPI_FAILURE(status))
-					err("failed to remove notify handler");
+					err("failed to remove notify handler\n");
 				kfree(func);
 			}
 			kfree(slot);
@@ -1270,7 +1251,7 @@
 		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
 						    handle_hotplug_event_bridge);
 		if (ACPI_FAILURE(status))
-			err("failed to remove notify handler");
+			err("failed to remove notify handler\n");
 
 		acpiphp_free_resource(&bridge->io_head);
 		acpiphp_free_resource(&bridge->mem_head);
@@ -1293,13 +1274,13 @@
 
 	num_slots = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
-		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
 		num_slots += bridge->nr_slots;
 	}
 
-	dbg("Total %dslots", num_slots);
+	dbg("Total %dslots\n", num_slots);
 	return num_slots;
 }
 
@@ -1317,7 +1298,7 @@
 	struct acpiphp_slot *slot;
 	int retval = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next) {
 			retval = fn(slot, data);
@@ -1338,7 +1319,7 @@
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next)
 			if (slot->id == id)
@@ -1346,7 +1327,7 @@
 	}
 
 	/* should never happen! */
-	err("%s: no object for id %d",__FUNCTION__, id);
+	err("%s: no object for id %d\n",__FUNCTION__, id);
 	return 0;
 }
 
@@ -1357,7 +1338,6 @@
 int acpiphp_enable_slot (struct acpiphp_slot *slot)
 {
 	int retval;
-	int online = 0;
 
 	down(&slot->crit_sect);
 
@@ -1381,8 +1361,6 @@
  */
 int acpiphp_disable_slot (struct acpiphp_slot *slot)
 {
-	struct list_head *l;
-	struct acpiphp_func *func;
 	int retval = 0;
 
 	down(&slot->crit_sect);
@@ -1397,14 +1375,12 @@
 	if (retval)
 		goto err_exit;
 
-#if 1
 	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	up(&slot->crit_sect);
@@ -1431,7 +1407,7 @@
 			if (sta != ACPI_STA_ALL) {
 				retval = acpiphp_disable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1442,7 +1418,7 @@
 			if (sta == ACPI_STA_ALL) {
 				retval = acpiphp_enable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1451,7 +1427,7 @@
 		}
 	}
 
-	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+	dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
 
  err_exit:
 	return retval;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_pci.c linux-2.4.21-rc3/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.20/drivers/hotplug/acpiphp_pci.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/acpiphp_pci.c	2003-05-22 22:06:42.000000000 +0000
@@ -37,16 +37,14 @@
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_pci"
 
 static void acpiphp_configure_irq (struct pci_dev *dev);
 
 
 /* allocate mem/pmem/io resource to a new function */
-static int alloc_resource (struct acpiphp_func *func)
+static int init_config_space (struct acpiphp_func *func)
 {
-	u64 base;
 	u32 bar, len;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -60,23 +58,22 @@
 	int count;
 	struct acpiphp_bridge *bridge;
 	struct pci_resource *res;
-	struct pci_ops *ops;
-	int bus, device, function;
+	struct pci_bus *bus;
+	int devfn;
 
 	bridge = func->slot->bridge;
-	bus = bridge->bus;
-	device = func->slot->device;
-	function = func->function;
-	ops = bridge->pci_ops;
+	bus = bridge->pci_bus;
+	devfn = PCI_DEVFN(func->slot->device, func->function);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_write_config_dword_nodev (ops, bus, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+		pci_bus_write_config_dword(bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword(bus, devfn, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+		dbg("Device %02x.%d BAR %d wants %x\n", PCI_SLOT(devfn),
+				PCI_FUNC(devfn), count, bar);
 
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -84,7 +81,7 @@
 			len = bar & 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg ("len in IO %x, BAR %d", len, count);
+			dbg("len in IO %x, BAR %d\n", len, count);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_io_resource(&bridge->io_head, len);
@@ -92,10 +89,10 @@
 
 			if (!res) {
 				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
-				    bus, device, function, len);
+				    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 				return -1;
 			}
-			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 			res->next = func->io_head;
 			func->io_head = res;
 
@@ -107,7 +104,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in PFMEM %x, BAR %d", len, count);
+				dbg("len in PFMEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->p_mem_head, len);
@@ -115,16 +112,16 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("inside the pfmem 64 case, count %d", count);
+					dbg("inside the pfmem 64 case, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->p_mem_head;
@@ -136,7 +133,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in MEM %x, BAR %d", len, count);
+				dbg("len in MEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->mem_head, len);
@@ -144,17 +141,17 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					dbg("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->mem_head;
@@ -165,7 +162,7 @@
 	}
 
 	/* disable expansion rom */
-	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+	pci_bus_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, 0x00000000);
 
 	return 0;
 }
@@ -203,15 +200,16 @@
 	pci_proc_attach_device(dev);
 #endif
 	pci_announce_device_to_drivers(dev);
+	info("Device %s configured\n", dev->slot_name);
 
 	return 0;
 }
 
 
-static int is_pci_dev_in_use (struct pci_dev* dev) 
+static int is_pci_dev_in_use (struct pci_dev* dev)
 {
-	/* 
-	 * dev->driver will be set if the device is in use by a new-style 
+	/*
+	 * dev->driver will be set if the device is in use by a new-style
 	 * driver -- otherwise, check the device's regions to see if any
 	 * driver has claimed them
 	 */
@@ -253,13 +251,13 @@
 {
 	struct pci_dev *dev = wrapped_dev->dev;
 
-	dbg("attempting removal of driver for device %s", dev->slot_name);
+	dbg("attempting removal of driver for device %s\n", dev->slot_name);
 
 	/* Now, remove the Linux Driver Representation */
 	if (dev->driver) {
 		if (dev->driver->remove) {
 			dev->driver->remove(dev);
-			dbg("driver was properly removed");
+			dbg("driver was properly removed\n");
 		}
 		dev->driver = NULL;
 	}
@@ -276,6 +274,7 @@
 	/* Now, remove the Linux Representation */
 	if (dev) {
 		if (pci_hp_remove_device(dev) == 0) {
+			info("Device %s removed\n", dev->slot_name);
 			kfree(dev); /* Now, remove */
 		} else {
 			return -1; /* problems while freeing, abort visitation */
@@ -313,7 +312,7 @@
 /* detect_used_resource - subtract resource under dev from bridge */
 static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
 {
-	u32 bar, len, pin;
+	u32 bar, len;
 	u64 base;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -327,7 +326,7 @@
 	int count;
 	struct pci_resource *res;
 
-	dbg("Device %s", dev->slot_name);
+	dbg("Device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
 		pci_read_config_dword(dev, address[count], &bar);
@@ -344,7 +343,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
@@ -361,10 +360,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -378,10 +377,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -403,7 +402,7 @@
 	struct list_head *l;
 	struct pci_dev *dev;
 
-	list_for_each(l, &bus->devices) {
+	list_for_each (l, &bus->devices) {
 		dev = pci_dev_b(l);
 		detect_used_resource(bridge, dev);
 		/* XXX recursive call */
@@ -421,9 +420,6 @@
  */
 int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
 {
-	struct list_head *l;
-	struct pci_dev *dev;
-
 	detect_used_resource_bus(bridge, bridge->pci_bus);
 
 	return 0;
@@ -452,20 +448,19 @@
 	};
 	int count;
 	struct pci_resource *res;
-	struct pci_ops *ops;
 	struct pci_dev *dev;
 
 	dev = func->pci_dev;
-	dbg("Hot-pluggable device %s", dev->slot_name);
+	dbg("Hot-pluggable device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_read_config_dword (dev, address[count], &bar);
+		pci_read_config_dword(dev, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
-		pci_read_config_dword (dev, address[count], &len);
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
 
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -473,7 +468,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			res = acpiphp_make_resource(base, len);
 			if (!res)
@@ -492,10 +487,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -511,10 +506,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -525,7 +520,7 @@
 			}
 		}
 
-		pci_write_config_dword (dev, address[count], bar);
+		pci_write_config_dword(dev, address[count], bar);
 	}
 #if 1
 	acpiphp_dump_func_resource(func);
@@ -534,7 +529,7 @@
 	return 0;
 
  no_memory:
-	err("out of memory");
+	err("out of memory\n");
 	acpiphp_free_resource(&func->io_head);
 	acpiphp_free_resource(&func->mem_head);
 	acpiphp_free_resource(&func->p_mem_head);
@@ -560,23 +555,22 @@
 	int retval = 0;
 	int is_multi = 0;
 
-	pci_read_config_byte_nodev(slot->bridge->pci_ops,
-				   slot->bridge->bus, slot->device, 0,
-				   PCI_HEADER_TYPE, &hdr);
+	pci_bus_read_config_byte(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, 0),
+					PCI_HEADER_TYPE, &hdr);
 
 	if (hdr & 0x80)
 		is_multi = 1;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 		if (is_multi || func->function == 0) {
-			pci_read_config_dword_nodev(slot->bridge->pci_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						    PCI_DEVFN(slot->device,
+								func->function),
 						    PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
-				retval = alloc_resource(func);
+				retval = init_config_space(func);
 				if (retval)
 					break;
 			}
@@ -589,16 +583,16 @@
 
 /* for pci_visit_dev() */
 static struct pci_visit configure_functions = {
-	post_visit_pci_dev:	configure_pci_dev
+	.post_visit_pci_dev =	configure_pci_dev
 };
 
 static struct pci_visit unconfigure_functions_phase1 = {
-	post_visit_pci_dev:	unconfigure_pci_dev_driver
+	.post_visit_pci_dev =	unconfigure_pci_dev_driver
 };
 
 static struct pci_visit unconfigure_functions_phase2 = {
-	post_visit_pci_bus:	unconfigure_pci_bus,
-	post_visit_pci_dev:	unconfigure_pci_dev
+	.post_visit_pci_bus =	unconfigure_pci_bus,
+	.post_visit_pci_dev =	unconfigure_pci_dev
 };
 
 
@@ -647,7 +641,6 @@
 int acpiphp_unconfigure_function (struct acpiphp_func *func)
 {
 	struct acpiphp_bridge *bridge;
-	struct pci_resource *tmp;
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
 	int retval = 0;
@@ -686,45 +679,6 @@
 }
 
 
-/* XXX IA64 specific */
-#ifdef CONFIG_IA64
-static int ia64_get_irq(struct pci_dev *dev, int pin)
-{
-	extern int pci_pin_to_vector(int bus, int slot, int pci_pin);
-	int irq;
-
-	irq = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-
-	if (irq < 0 && dev->bus->parent) {
-		/* go back to the bridge */
-		struct pci_dev *bridge = dev->bus->self;
-
-		if (bridge) {
-			/* allow for multiple bridges on an adapter */
-			do {
-				/* do the bridge swizzle... */
-				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-				irq = pci_pin_to_vector(bridge->bus->number,
-							PCI_SLOT(bridge->devfn),
-							   pin);
-			} while (irq < 0 && (bridge = bridge->bus->self));
-		}
-		if (irq >= 0)
-			printk(KERN_WARNING
-			       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn),
-			       pin, irq);
-		else
-			printk(KERN_WARNING
-			       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn), pin);
-	}
-
-	return irq;
-}
-#endif
-
-
 /*
  * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
  *
@@ -740,24 +694,10 @@
  */
 static void acpiphp_configure_irq (struct pci_dev *dev)
 {
-#if CONFIG_IA64		    /* XXX IA64 specific, need i386 version */
-	int bus, device, function, irq;
-	u8 tmp;
-
-	bus = dev->bus->number;
-	device = PCI_SLOT(dev->devfn);
-	function = PCI_FUNC(dev->devfn);
-
-	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &tmp);
-
-	if ((tmp > 0x00) && (tmp < 0x05)) {
-		irq = ia64_get_irq(dev, tmp - 1);
-		if (irq > 0) {
-			dev->irq = irq;
-			pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
-		} else {
-			err("Couldn't get IRQ for INT%c", 'A' + tmp - 1);
-		}
-	}
+#if CONFIG_IA64		    /* XXX IA64 specific */
+	extern void iosapic_fixup_pci_interrupt (struct pci_dev *dev);
+
+	iosapic_fixup_pci_interrupt(dev);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_res.c linux-2.4.21-rc3/drivers/hotplug/acpiphp_res.c
--- linux-2.4.20/drivers/hotplug/acpiphp_res.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/acpiphp_res.c	2003-05-22 22:06:43.000000000 +0000
@@ -59,8 +59,6 @@
 
 #define MY_NAME "acpiphp_res"
 
-/* local variables */
-static int debug = 0;
 
 /*
  * sort_by_size - sort nodes by their length, smallest first
@@ -275,7 +273,7 @@
 
 	for (max = *head;max; max = max->next) {
 
-		/* If not big enough we could probably just bail, 
+		/* If not big enough we could probably just bail,
 		   instead we'll continue to the next. */
 		if (max->length < size)
 			continue;
@@ -372,13 +370,13 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
 		    __FUNCTION__, size, node, (u32)node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg("%s: not aligned", __FUNCTION__);
+			dbg("%s: not aligned\n", __FUNCTION__);
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = (node->base | (size-1)) + 1;
@@ -402,7 +400,7 @@
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg("%s: too big", __FUNCTION__);
+			dbg("%s: too big\n", __FUNCTION__);
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -417,7 +415,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg("%s: got one!!!", __FUNCTION__);
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -439,7 +437,7 @@
 /**
  * get_resource_with_base - get resource with specific base address
  *
- * this function 
+ * this function
  * returns the first node of "size" length located at specified base address.
  * If it finds a node larger than "size" it will split it up.
  *
@@ -460,7 +458,7 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 		if (node->base > base)
 			continue;
@@ -469,7 +467,7 @@
 			continue;
 
 		if (node->base < base) {
-			dbg(": split 1");
+			dbg(": split 1\n");
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = base;
@@ -491,12 +489,12 @@
 			node->next = split_node;
 		}
 
-		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg(": split 2");
+			dbg(": split 2\n");
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -511,7 +509,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg(": got one!!!");
+		dbg(": got one!!!\n");
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -549,13 +547,13 @@
 	if (!(*head))
 		return 1;
 
-	dbg("*head->next = %p",(*head)->next);
+	dbg("*head->next = %p\n",(*head)->next);
 
 	if (!(*head)->next)
 		return 0;	/* only one item on the list, already sorted! */
 
-	dbg("*head->base = 0x%x",(u32)(*head)->base);
-	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	dbg("*head->base = 0x%x\n",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
 	while (out_of_order) {
 		out_of_order = 0;
 
@@ -589,7 +587,7 @@
 	while (node1 && node1->next) {
 		if ((node1->base + node1->length) == node1->next->base) {
 			/* Combine */
-			dbg("8..");
+			dbg("8..\n");
 			node1->length += node1->next->length;
 			node2 = node1->next;
 			node1->next = node1->next->next;
@@ -670,39 +668,32 @@
 	cnt = 0;
 
 	while (p) {
-		info("[%02d] %08x - %08x",
-		     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		dbg("[%02d] %08x - %08x\n",
+		    cnt++, (u32)p->base, (u32)p->base + p->length - 1);
 		p = p->next;
 	}
 }
 
 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(bridge->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(bridge->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(bridge->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(bridge->bus_head);
 }
 
 void acpiphp_dump_func_resource(struct acpiphp_func *func)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(func->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(func->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(func->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(func->bus_head);
 }
-
-/*
-EXPORT_SYMBOL(acpiphp_get_io_resource);
-EXPORT_SYMBOL(acpiphp_get_max_resource);
-EXPORT_SYMBOL(acpiphp_get_resource);
-EXPORT_SYMBOL(acpiphp_resource_sort_and_combine);
-*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/cpqphp.h linux-2.4.21-rc3/drivers/hotplug/cpqphp.h
--- linux-2.4.20/drivers/hotplug/cpqphp.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/cpqphp.h	2003-05-22 22:06:39.000000000 +0000
@@ -30,7 +30,7 @@
 
 #include "pci_hotplug.h"
 #include <asm/io.h>		/* for read? and write? functions */
-
+#include <linux/delay.h>	/* for delays */
 
 #if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE)
 	#define MY_NAME	"cpqphp.o"
@@ -145,6 +145,10 @@
 	u8	reserved11;		/* 0x2b */
 	u8	slot_SERR;		/* 0x2c */
 	u8	slot_power;		/* 0x2d */
+	u8	reserved12;		/* 0x2e */
+	u8	reserved13;		/* 0x2f */
+	u8	next_curr_freq;		/* 0x30 */
+	u8	reset_freq_mode;	/* 0x31 */
 } __attribute__ ((packed));
 
 /* offsets to the controller registers based on the above structure layout */
@@ -172,6 +176,8 @@
 	CTRL_RESERVED11 =	offsetof(struct ctrl_reg, reserved11),
 	SLOT_SERR =		offsetof(struct ctrl_reg, slot_SERR),
 	SLOT_POWER =		offsetof(struct ctrl_reg, slot_power),
+	NEXT_CURR_FREQ =	offsetof(struct ctrl_reg, next_curr_freq),
+	RESET_FREQ_MODE =	offsetof(struct ctrl_reg, reset_freq_mode),
 };
 
 struct hrt {
@@ -345,6 +351,7 @@
 #define PCI_SUB_HPC_ID2			0xA2F8
 #define PCI_SUB_HPC_ID3			0xA2F9
 #define PCI_SUB_HPC_ID_INTC		0xA2FA
+#define PCI_SUB_HPC_ID4			0xA2FD
 
 #define INT_BUTTON_IGNORE		0
 #define INT_PRESENCE_ON			1
@@ -460,6 +467,7 @@
 extern void	cpqhp_destroy_resource_list	(struct resource_lists * resources);
 extern int	cpqhp_configure_device		(struct controller* ctrl, struct pci_func* func);
 extern int	cpqhp_unconfigure_device	(struct pci_func* func);
+extern struct slot *cpqhp_find_slot 		(struct controller *ctrl, u8 device);
 
 
 /* Global variables */
@@ -473,8 +481,6 @@
 
 
 
-/* inline functions */
-
 
 /* Inline functions to check the sanity of a pointer that is passed to us */
 static inline int slot_paranoia_check (struct slot *slot, const char *function)
@@ -588,6 +594,7 @@
 	u32 led_control;
 	
 	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x0101L << slot);
 	led_control |= (0x0001L << slot);
 	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
 }
@@ -629,14 +636,62 @@
 }
 
 
+/*
+ * get_controller_speed - find the current frequency/mode of controller.
+ *
+ * @ctrl: controller to get frequency/mode for.
+ *
+ * Returns controller speed.
+ *
+ */
 static inline u8 get_controller_speed (struct controller *ctrl)
 {
+	u8 curr_freq;
 	u16 misc;
 	
+	if (ctrl->pcix_support) {
+		curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
+		if ((curr_freq & 0xB0) == 0xB0) 
+			return PCI_SPEED_133MHz_PCIX;
+		if ((curr_freq & 0xA0) == 0xA0)
+			return PCI_SPEED_100MHz_PCIX;
+		if ((curr_freq & 0x90) == 0x90)
+			return PCI_SPEED_66MHz_PCIX;
+		if (curr_freq & 0x10)
+			return PCI_SPEED_66MHz;
+
+		return PCI_SPEED_33MHz;
+	}
+
 	misc = readw(ctrl->hpc_reg + MISC);
 	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
 }
 
+/*
+ * get_adapter_speed - find the max supported frequency/mode of adapter.
+ *
+ * @ctrl: hotplug controller.
+ * @hp_slot: hotplug slot where adapter is installed.
+ *
+ * Returns adapter speed.
+ *
+ */
+static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot)
+{
+	u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT);
+	dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword);
+	if (ctrl->pcix_support) {
+		if (temp_dword & (0x10000 << hp_slot))
+			return PCI_SPEED_133MHz_PCIX;
+		if (temp_dword & (0x100 << hp_slot))
+			return PCI_SPEED_66MHz_PCIX;
+	}
+
+	if (temp_dword & (0x01 << hp_slot))
+		return PCI_SPEED_66MHz;
+
+	return PCI_SPEED_33MHz;
+}
 
 static inline void enable_slot_power (struct controller *ctrl, u8 slot)
 {
@@ -744,5 +799,136 @@
 	return retval;
 }
 
-#endif
+/**
+ * set_controller_speed - set the frequency and/or mode of a specific
+ * controller segment.
+ *
+ * @ctrl: controller to change frequency/mode for.
+ * @adapter_speed: the speed of the adapter we want to match.
+ * @hp_slot: the slot number where the adapter is installed.
+ *
+ * Returns 0 if we successfully change frequency and/or mode to match the
+ * adapter speed.
+ * 
+ */
+static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
+{
+	struct slot *slot;
+	u8 reg;
+	u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	u16 reg16;
+	u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
+	
+	if (ctrl->speed == adapter_speed)
+		return 0;
+	
+	/* We don't allow freq/mode changes if we find another adapter running
+	 * in another slot on this controller */
+	for(slot = ctrl->slot; slot; slot = slot->next) {
+		if (slot->device == (hp_slot + ctrl->slot_device_offset)) 
+			continue;
+		if (!slot->hotplug_slot && !slot->hotplug_slot->info) 
+			continue;
+		if (slot->hotplug_slot->info->adapter_status == 0) 
+			continue;
+		/* If another adapter is running on the same segment but at a
+		 * lower speed/mode, we allow the new adapter to function at
+		 * this rate if supported */
+		if (ctrl->speed < adapter_speed) 
+			return 0;
+
+		return 1;
+	}
+	
+	/* If the controller doesn't support freq/mode changes and the
+	 * controller is running at a higher mode, we bail */
+	if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 1;
+	
+	/* But we allow the adapter to run at a lower rate if possible */
+	if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 0;
+
+	/* We try to set the max speed supported by both the adapter and
+	 * controller */
+	if (ctrl->speed_capability < adapter_speed) {
+		if (ctrl->speed == ctrl->speed_capability)
+			return 0;
+		adapter_speed = ctrl->speed_capability;
+	}
+
+	writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
+	writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl); 
+	wait_for_ctrl_irq(ctrl);
+	
+	if (adapter_speed != PCI_SPEED_133MHz_PCIX)
+		reg = 0xF5;
+	else
+		reg = 0xF4;	
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+	
+	reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ);
+	reg16 &= ~0x000F;
+	switch(adapter_speed) {
+		case(PCI_SPEED_133MHz_PCIX): 
+			reg = 0x75;
+			reg16 |= 0xB; 
+			break;
+		case(PCI_SPEED_100MHz_PCIX):
+			reg = 0x74;
+			reg16 |= 0xA;
+			break;
+		case(PCI_SPEED_66MHz_PCIX):
+			reg = 0x73;
+			reg16 |= 0x9;
+			break;
+		case(PCI_SPEED_66MHz):
+			reg = 0x73;
+			reg16 |= 0x1;
+			break;
+		default: /* 33MHz PCI 2.2 */
+			reg = 0x71;
+			break;
+			
+	}
+	reg16 |= 0xB << 12;
+	writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ);
+	
+	mdelay(5); 
+	
+	/* Reenable interrupts */
+	writel(0, ctrl->hpc_reg + INT_MASK);
+
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg); 
+	
+	/* Restart state machine */
+	reg = ~0xF;
+	pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
+	pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
+	
+	/* Only if mode change...*/
+	if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+		((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) 
+			set_SOGO(ctrl);
+	
+	wait_for_ctrl_irq(ctrl);
+	mdelay(1100);
+	
+	/* Restore LED/Slot state */
+	writel(leds, ctrl->hpc_reg + LED_CONTROL);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl);
+	wait_for_ctrl_irq(ctrl);
+	
+	ctrl->speed = adapter_speed;
+	slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
+	info("Successfully changed frequency/mode for adapter in slot %d\n", 
+			slot->number);
+	return 0;
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/cpqphp_core.c linux-2.4.21-rc3/drivers/hotplug/cpqphp_core.c
--- linux-2.4.20/drivers/hotplug/cpqphp_core.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/cpqphp_core.c	2003-05-22 22:06:24.000000000 +0000
@@ -24,6 +24,9 @@
  *
  * Send feedback to <greg@kroah.com>
  *
+ * Jan 12, 2003 -	Added 66/100/133MHz PCI-X support, 
+ * 			Torben Mathiasen <torben.mathiasen@hp.com>
+ *
  */
 
 #include <linux/config.h>
@@ -53,7 +56,7 @@
 static u8 power_mode;
 static int debug;
 
-#define DRIVER_VERSION	"0.9.6"
+#define DRIVER_VERSION	"0.9.7"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC	"Compaq Hot Plug PCI Controller Driver"
 
@@ -829,6 +832,7 @@
 	u8 hp_slot = 0;
 	u8 device;
 	u8 rev;
+	u8 bus_cap;
 	u16 temp_word;
 	u16 vendor_id;
 	u16 subsystem_vid;
@@ -890,6 +894,39 @@
 
 		switch (subsystem_vid) {
 			case PCI_VENDOR_ID_COMPAQ:
+				if (rev >= 0x13) { /* CIOBX */
+					ctrl->push_flag = 1;
+					ctrl->slot_switch_type = 1;		// Switch is present
+					ctrl->push_button = 1;			// Pushbutton is present
+					ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+					ctrl->defeature_PHP = 1;		// PHP is supported
+					ctrl->pcix_support = 1;			// PCI-X supported
+					ctrl->pcix_speed_capability = 1;
+					pci_read_config_byte(pdev, 0x41, &bus_cap);
+					if (bus_cap & 0x80) {
+						dbg("bus max supports 133MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_133MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 0x40) {
+						dbg("bus max supports 100MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 20) {
+						dbg("bus max supports 66MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 10) {
+						dbg("bus max supports 66MHz PCI\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz;
+						break;
+					}
+
+					break;
+				}
+
 				switch (subsystem_deviceid) {
 					case PCI_SUB_HPC_ID:
 						/* Original 6500/7000 implementation */
@@ -933,8 +970,18 @@
 						ctrl->pcix_support = 0;			// PCI-X not supported
 						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
+					case PCI_SUB_HPC_ID4:
+						/* First PCI-X implementation, 100MHz */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;		// Switch is present
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						ctrl->push_button = 1;			// Pushbutton is present
+						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
+						ctrl->pcix_support = 1;			// PCI-X supported
+						ctrl->pcix_speed_capability = 0;	
+						break;
 					default:
-						// TODO: Add SSIDs for CPQ systems that support PCI-X
 						err(msg_HPC_not_supported);
 						rc = -ENODEV;
 						goto err_free_ctrl;
@@ -1023,7 +1070,7 @@
 	info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number);
 
 	dbg ("Hotplug controller capabilities:\n");
-	dbg ("    speed_capability       %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz");
+	dbg ("    speed_capability       %d\n", ctrl->speed_capability);
 	dbg ("    slot_switch_type       %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present");
 	dbg ("    defeature_PHP          %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported");
 	dbg ("    alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported");
@@ -1066,11 +1113,9 @@
 		goto err_free_mem_region;
 	}
 
-	// Check for 66Mhz operation
-	// TODO: Add PCI-X support
+	// Check for 66Mhz and/or PCI-X operation
 	ctrl->speed = get_controller_speed(ctrl);
-
-
+	
 	//**************************************************
 	//
 	//              Save configuration headers for this and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/cpqphp_ctrl.c linux-2.4.21-rc3/drivers/hotplug/cpqphp_ctrl.c
--- linux-2.4.20/drivers/hotplug/cpqphp_ctrl.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/cpqphp_ctrl.c	2003-05-22 22:06:40.000000000 +0000
@@ -135,9 +135,9 @@
 
 
 /*
- * find_slot
+ * cpqhp_find_slot
  */
-static inline struct slot *find_slot (struct controller * ctrl, u8 device)
+struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device)
 {
 	struct slot *slot;
 
@@ -186,7 +186,7 @@
 
 			rc++;
 
-			p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
+			p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
 
 			// If the switch closed, must be a button
 			// If not in button mode, nevermind
@@ -916,6 +916,7 @@
 void cpqhp_ctrl_intr(int IRQ, struct controller * ctrl, struct pt_regs *regs)
 {
 	u8 schedule_flag = 0;
+	u8 reset;
 	u16 misc;
 	u32 Diff;
 	u32 temp_dword;
@@ -966,6 +967,15 @@
 		schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl);
 		schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl);
 	}
+	
+	reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+	if (reset & 0x40) {
+		/* Bus Reset has completed */
+		reset &= 0xCF;
+		writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE);
+		reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+		wake_up_interruptible(&ctrl->queue);
+	}
 
 	if (schedule_flag) {
 		up(&event_semaphore);
@@ -1169,6 +1179,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	u32 index;
 	u32 rc = 0;
 	u32 src = 8;
@@ -1186,46 +1197,47 @@
 		//*********************************
 		rc = CARD_FUNCTIONING;
 	} else {
-		if (ctrl->speed == PCI_SPEED_66MHz) {
-			// Wait for exclusive access to hardware
-			down(&ctrl->crit_sect);
-
-			// turn on board without attaching to the bus
-			enable_slot_power (ctrl, hp_slot);
+		// Wait for exclusive access to hardware
+		down(&ctrl->crit_sect);
 
-			set_SOGO(ctrl);
+		// turn on board without attaching to the bus
+		enable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Change bits in slot power register to force another shift out
-			// NOTE: this is to work around the timer bug
-			temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-			writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-			writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			set_SOGO(ctrl);
+		// Change bits in slot power register to force another shift out
+		// NOTE: this is to work around the timer bug
+		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
+		
+		// 66MHz and/or PCI-X support check
+		adapter_speed = get_adapter_speed(ctrl, hp_slot);
+		if (ctrl->speed != adapter_speed)
+			if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 				rc = WRONG_BUS_FREQUENCY;
-			}
-			// turn off board without attaching to the bus
-			disable_slot_power (ctrl, hp_slot);
 
-			set_SOGO(ctrl);
+		// turn off board without attaching to the bus
+		disable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Done with exclusive hardware access
-			up(&ctrl->crit_sect);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			if (rc)
-				return(rc);
-		}
+		// Done with exclusive hardware access
+		up(&ctrl->crit_sect);
+
+		if (rc)
+			return(rc);
 
 		// Wait for exclusive access to hardware
 		down(&ctrl->crit_sect);
@@ -1373,6 +1385,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	int index;
 	u32 temp_register = 0xFFFFFFFF;
 	u32 rc = 0;
@@ -1383,48 +1396,50 @@
 	hp_slot = func->device - ctrl->slot_device_offset;
 	dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    func->device, ctrl->slot_device_offset, hp_slot);
+	
+	// Wait for exclusive access to hardware
+	down(&ctrl->crit_sect);
 
-	if (ctrl->speed == PCI_SPEED_66MHz) {
-		// Wait for exclusive access to hardware
-		down(&ctrl->crit_sect);
-
-		// turn on board without attaching to the bus
-		enable_slot_power (ctrl, hp_slot);
-
-		set_SOGO(ctrl);
+	// turn on board without attaching to the bus
+	enable_slot_power (ctrl, hp_slot);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		// Change bits in slot power register to force another shift out
-		// NOTE: this is to work around the timer bug
-		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		set_SOGO(ctrl);
+	// Change bits in slot power register to force another shift out
+	// NOTE: this is to work around the timer bug
+	temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+	writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+	writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
+	
+	// 66MHz and/or PCI-X support check
+	adapter_speed = get_adapter_speed(ctrl, hp_slot);
+	if (ctrl->speed != adapter_speed)
+		if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 			rc = WRONG_BUS_FREQUENCY;
-		}
-		// turn off board without attaching to the bus
-		disable_slot_power (ctrl, hp_slot);
+	
+	// turn off board without attaching to the bus
+	disable_slot_power (ctrl, hp_slot);
 
-		set_SOGO(ctrl);
+	set_SOGO(ctrl);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		// Done with exclusive hardware access
-		up(&ctrl->crit_sect);
+	// Done with exclusive hardware access
+	up(&ctrl->crit_sect);
 
-		if (rc)
-			return(rc);
-	}
-	p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	if (rc)
+		return(rc);
+	
+	p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	// turn on board and blink green LED
 
@@ -1800,7 +1815,7 @@
 
 				func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0);
 
-				p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+				p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 				dbg("hp_slot %d, func %p, p_slot %p\n",
 				    hp_slot, func, p_slot);
@@ -1990,7 +2005,7 @@
 
 	device = func->device;
 	hp_slot = device - ctrl->slot_device_offset;
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
@@ -2087,7 +2102,7 @@
 
 	device = func->device; 
 	func = cpqhp_slot_find(ctrl->bus, device, index++);
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/ibmphp_ebda.c linux-2.4.21-rc3/drivers/hotplug/ibmphp_ebda.c
--- linux-2.4.20/drivers/hotplug/ibmphp_ebda.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/ibmphp_ebda.c	2003-05-22 22:06:40.000000000 +0000
@@ -65,24 +65,11 @@
 static LIST_HEAD (opt_lo_head);
 static void *io_mem;
 
-char *chassis_str, *rxe_str, *str;
-
 /* Local functions */
 static int ebda_rsrc_controller (void);
 static int ebda_rsrc_rsrc (void);
 static int ebda_rio_table (void);
 
-static struct slot *alloc_ibm_slot (void)
-{
-	struct slot *slot;
-
-	slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
-	if (!slot)
-		return NULL;
-	memset (slot, 0, sizeof (*slot));
-	return slot;
-}
-
 static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
 {
 	struct ebda_hpc_list *list;
@@ -591,32 +578,6 @@
 	return 0;	
 }
 	
-static char *convert_2digits_to_char (int var)
-{
-	int bit;	
-	char *str1;
-
-	str = (char *) kmalloc (3, GFP_KERNEL);
-	memset (str, 0, 3);
-	str1 = (char *) kmalloc (2, GFP_KERNEL);
-	memset (str, 0, 3);
-	bit = (int)(var / 10);
-	switch (bit) {
-	case 0:
-		//one digit number
-		*str = (char)(var + 48);
-		return str;
-	default: 	
-		//2 digits number
-		*str1 = (char)(bit + 48);
-		strncpy (str, str1, 1);
-		memset (str1, 0, 3);
-		*str1 = (char)((var % 10) + 48);
-		strcat (str, str1);
-		return str;
-	}	
-	return NULL;	
-}
 
 /* Since we don't know the max slot number per each chassis, hence go
  * through the list of all chassis to find out the range
@@ -701,7 +662,7 @@
 {
 	struct opt_rio *opt_vg_ptr = NULL;
 	struct opt_rio_lo *opt_lo_ptr = NULL;
-	char *ptr_chassis_num, *ptr_rxe_num, *ptr_slot_num;
+	static char str[30];
 	int which = 0; /* rxe = 1, chassis = 0 */
 	u8 number = 1; /* either chassis or rxe # */
 	u8 first_slot = 1;
@@ -715,19 +676,7 @@
 	
 	slot_num = slot_cur->number;
 
-	chassis_str = (char *) kmalloc (30, GFP_KERNEL);
-	memset (chassis_str, 0, 30);
-	rxe_str = (char *) kmalloc (30, GFP_KERNEL);
-	memset (rxe_str, 0, 30);
-	ptr_chassis_num = (char *) kmalloc (3, GFP_KERNEL);
-	memset (ptr_chassis_num, 0, 3);
-	ptr_rxe_num = (char *) kmalloc (3, GFP_KERNEL);
-	memset (ptr_rxe_num, 0, 3);
-	ptr_slot_num = (char *) kmalloc (3, GFP_KERNEL);
-	memset (ptr_slot_num, 0, 3);
-	
-	strcpy (chassis_str, "chassis");
-	strcpy (rxe_str, "rxe");
+	memset (str, 0, sizeof(str));
 	
 	if (rio_table_ptr) {
 		if (rio_table_ptr->ver_num == 3) {
@@ -772,31 +721,10 @@
 		}
 	}
 
-	switch (which) {
-	case 0:
-		/* Chassis */
-		*ptr_chassis_num = (char)(number + 48);
-		strcat (chassis_str, ptr_chassis_num);
-		kfree (ptr_chassis_num);
-		strcat (chassis_str, "slot");
-		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
-		strcat (chassis_str, ptr_slot_num);
-		kfree (ptr_slot_num);
-		return chassis_str;
-		break;
-	case 1:
-		/* RXE */
-		*ptr_rxe_num = (char)(number + 48);
-		strcat (rxe_str, ptr_rxe_num);
-		kfree (ptr_rxe_num);
-		strcat (rxe_str, "slot");
-		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
-		strcat (rxe_str, ptr_slot_num);
-		kfree (ptr_slot_num);
-		return rxe_str;
-		break;
-	}	
-	return NULL;
+	sprintf(str, "%s%dslot%d",
+		which == 0 ? "chassis" : "rxe",
+		number, slot_num - first_slot + 1);
+	return str;
 }
 
 static struct pci_driver ibmphp_driver;
@@ -818,8 +746,7 @@
 	struct ebda_hpc_slot *slot_ptr;
 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
 	int rc;
-	int retval;
-	struct slot *slot_cur;
+	struct slot *tmp_slot;
 	struct list_head *list;
 
 	addr = hpc_list_ptr->phys_addr;
@@ -844,8 +771,8 @@
 		/* init hpc structure */
 		hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
 		if (!hpc_ptr ) {
-			iounmap (io_mem);
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto error_no_hpc;
 		}
 		hpc_ptr->ctlr_id = ctlr_id;
 		hpc_ptr->ctlr_relative_id = ctlr;
@@ -871,8 +798,8 @@
 			if (!bus_info_ptr2) {
 				bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL);
 				if (!bus_info_ptr1) {
-					iounmap (io_mem);
-					return -ENOMEM;
+					rc = -ENOMEM;
+					goto error_no_hp_slot;
 				}
 				memset (bus_info_ptr1, 0, sizeof (struct bus_info));
 				bus_info_ptr1->slot_min = slot_ptr->slot_num;
@@ -932,16 +859,20 @@
 				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
 				hpc_ptr->irq = readb (io_mem + addr + 2);
 				addr += 3;
-				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", hpc_ptr->u.pci_ctlr.bus, hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
+				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", 
+					hpc_ptr->u.pci_ctlr.bus,
+					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
 				break;
 
 			case 0:
 				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
 				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
-				retval = check_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1));
-				if (retval)
-					return -ENODEV;
-				request_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), "ibmphp");
+				if (!request_region (hpc_ptr->u.isa_ctlr.io_start,
+						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
+						     "ibmphp")) {
+					rc = -ENODEV;
+					goto error_no_hp_slot;
+				}
 				hpc_ptr->irq = readb (io_mem + addr + 4);
 				addr += 5;
 				break;
@@ -954,8 +885,8 @@
 				addr += 6;
 				break;
 			default:
-				iounmap (io_mem);
-				return -ENODEV;
+				rc = -ENODEV;
+				goto error_no_hp_slot;
 		}
 
 		//reorganize chassis' linked list
@@ -971,79 +902,71 @@
 
 			hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
 			if (!hp_slot_ptr) {
-				iounmap (io_mem);
-				return -ENOMEM;
+				rc = -ENOMEM;
+				goto error_no_hp_slot;
 			}
 			memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot));
 
 			hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
 			if (!hp_slot_ptr->info) {
-				iounmap (io_mem);
-				kfree (hp_slot_ptr);
-				return -ENOMEM;
+				rc = -ENOMEM;
+				goto error_no_hp_info;
 			}
 			memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info));
 
 			hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL);
 			if (!hp_slot_ptr->name) {
-				iounmap (io_mem);
-				kfree (hp_slot_ptr->info);
-				kfree (hp_slot_ptr);
-				return -ENOMEM;
+				rc = -ENOMEM;
+				goto error_no_hp_name;
 			}
 
-			hp_slot_ptr->private = alloc_ibm_slot ();
-			if (!hp_slot_ptr->private) {
-				iounmap (io_mem);
-				kfree (hp_slot_ptr->name);
-				kfree (hp_slot_ptr->info);
-				kfree (hp_slot_ptr);
-				return -ENOMEM;
+			tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+			if (!tmp_slot) {
+				rc = -ENOMEM;
+				goto error_no_slot;
 			}
+			memset (tmp_slot, 0, sizeof (*tmp_slot));
 
-			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
+			tmp_slot->flag = TRUE;
 
-			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
+			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
-				((struct slot *) hp_slot_ptr->private)->supported_speed =  3;
+				tmp_slot->supported_speed =  3;
 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
-				((struct slot *) hp_slot_ptr->private)->supported_speed =  2;
+				tmp_slot->supported_speed =  2;
 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
-				((struct slot *) hp_slot_ptr->private)->supported_speed =  1;
+				tmp_slot->supported_speed =  1;
 				
 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
-				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 1;
+				tmp_slot->supported_bus_mode = 1;
 			else
-				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 0;
+				tmp_slot->supported_bus_mode = 0;
 
 
-			((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
+			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
 
 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
 			if (!bus_info_ptr1) {
-				iounmap (io_mem);
-				return -ENODEV;
+				rc = -ENODEV;
+				goto error;
 			}
-			((struct slot *) hp_slot_ptr->private)->bus_on = bus_info_ptr1;
+			tmp_slot->bus_on = bus_info_ptr1;
 			bus_info_ptr1 = NULL;
-			((struct slot *) hp_slot_ptr->private)->ctrl = hpc_ptr;
+			tmp_slot->ctrl = hpc_ptr;
 
+			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
+			tmp_slot->number = hpc_ptr->slots[index].slot_num;
+			tmp_slot->hotplug_slot = hp_slot_ptr;
+
+			hp_slot_ptr->private = tmp_slot;
 
-			((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
-			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
-			
-			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
 			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
-			if (rc) {
-				iounmap (io_mem);
-				return rc;
-			}
+			if (rc)
+				goto error;
 
 			rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
-			if (rc) {
-				iounmap (io_mem);
-				return rc;
-			}
+			if (rc)
+				goto error;
 			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
 
 			// end of registering ibm slot with hotplug core
@@ -1057,19 +980,29 @@
 	}			/* each hpc  */
 
 	list_for_each (list, &ibmphp_slot_head) {
-		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+		tmp_slot = list_entry (list, struct slot, ibm_slot_list);
 
-		snprintf (slot_cur->hotplug_slot->name, 30, "%s", create_file_name (slot_cur));
-		if (chassis_str) 
-			kfree (chassis_str);
-		if (rxe_str)
-			kfree (rxe_str);
-		pci_hp_register (slot_cur->hotplug_slot);
+		snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
+		pci_hp_register (tmp_slot->hotplug_slot);
 	}
 
 	print_ebda_hpc ();
 	print_ibm_slot ();
 	return 0;
+
+error:
+	kfree (hp_slot_ptr->private);
+error_no_slot:
+	kfree (hp_slot_ptr->name);
+error_no_hp_name:
+	kfree (hp_slot_ptr->info);
+error_no_hp_info:
+	kfree (hp_slot_ptr);
+error_no_hp_slot:
+	free_ebda_hpc (hpc_ptr);
+error_no_hpc:
+	iounmap (io_mem);
+	return rc;
 }
 
 /* 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug.h linux-2.4.21-rc3/drivers/hotplug/pci_hotplug.h
--- linux-2.4.20/drivers/hotplug/pci_hotplug.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/pci_hotplug.h	2003-05-22 22:06:41.000000000 +0000
@@ -167,6 +167,18 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+
+/*
+ * Compatibility functions.  Don't use these, use the
+ * pci_bus_*() functions above.
+ */
+
 extern int pci_read_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
 					 u8 function, int where, u8 *val);
 extern int pci_read_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug_util.c linux-2.4.21-rc3/drivers/hotplug/pci_hotplug_util.c
--- linux-2.4.20/drivers/hotplug/pci_hotplug_util.c	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.21-rc3/drivers/hotplug/pci_hotplug_util.c	2003-05-22 22:06:50.000000000 +0000
@@ -50,78 +50,58 @@
 /* local variables */
 static int debug;
 
-
-static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev)
+static int build_dev (struct pci_bus *bus, unsigned int devfn, struct pci_dev **pci_dev)
 {
 	struct pci_dev *my_dev;
-	struct pci_bus *my_bus;
-
-	/* Some validity checks. */
-	if ((function > 7) ||
-	    (slot > 31) ||
-	    (pci_dev == NULL) ||
-	    (ops == NULL))
-		return -ENODEV;
 
 	my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL);
 	if (!my_dev)
 		return -ENOMEM;
-	my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL);
-	if (!my_bus) {
-		kfree (my_dev);
-		return -ENOMEM;
-	}
+
 	memset(my_dev, 0, sizeof(struct pci_dev));
-	memset(my_bus, 0, sizeof(struct pci_bus));
 
-	my_bus->number = bus;
-	my_bus->ops = ops;
-	my_dev->devfn = PCI_DEVFN(slot, function);
-	my_dev->bus = my_bus;
+	my_dev->devfn = devfn;
+	my_dev->bus = bus;
+	my_dev->sysdata = bus->sysdata;
 	*pci_dev = my_dev;
 	return 0;
 }
 
 /**
- * pci_read_config_byte_nodev - read a byte from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
- * @where: the location on the pci address space to read from
+ * pci_bus_read_config_byte - read a byte from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
+ * @where: the location in the pci address space to read from
  * @value: pointer to where to place the data read
  *
  * Like pci_read_config_byte() but works for pci devices that do not have a
  * pci_dev structure set up yet.
  * Returns 0 on success.
  */
-int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value)
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_word_nodev - read a word from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_word - read a word from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -129,34 +109,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value)
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_dword_nodev - read a dword from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci
- * device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_dword - read a dword from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -164,34 +140,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value)
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_byte_nodev - write a byte to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_byte - write a byte to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -199,34 +171,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value)
+int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_word_nodev - write a word to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_word - write a word to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -234,34 +202,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value)
+int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_dword_nodev - write a dword to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_dword - write a dword to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -269,23 +233,22 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value)
+int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
@@ -392,8 +355,98 @@
 	return result;
 }
 
+/* Compatibility wrapper functions */
+
+static struct pci_bus *alloc_bus(struct pci_ops *ops, u8 bus_nr)
+{
+	struct pci_bus *bus = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+	memset(bus, 0, sizeof(struct pci_bus));
+	bus->number = bus_nr;
+	bus->ops = ops;
+	return bus;
+}
+
+int pci_read_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
 
 EXPORT_SYMBOL(pci_visit_dev);
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
 EXPORT_SYMBOL(pci_read_config_byte_nodev);
 EXPORT_SYMBOL(pci_read_config_word_nodev);
 EXPORT_SYMBOL(pci_read_config_dword_nodev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Config.in linux-2.4.21-rc3/drivers/i2c/Config.in
--- linux-2.4.20/drivers/i2c/Config.in	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/Config.in	2003-05-22 22:06:52.000000000 +0000
@@ -13,6 +13,12 @@
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
       dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
       dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+      dep_tristate '  NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT
+      if [ "$CONFIG_SCx200_I2C" != "n" ]; then
+         int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+         int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+      fi
+      dep_tristate '  NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
    fi
 
    dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Makefile linux-2.4.21-rc3/drivers/i2c/Makefile
--- linux-2.4.20/drivers/i2c/Makefile	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/Makefile	2003-05-22 22:06:25.000000000 +0000
@@ -18,6 +18,8 @@
 obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 
 # This is needed for automatic patch generation: sensors code starts here
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/i2c-dev.c linux-2.4.21-rc3/drivers/i2c/i2c-dev.c
--- linux-2.4.20/drivers/i2c/i2c-dev.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/i2c-dev.c	2003-05-22 22:06:51.000000000 +0000
@@ -254,6 +254,11 @@
 				   sizeof(rdwr_arg)))
 			return -EFAULT;
 
+		/* Put an arbritrary limit on the number of messages that can
+		 * be sent at once */
+		if (rdwr_arg.nmsgs > 42)
+			return -EINVAL;
+		
 		rdwr_pa = (struct i2c_msg *)
 			kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 
 			GFP_KERNEL);
@@ -270,6 +275,11 @@
 			        res = -EFAULT;
 				break;
 			}
+			/* Limit the size of the message to a sane amount */
+			if (rdwr_pa[i].len > 8192) {
+				res = -EINVAL;
+				break;
+			}
 			rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
 			if(rdwr_pa[i].buf == NULL)
 			{
@@ -280,11 +290,17 @@
 				rdwr_arg.msgs[i].buf,
 				rdwr_pa[i].len))
 			{
-			    	kfree(rdwr_pa[i].buf);
 			    	res = -EFAULT;
 				break;
 			}
 		}
+		if (res < 0) {
+			int j;
+			for (j = 0; j < i; ++j)
+				kfree(rdwr_pa[j].buf);
+			kfree(rdwr_pa);
+			return res;
+		}
 		if (!res) 
 		{
 			res = i2c_transfer(client->adapter,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/i2c-proc.c linux-2.4.21-rc3/drivers/i2c/i2c-proc.c
--- linux-2.4.20/drivers/i2c/i2c-proc.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/i2c-proc.c	2003-05-22 22:06:47.000000000 +0000
@@ -729,7 +729,7 @@
 			     ||
 			     ((address_data->
 			       ignore_range[i] ==
-			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			       SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr >= address_data->ignore_range[i + 1])
 			    && (addr <= address_data->ignore_range[i + 2])) {
 #ifdef DEBUG
@@ -818,7 +818,7 @@
 		     i += 2) {
 			if (((adapter_id == address_data->probe[i]) ||
 			     ((address_data->
-			       probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa))
+			       probe[i] == SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr == address_data->probe[i + 1])) {
 #ifdef DEBUG
 				printk
@@ -835,7 +835,7 @@
 			    ((adapter_id == address_data->probe_range[i])
 			     ||
 			     ((address_data->probe_range[i] ==
-			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			       SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr >= address_data->probe_range[i + 1])
 			    && (addr <= address_data->probe_range[i + 2])) {
 				found = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_acb.c linux-2.4.21-rc3/drivers/i2c/scx200_acb.c
--- linux-2.4.20/drivers/i2c/scx200_acb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/scx200_acb.c	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,579 @@
+/*  linux/drivers/i2c/scx200_acb.c 
+
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.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 the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+   
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+   
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+   implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct semaphore sem;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20 
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define	   ACBCTL1_ACK		0x10
+#define	   ACBCTL1_STOP		0x02
+#define	   ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	DBG("state %s, status = 0x%02x\n", 
+	    scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK)
+		goto negack;
+
+	switch (iface->state) {
+	case state_idle:
+		printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", 
+		       iface->adapter.name);
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+		
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1) 
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if receiving the last byte */
+		if (iface->len == 1)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+		
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+		
+		break;
+	}
+
+	return;
+
+ negack:
+	DBG("negative acknowledge in state %s\n", 
+	    scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -ENXIO;
+
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+	return;
+
+ error:
+	printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, 
+	       errmsg, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
+{
+	printk(KERN_ERR NAME ": %s, timeout in state %s\n", 
+	       iface->adapter.name, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status = 0;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (time_before(jiffies, timeout)) {
+		status = inb(ACBST);
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		yield();
+	}
+
+	scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				u16 address, unsigned short flags,	
+				char rw, u8 command, int size, 
+				union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = adapter->data;
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+	    	len = 0;
+	    	buffer = NULL;
+	    	break;
+	case I2C_SMBUS_BYTE:
+		if (rw == I2C_SMBUS_READ) {
+			len = 1;
+			buffer = &data->byte;
+		} else {
+			len = 1;
+			buffer = &command;
+		}
+	    	break;
+	case I2C_SMBUS_BYTE_DATA:
+	    	len = 1;
+	    	buffer = &data->byte;
+	    	break;
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+	    	cur_word = cpu_to_le16(data->word);
+	    	buffer = (u8 *)&cur_word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	    	len = data->block[0];
+	    	buffer = &data->block[1];
+		break;
+	default:
+	    	return -EINVAL;
+	}
+
+	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+	    size, address, command, len, rw == I2C_SMBUS_READ);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		printk(KERN_WARNING NAME ": %s, zero length read\n", 
+		       adapter->name);
+		return -EINVAL;
+	}
+
+	if (len && !buffer) {
+		printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name);
+		return -EFAULT;
+	}
+
+	down(&iface->sem);
+
+	iface->address_byte = address<<1;
+	if (rw == I2C_SMBUS_READ)
+		iface->address_byte |= 1;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+#ifdef POLLED_MODE
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */	
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	up(&iface->sem);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+	    	data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+	printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int scx200_acb_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_acb_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_acb_inc_use(struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_acb_dec_use(struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+	name:		"NatSemi SCx200 ACCESS.bus",
+	id:		I2C_ALGO_SMBUS,
+	smbus_xfer:	scx200_acb_smbus_xfer,
+	functionality:	scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		DBG("ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int  __init scx200_acb_create(int base, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+	int rc = 0;
+	char description[64];
+
+	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		rc = -ENOMEM;
+		goto errout;
+	}
+
+	memset(iface, 0, sizeof(*iface));
+	adapter = &iface->adapter;
+	adapter->data = iface;
+	sprintf(adapter->name, "SCx200 ACB%d", index);
+	adapter->id = I2C_ALGO_SMBUS;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->inc_use = scx200_acb_inc_use;
+	adapter->dec_use = scx200_acb_dec_use;
+	adapter->client_register = scx200_acb_reg;
+	adapter->client_unregister = scx200_acb_unreg;
+
+	init_MUTEX(&iface->sem);
+
+	sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+	if (request_region(base, 8, description) == 0) {
+		printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", 
+		       adapter->name, base, base + 8-1);
+		rc = -EBUSY;
+		goto errout;
+	}
+	iface->base = base;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name);
+		goto errout;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name);
+		rc = -ENODEV;
+		goto errout;
+	}
+
+	lock_kernel();
+	iface->next = scx200_acb_list;
+	scx200_acb_list = iface;
+	unlock_kernel();
+
+	return 0;
+
+ errout:
+	if (iface) {
+		if (iface->base)
+			release_region(iface->base, 8);
+		kfree(iface);
+	}
+	return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+	int i;
+	int rc;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* Verify that this really is a SCx200 processor */
+	if (pci_find_device(PCI_VENDOR_ID_NS,
+			    PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			    NULL) == NULL)
+		return -ENODEV;
+
+	rc = -ENXIO;
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] > 0)
+			rc = scx200_acb_create(base[i], i);
+	}
+	if (scx200_acb_list)
+		return 0;
+	return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+	lock_kernel();
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		unlock_kernel();
+
+		i2c_del_adapter(&iface->adapter);
+		release_region(iface->base, 8);
+		kfree(iface);
+		lock_kernel();
+	}
+	unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_i2c.c linux-2.4.21-rc3/drivers/i2c/scx200_i2c.c
--- linux-2.4.20/drivers/i2c/scx200_i2c.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/i2c/scx200_i2c.c	2003-05-22 22:06:46.000000000 +0000
@@ -0,0 +1,156 @@
+/* linux/drivers/i2c/scx200_i2c.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   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.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+static int scx200_i2c_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_i2c_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_i2c_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_i2c_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	NULL,
+	scx200_i2c_setsda,
+	scx200_i2c_setscl,
+	scx200_i2c_getsda,
+	scx200_i2c_getscl,
+	10, 10, 100,		/* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.name              = "NatSemi SCx200 I2C",
+	.id		   = I2C_HW_B_VELLE,
+	.algo_data	   = &scx200_i2c_data,
+	.inc_use	   = scx200_i2c_inc_use,
+	.dec_use	   = scx200_i2c_dec_use,
+	.client_register   = scx200_i2c_reg,
+	.client_unregister = scx200_i2c_unreg,
+};
+
+int scx200_i2c_init(void)
+{
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", 
+	       scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+	i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Config.in linux-2.4.21-rc3/drivers/ide/Config.in
--- linux-2.4.20/drivers/ide/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/Config.in	2003-05-22 22:06:52.000000000 +0000
@@ -16,17 +16,6 @@
    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
-   dep_mbool '    IBM Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
-
-   define_bool CONFIG_BLK_DEV_COMMERIAL n
-   dep_mbool '    TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL
-
    dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
@@ -42,9 +31,9 @@
       dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
       dep_bool '  ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
       if [ "$CONFIG_PCI" = "y" ]; then
-	 dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+	 bool '  PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    dep_bool '    Generic PCI IDE Chipset Support' CONFIG_BLK_DEV_GENERIC $CONFIG_BLK_DEV_IDEPCI
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
@@ -53,46 +42,41 @@
             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 '      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 $CONFIG_EXPERIMENTAL
-	    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 $CONFIG_EXPERIMENTAL
-
-	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
-	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
-	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
-	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
-  	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "y" ]; then
-	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
-	    fi
+#	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+            dep_tristate '    Pacific Digital ADMA-100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+	    dep_tristate '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX
+	    dep_tristate '    CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Compaq Triflex IDE support' CONFIG_BLK_DEV_TRIFLEX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+  	    dep_tristate '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	    dep_tristate '    HPT36X/37X chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
 	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	    fi
-	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-#	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+	    dep_tristate '    PROMISE PDC202{46|62|65|67} support' CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool     '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFI_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI
+		# FIXME - probably wants to be one for old and for new
+	    dep_bool     '    Special FastTrak Feature' CONFIG_PDC202XX_FORCE
+	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+	    dep_tristate '    SCx200 chipset support' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_tristate '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-	       bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	       dep_tristate '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEPCI
 	    fi
          fi
       fi
@@ -149,14 +133,12 @@
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
 	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-	 fi
-	 bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
-	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+	 dep_tristate '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278 $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 $CONFIG_BLK_DEV_IDEDISK $CONFIG_EXPERIMENTAL
+	 dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672 $CONFIG_BLK_DEV_IDE
       fi
    fi
 else
@@ -184,7 +166,26 @@
   define_bool CONFIG_DMA_NONPCI n
 fi
 
-if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+   if [ "$CONFIG_BLK_DEV_PDC202XX_OLD" != "n" -o \
+        "$CONFIG_BLK_DEV_PDC202XX_NEW" != "n" ]; then
+      define_bool CONFIG_BLK_DEV_PDC202XX y
+   fi
+fi
+
+##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then
+##  dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK
+##else
+##  dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK
+##fi
+
+if [ "$CONFIG_BLK_DEV_4DRIVES" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI14XX" != "n" -o \
+     "$CONFIG_BLK_DEV_DTC2278" != "n" -o \
+     "$CONFIG_BLK_DEV_HT6560B" != "n" -o \
+     "$CONFIG_BLK_DEV_PDC4030" != "n" -o \
+     "$CONFIG_BLK_DEV_QD65XX" != "n" -o \
+     "$CONFIG_BLK_DEV_UMC8672" != "n" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
@@ -195,16 +196,19 @@
      "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
      "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" -o \
+     "$CONFIG_BLK_DEV_NFORCE" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
      "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
-     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
+     "$CONFIG_BLK_DEV_SIIMAGE" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
-     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \
-     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
    define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
@@ -213,5 +217,6 @@
 dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
 dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Silicon Image Medley software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_SII $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Makefile linux-2.4.21-rc3/drivers/ide/Makefile
--- linux-2.4.20/drivers/ide/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/Makefile	2003-05-22 22:06:49.000000000 +0000
@@ -10,80 +10,58 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o
-list-multi		:= ide-mod.o ide-probe-mod.o
+export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o ide-io.o ide-disk.o
+
+all-subdirs	:= arm legacy pci ppc raid
+mod-subdirs	:= arm legacy pci ppc raid
 
 obj-y		:=
 obj-m		:=
 ide-obj-y	:=
 
-obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
-obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o ide-probe-mod.o
-obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
-obj-$(CONFIG_BLK_DEV_IDEDISK)   += ide-disk.o
-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
-ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI15X3)	+= alim15x3.o
-ide-obj-$(CONFIG_BLK_DEV_AMD74XX)	+= amd74xx.o
-ide-obj-$(CONFIG_BLK_DEV_BUDDHA)	+= buddha.o
-ide-obj-$(CONFIG_BLK_DEV_CMD640)	+= cmd640.o
-ide-obj-$(CONFIG_BLK_DEV_CMD64X)	+= cmd64x.o
-ide-obj-$(CONFIG_BLK_DEV_CS5530)	+= cs5530.o
-ide-obj-$(CONFIG_BLK_DEV_CY82C693)	+= cy82c693.o
-ide-obj-$(CONFIG_BLK_DEV_DTC2278)	+= dtc2278.o
-ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
-ide-obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
-ide-obj-$(CONFIG_BLK_DEV_Q40IDE)	+= q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HPT34X)	+= hpt34x.o
-ide-obj-$(CONFIG_BLK_DEV_HPT366)	+= hpt366.o
-ide-obj-$(CONFIG_BLK_DEV_HT6560B)	+= ht6560b.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
-ide-obj-$(CONFIG_BLK_DEV_ADMA)		+= ide-adma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
-ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= ide-sibyte.o
-ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
-ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
-ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
-ide-obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
-ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
-ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
-ide-obj-$(CONFIG_BLK_DEV_PDC_ADMA)	+= pdcadma.o
-ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
-ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
-ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
-ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
-ide-obj-$(CONFIG_BLK_DEV_SLC90E66)	+= slc90e66.o
-ide-obj-$(CONFIG_BLK_DEV_SL82C105)	+= sl82c105.o
-ide-obj-$(CONFIG_BLK_DEV_TRM290)	+= trm290.o
-ide-obj-$(CONFIG_BLK_DEV_UMC8672)	+= umc8672.o
-ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)	+= via82cxxx.o
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
-
-# 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_PDC)	+= pdcraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm raid pci
 
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
+# First come modules that register themselves with the core
 
-ide-mod-objs		:= ide.o ide-features.o ide-taskfile.o $(ide-obj-y)
-ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= pci/idedriver-pci.o
+endif
+
+# Core IDE code - must come before legacy
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o ide-default.o
+obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
+
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+obj-$(CONFIG_BLK_DEV_IDE)		+= setup-pci.o
+endif
+ifeq ($(CONFIG_BLK_DEV_IDEDMA_PCI),y)
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-dma.o
+endif
+obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
+
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= legacy/idedriver-legacy.o
+  obj-y		+= ppc/idedriver-ppc.o
+  obj-y		+= arm/idedriver-arm.o
+else
+  ifeq ($(CONFIG_BLK_DEV_HD_ONLY),y)
+	obj-y	+= legacy/idedriver-legacy.o
+  endif
+endif
+
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+# RAID must be last of all
+  obj-y		+= raid/idedriver-raid.o
+endif
 
 include $(TOPDIR)/Rules.make
-
-ide-mod.o: $(ide-mod-objs)
-	$(LD) -r -o $@ $(ide-mod-objs)
-
-ide-probe-mod.o: $(ide-probe-mod-objs)
-	$(LD) -r -o $@ $(ide-probe-mod-objs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/aec62xx.c linux-2.4.21-rc3/drivers/ide/aec62xx.c
--- linux-2.4.20/drivers/ide/aec62xx.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,582 +0,0 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.09	June. 9, 2000
- *
- * 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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_AEC62XX_TIMINGS
-
-#ifndef HIGH_4
-#define HIGH_4(H)		((H)=(H>>4))
-#endif
-#ifndef LOW_4
-#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
-#endif
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-#ifndef MAKE_WORD
-#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
-#endif
-
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec62xx_get_info(char *, char **, off_t, int);
-extern int (*aec62xx_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 aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-	u8 art = 0, uart = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
-			break;
-	}
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
-	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 ");
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)           %s(%s)\n",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		default:
-			break;
-	}
-
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-#ifdef CONFIG_AEC62XX_TUNING
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-
-	byte		chipset_settings_34;
-	byte		ultra_settings_34;
-
-	byte		chipset_settings_33;
-	byte		ultra_settings_33;
-};
-
-struct chipset_bus_clock_list_entry aec62xx_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
-	{	0,		0x00,	0x00,	0x00,	0x00	}
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
-		}
-	return 0x00;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
-		}
-	return 0x00;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
-	SPLIT_BYTE(tmp0,tmp1,tmp2);
-	MAKE_WORD(d_conf,tmp1,tmp2);
-	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-	tmp1 = 0x00;
-	tmp2 = 0x00;
-	pci_read_config_byte(dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	err = ide_config_drive_speed(drive, speed);
-	return(err);
-}
-
-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
-	int err			= 0;
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-	pci_read_config_byte(dev, ultra_pci, &ultra);
-	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	__restore_flags(flags);	/* local CPU only */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return(err);
-}
-
-
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-		return ((int) aec6210_tune_chipset(drive, speed));
-	} else {
-		return ((int) aec6260_tune_chipset(drive, speed));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if (((id->dma_ultra & 0x0010) ||
-	     (id->dma_ultra & 0x0008) ||
-	     (id->dma_ultra & 0x0004)) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
- 		return ((int) ide_dma_off_quietly);
- 	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6210_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-	byte ultra66		= eighty_ninty_three(drive);
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6260_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? 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);
-}
-
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	switch(HWIF(drive)->pci_dev->device) {	
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return config_aec6210_chipset_for_dma(drive, ultra);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return config_aec6260_chipset_for_dma(drive, ultra);
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	switch(pio) {
-		case 5:		speed = new_pio; break;
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) aec6210_tune_chipset(drive, speed);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) aec6260_tune_chipset(drive, speed);
-		default:
-			break;
-        }
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x001F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		aec62xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			switch(HWIF(drive)->pci_dev->device) {
-				case PCI_DEVICE_ID_ARTOP_ATP860:
-				case PCI_DEVICE_ID_ARTOP_ATP860R:
-//					{
-//						int i = 0;
-//						byte reg49h = 0;
-//						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
-//						for (i=0;i<256;i++)
-//							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-//						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
-//					}
-//					return 0;
-				default:
-					break;
-			}
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
-{
-	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 defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		bmide_dev = dev;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
-{
-	byte mask	= hwif->channel ? 0x02 : 0x01;
-	byte ata66	= 0;
-
-	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-	return ((ata66 & mask) ? 0 : 1);
-}
-
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &aec62xx_dmaproc;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-}
-
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	unsigned long flags;
-	byte reg54h = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
-
-	__restore_flags(flags);	/* local CPU only */
-#endif /* CONFIG_AEC62XX_TUNING */
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ali14xx.c linux-2.4.21-rc3/drivers/ide/ali14xx.c
--- linux-2.4.20/drivers/ide/ali14xx.c	2001-07-15 23:22:23.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,226 +0,0 @@
-/*
- *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function.  The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk.  I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg  (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets.  I've added support for PIO mode 4 for the 1487.  This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.)  -Derek
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
-
-/* register initialization data */
-typedef struct { byte reg, data; } RegInitializer;
-
-static RegInitializer initData[] __initdata = {
-	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
-	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
-	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
-	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
-	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
-	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
-	{0x35, 0x03}, {0x00, 0x00}
-};
-
-#define ALI_MAX_PIO 4
-
-/* timing parameter registers for each drive */
-static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
-	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
-};
-
-static int basePort;	/* base port address */
-static int regPort;	/* port for register number */
-static int dataPort;	/* port for register data */
-static byte regOn;	/* output to base port to access registers */
-static byte regOff;	/* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline byte inReg (byte reg)
-{
-	outb_p(reg, regPort);
-	return inb(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg (byte data, byte reg)
-{
-	outb_p(reg, regPort);
-	outb_p(data, dataPort);
-}
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int driveNum;
-	int time1, time2;
-	byte param1, param2, param3, param4;
-	unsigned long flags;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-
-	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
-	/* calculate timing, according to PIO mode */
-	time1 = d.cycle_time;
-	time2 = ide_pio_timings[pio].active_time;
-	param3 = param1 = (time2 * bus_speed + 999) / 1000;
-	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
-	if (pio < 3) {
-		param3 += 8;
-		param4 += 8;
-	}
-	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-		drive->name, pio, time1, time2, param1, param2, param3, param4);
-
-	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb_p(regOn, basePort);
-	outReg(param1, regTab[driveNum].reg1);
-	outReg(param2, regTab[driveNum].reg2);
-	outReg(param3, regTab[driveNum].reg3);
-	outReg(param4, regTab[driveNum].reg4);
-	outb_p(regOff, basePort);
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort (void)
-{
-	int i;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	for (i = 0; i < ALI_NUM_PORTS; ++i) {
-		basePort = ports[i];
-		regOff = inb(basePort);
-		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-			outb_p(regOn, basePort);
-			if (inb(basePort) == regOn) {
-				regPort = basePort + 4;
-				dataPort = basePort + 8;
-				t = inReg(0) & 0xf0;
-				outb_p(regOff, basePort);
-				__restore_flags(flags);	/* local CPU only */
-				if (t != 0x50)
-					return 0;
-				return 1;  /* success */
-			}
-		}
-		outb_p(regOff, basePort);
-	}
-	__restore_flags(flags);	/* local CPU only */
-	return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	outb_p(regOn, basePort);
-	for (p = initData; p->reg != 0; ++p)
-		outReg(p->data, p->reg);
-	outb_p(0x01, regPort);
-	t = inb(regPort) & 0x01;
-	outb_p(regOff, basePort);
-	__restore_flags(flags);	/* local CPU only */
-	return t;
-}
-
-void __init init_ali14xx (void)
-{
-	/* auto-detect IDE controller port */
-	if (!findPort()) {
-		printk("\nali14xx: not found");
-		return;
-	}
-
-	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
-	ide_hwifs[0].chipset = ide_ali14xx;
-	ide_hwifs[1].chipset = ide_ali14xx;
-	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-
-	/* initialize controller registers */
-	if (!initRegisters()) {
-		printk("\nali14xx: Chip initialization failed");
-		return;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/alim15x3.c linux-2.4.21-rc3/drivers/ide/alim15x3.c
--- linux-2.4.20/drivers/ide/alim15x3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,705 +0,0 @@
-/*
- * linux/drivers/ide/alim15x3.c		Version 0.10	Jun. 9, 2000
- *
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- *  9/7/99 --Parts from the above author are included and need to be
- *  converted into standard interface, once I finish the thought.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_ALI_TIMINGS
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
-extern int (*ali_display_info)(char *, char **, off_t, int);  /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-char *fifo[4] = {
-	"FIFO Off",
-	"FIFO On ",
-	"DMA mode",
-	"PIO mode" };
-
-char *udmaT[8] = {
-	"1.5T",
-	"  2T",
-	"2.5T",
-	"  3T",
-	"3.5T",
-	"  4T",
-	"  6T",
-	"  8T"
-};
-
-char *channel_status[8] = {
-	"OK            ",
-	"busy          ",
-	"DRQ           ",
-	"DRQ busy      ",
-	"error         ",
-	"error busy    ",
-	"error DRQ     ",
-	"error DRQ busy"
-};
-
-static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
-	unsigned int bibma;
-	byte c0, c1;
-	byte rev, tmp;
-	char *p = buffer;
-	char *q;
-
-	/* fetch rev. */
-	pci_read_config_byte(bmide_dev, 0x08, &rev);
-	if (rev >= 0xc1)	/* M1543C or newer */
-		udmaT[7] = " ???";
-	else
-		fifo[3]  = "   ???  ";
-
-	/* first fetch bibma: */
-	pci_read_config_dword(bmide_dev, 0x20, &bibma);
-	bibma = (bibma & 0xfff0) ;
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte
-	 * registers to investigate:
-	 */
-	c0 = inb((unsigned short)bibma + 0x02);
-	c1 = inb((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p,
-		"\n                                Ali M15x3 Chipset.\n");
-	p += sprintf(p,
-		"                                ------------------\n");
-	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
-	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
-
-	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
-	p += sprintf(p,
-		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
-		(reg53h & 0x02) ? "Yes" : "No ",
-		(reg53h & 0x01) ? "Yes" : "No " );
-	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
-	p += sprintf(p,
-		"FIFO Status: contains %d Words, runs%s%s\n\n",
-		(reg53h & 0x3f),
-		(reg53h & 0x40) ? " OVERWR" : "",
-		(reg53h & 0x80) ? " OVERRD." : "." );
-
-	p += sprintf(p,
-		"-------------------primary channel-------------------secondary channel---------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
-	p += sprintf(p,
-		"channel status:       %s                               %s\n",
-		(reg53h & 0x20) ? "On " : "Off",
-		(reg53h & 0x10) ? "On " : "Off" );
-
-	p += sprintf(p,
-		"both channels togth:  %s                               %s\n",
-		(c0&0x80) ? "No " : "Yes",
-		(c1&0x80) ? "No " : "Yes" );
-
-	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
-	p += sprintf(p,
-		"Channel state:        %s                    %s\n",
-		channel_status[reg53h & 0x07],
-		channel_status[(reg53h & 0x70) >> 4] );
-
-	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
-	p += sprintf(p,
-		"Add. Setup Timing:    %dT                                %dT\n",
-		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
-		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
-
-	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
-	p += sprintf(p,
-		"Command Act. Count:   %dT                                %dT\n"
-		"Command Rec. Count:   %dT                               %dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"----------------drive0-----------drive1------------drive0-----------drive1------\n\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 " );
-
-	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
-	q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
-	if (rev < 0xc1) {
-		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
-			p += sprintf(p, q, 8, 8, 8, 8);
-		} else {
-			p += sprintf(p, q,
-				(reg5xh & 0x03) + 12,
-				((reg5xh & 0x30)>>4) + 12,
-				(reg5yh & 0x03) + 12,
-				((reg5yh & 0x30)>>4) + 12 );
-		}
-	} else {
-		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
-		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
-		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
-		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
-		p += sprintf(p, q, t1, t2, t3, t4);
-	}
-
-#if 0
-	p += sprintf(p, 
-		"FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
-		(reg5xh & 0x03) + 12,
-		((reg5xh & 0x30)>>4) + 12,
-		(reg5yh & 0x03) + 12,
-		((reg5yh & 0x30)>>4) + 12 );
-#endif
-
-	p += sprintf(p,
-		"FIFO mode:        %s         %s          %s         %s\n",
-		fifo[((reg5xh & 0x0c) >> 2)],
-		fifo[((reg5xh & 0xc0) >> 6)],
-		fifo[((reg5yh & 0x0c) >> 2)],
-		fifo[((reg5yh & 0xc0) >> 6)] );
-
-	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
-	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
-	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
-
-	p += sprintf(p,/*
-		"------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
-		"Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
-		"Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
-		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
-		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"-----------------------------------UDMA Timings--------------------------------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
-	p += sprintf(p,
-		"UDMA:             %s               %s                %s               %s\n"
-		"UDMA timings:     %s             %s              %s             %s\n\n",
-		(reg5xh & 0x08) ? "OK" : "No",
-		(reg5xh & 0x80) ? "OK" : "No",
-		(reg5yh & 0x08) ? "OK" : "No",
-		(reg5yh & 0x80) ? "OK" : "No",
-		udmaT[(reg5xh & 0x07)],
-		udmaT[(reg5xh & 0x70) >> 4],
-		udmaT[reg5yh & 0x07],
-		udmaT[(reg5yh & 0x70) >> 4] );
-
-	return p-buffer; /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static byte m5229_revision;
-static byte chip_is_1543c_e;
-
-byte ali_proc = 0;
-static struct pci_dev *isa_dev;
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	int s_time, a_time, c_time;
-	byte s_clc, a_clc, r_clc;
-	unsigned long flags;
-	int bus_speed = system_bus_clock();
-	int port = hwif->index ? 0x5c : 0x58;
-	int portFIFO = hwif->channel ? 0x55 : 0x54;
-	byte cd_dma_fifo = 0;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-	s_time = ide_pio_timings[pio].setup_time;
-	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
-		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
-		a_clc = 0;
-	c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
-		r_clc = 0;
-#endif
-
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
-		r_clc = 1;
-	} else {
-		if (r_clc >= 16)
-			r_clc = 0;
-	}
-	__save_flags(flags);
-	__cli();
-	
-	/* 
-	 * PIO mode => ATA FIFO on, ATAPI FIFO off
-	 */
-	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
-		} else {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
-		}
-	} else {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
-		} else {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
-		}
-	}
-	
-	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-	__restore_flags(flags);
-
-	/*
-	 * setup   active  rec
-	 * { 70,   165,    365 },   PIO Mode 0
-	 * { 50,   125,    208 },   PIO Mode 1
-	 * { 30,   100,    110 },   PIO Mode 2
-	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
-	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
-	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
-	 */
-
-}
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte tmpbyte		= 0x00;
-	int m5229_udma		= hwif->channel? 0x57 : 0x56;
-	int err			= 0;
-
-	if (speed < XFER_UDMA_0) {
-		byte ultra_enable	= (unit) ? 0x7f : 0xf7;
-		/*
-		 * clear "ultra enable" bit
-		 */
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= ultra_enable;
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-	}
-
-	err = ide_config_drive_speed(drive, speed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		unsigned long dma_base = hwif->dma_base;
-
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= (0x0f << ((1-unit) << 2));
-		/*
-		 * enable ultra dma and set timing
-		 */
-		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-		if (speed >= XFER_UDMA_3) {
-			pci_read_config_byte(dev, 0x4b, &tmpbyte);
-			tmpbyte |= 1;
-			pci_write_config_byte(dev, 0x4b, tmpbyte);
-		}
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	drive->current_speed = speed;
-
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	ali15x3_tune_drive(drive, 5);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	byte ultra100		= (m5229_revision>=0xc4) ? 1 : 0;
-	int  rval;
-
-	if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra33)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) ali15x3_tune_chipset(drive, speed);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	rval = (int)(	((id->dma_ultra >> 11) & 3) ? 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 byte ali15x3_can_ultra (ide_drive_t *drive)
-{
-#ifndef CONFIG_WDC_ALI15X3
-	struct hd_driveid *id	= drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
-
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_on;
-	byte can_ultra_dma		= ali15x3_can_ultra(drive);
-
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return hwif->dmaproc(dma_func, drive);
-}
-
-static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch(func) {
-		case ide_dma_check:
-			return ali15x3_config_drive_for_dma(drive);
-		case ide_dma_write:
-			if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
-				return 1;	/* try PIO instead of DMA */
-			break;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
-
-	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!ali_proc) {
-		ali_proc = 1;
-		bmide_dev = dev;
-		ali_display_info = &ali_get_info;
-	}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-	return 0;
-}
-
-/*
- * This checks if the controller and the cable are capable
- * of UDMA66 transfers. It doesn't check the drives.
- * But see note 2 below!
- */
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int ata66	= 0;
-	byte cable_80_pin[2]	= { 0, 0 };
-
-	unsigned long flags;
-	byte tmpbyte;
-
-	__save_flags(flags);
-	__cli();
-
-	if (m5229_revision >= 0xC2) {
-		/*
-		 * 1543C-B?, 1535, 1535D, 1553
-		 * Note 1: not all "motherboard" support this detection
-		 * Note 2: if no udma 66 device, the detection may "error".
-		 *         but in this case, we will not set the device to
-		 *         ultra 66, the detection result is not important
-		 */
-
-		/*
-		 * enable "Cable Detection", m5229, 0x4b, bit3
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-		/*
-		 * set south-bridge's enable bit, m1533, 0x79
-		 */
-		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-		if (m5229_revision == 0xC2) {
-			/*
-			 * 1543C-B0 (m1533, 0x79, bit 2)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-		} else if (m5229_revision >= 0xC3) {
-			/*
-			 * 1553/1535 (m1533, 0x79, bit 1)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-		}
-		/*
-		 * Ultra66 cable detection (from Host View)
-		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-		 */
-		pci_read_config_byte(dev, 0x4a, &tmpbyte);
-		/*
-		 * 0x4a, bit0 is 0 => primary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
-		/*
-		 * 0x4a, bit1 is 0 => secondary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
-		/*
-		 * Allow ata66 if cable of current channel has 80 pins
-		 */
-		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
-	} else {
-		/*
-		 * revision 0x20 (1543-E, 1543-F)
-		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		/*
-		 * clear bit 7
-		 */
-		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-		/*
-		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-		 */
-		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
-		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
-	}
-
-	/*
-	 * CD_ROM DMA on (m5229, 0x53, bit0)
-	 *      Enable this bit even if we want to use PIO
-	 * PIO FIFO off (m5229, 0x53, bit1)
-	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
-	 */
-	pci_read_config_byte(dev, 0x53, &tmpbyte);
-	tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-
-	pci_write_config_byte(dev, 0x53, tmpbyte);
-
-	__restore_flags(flags);
-
-	return(ata66);
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_SPARC64
-	byte ideic, inmir;
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-				      1, 11, 0, 12, 0, 14, 0, 15 };
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	if (isa_dev) {
-		/*
-		 * read IDE interface control
-		 */
-		pci_read_config_byte(isa_dev, 0x58, &ideic);
-
-		/* bit0, bit1 */
-		ideic = ideic & 0x03;
-
-		/* get IRQ for IDE Controller */
-		if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
-			/*
-			 * get SIRQ1 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x44, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->channel && !(ideic & 0x01)) {
-			/*
-			 * get SIRQ2 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x75, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		}
-	}
-#endif /* CONFIG_SPARC64 */
-
-	hwif->tuneproc = &ali15x3_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
-		/*
-		 * M1543C or newer for DMAing
-		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
-		hwif->autodma = 1;
-	}
-
-	if (noautodma)
-		hwif->autodma = 0;
-#else
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((dmabase) && (m5229_revision < 0x20)) {
-		return;
-	}
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/amd74xx.c linux-2.4.21-rc3/drivers/ide/amd74xx.c
--- linux-2.4.20/drivers/ide/amd74xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,513 +0,0 @@
-/*
- * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
- *
- * 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"
-
-#define DISPLAY_VIPER_TIMINGS
-
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int amd74xx_get_info(char *, char **, off_t, int);
-extern int (*amd74xx_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 amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                AMD %04X VIPER Chipset.\n", bmide_dev->device);
-	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");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte amd74xx_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-
-	if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) ||
-	    (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441))
-		return 0;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev >= 7) ? 1 : 0);
-}
-
-static int amd74xx_swdma_error(ide_drive_t *drive)
-{
-	printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
-	return 0;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- *
- */
-static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_pio_timing	= 0x00;
-	byte pio_timing		= 0x00;
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
-		case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
-		case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
-		case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
-		default:
-                        return -1;
-        }
-
-	pci_read_config_byte(dev, drive_pci, &ultra_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
-	pci_read_config_byte(dev, 0x4c, &pio_timing);
-
-#ifdef DEBUG
-	printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	ultra_timing	&= ~0xC7;
-	dma_pio_timing	&= ~0xFF;
-	pio_timing	&= ~(0x03 << drive->dn);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_7:
-		case XFER_UDMA_6:
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			ultra_timing |= 0x46;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_4:
-			ultra_timing |= 0x45;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_3:
-			ultra_timing |= 0x44;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_2:
-			ultra_timing |= 0x40;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_1:
-			ultra_timing |= 0x41;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_0:
-		ultra_timing |= 0x42;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_2:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_1:
-			dma_pio_timing |= 0x21;
-			break;
-		case XFER_MW_DMA_0:
-			dma_pio_timing |= 0x77;
-			break;
-		case XFER_SW_DMA_2:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_SW_DMA_1:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_SW_DMA_0:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0xA8;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_PIO_3:
-			dma_pio_timing |= 0x22;
-			break;
-		case XFER_PIO_2:
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_PIO_1:
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_PIO_0:
-		default:
-			dma_pio_timing |= 0xA8;
-			break;
-        }
-
-	pio_timing |= (0x03 << drive->dn);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci, ultra_timing);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
-	pci_write_config_byte(dev, 0x4c, pio_timing);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed > XFER_PIO_4) {
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	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;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 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 {
-		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;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)||
-				   (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0;
-	byte speed		= 0x00;
-	int  rval;
-
-	if (udma_100)
-		udma_66 = eighty_ninty_three(drive);
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (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) {
-		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 {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) amd74xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    ((id->dma_1word & 0x007) &&
-			     (amd74xx_swdma_check(HWIF(drive)->pci_dev)))) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-			
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * amd74xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int amd74xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (!amd74xx_swdma_check(dev))
-		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!amd74xx_proc) {
-		amd74xx_proc = 1;
-		bmide_dev = dev;
-		amd74xx_display_info = &amd74xx_get_info;
-	}
-#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte cable_80_pin[2]	= { 0, 0 };
-	byte ata66		= 0;
-	byte tmpbyte;
-
-	/*
-	 * Ultra66 cable detection (from Host View)
-	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
-	 */
-	pci_read_config_byte(dev, 0x42, &tmpbyte);
-
-	/*
-	 * 0x42, bit0 is 1 => primary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
-
-	/*
-	 * 0x42, bit2 is 1 => secondary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_VIPER_7441:
-		case PCI_DEVICE_ID_AMD_VIPER_7411:
-			ata66 = (hwif->channel) ?
-				cable_80_pin[1] :
-				cable_80_pin[0];
-		default:
-			break;
-	}
-#ifdef CONFIG_AMD74XX_OVERRIDE
-	return(1);
-#else
-	return (unsigned int) ata66;
-#endif /* CONFIG_AMD74XX_OVERRIDE */
-}
-
-void __init ide_init_amd74xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd74xx_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-	return;
-#else
-
-	if (hwif->dma_base) {
-		hwif->dmaproc = &amd74xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/Makefile linux-2.4.21-rc3/drivers/ide/arm/Makefile
--- linux-2.4.20/drivers/ide/arm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/arm/Makefile	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,12 @@
+
+O_TARGET := idedriver-arm.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/icside.c linux-2.4.21-rc3/drivers/ide/arm/icside.c
--- linux-2.4.20/drivers/ide/arm/icside.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/arm/icside.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,875 @@
+/*
+ * linux/drivers/ide/arm/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ *  08-Jun-1996	RMK	Created
+ *  12-Sep-1997	RMK	Added interrupt enable/disable
+ *  17-Apr-1999	RMK	Added support for V6 EASI
+ *  22-May-1999	RMK	Added support for V6 DMA
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#include "ide-noise.h"
+
+/*
+ * FIXME: We want to drop the the MACRO CRAP!
+ *
+ * ec->iops->in{b/w/l}
+ * ec->iops->in{b/w/l}_p
+ * ec->iops->out{b/w/l}
+ * ec->iops->out{b/w/l}_p
+ *
+ * the new core supports clean MMIO calls and other goodies
+ */
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS	2
+
+#define ICS_IDENT_OFFSET		0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT		0x000
+#define ICS_ARCIN_V5_INTROFFSET		0x001
+#define ICS_ARCIN_V5_IDEOFFSET		0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
+#define ICS_ARCIN_V5_IDESTEPPING	4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
+#define ICS_ARCIN_V6_INTROFFSET_1	0x880
+#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
+#define ICS_ARCIN_V6_IDESTEPPING	4
+
+struct cardinfo {
+	unsigned int dataoffset;
+	unsigned int ctrloffset;
+	unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+	ICS_ARCIN_V5_IDEOFFSET,
+	ICS_ARCIN_V5_IDEALTOFFSET,
+	ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+	ICS_ARCIN_V6_IDEOFFSET_1,
+	ICS_ARCIN_V6_IDEALTOFFSET_1,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+	ICS_ARCIN_V6_IDEOFFSET_2,
+	ICS_ARCIN_V6_IDEALTOFFSET_2,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+	{ MANU_ICS,  PROD_ICS_IDE  },
+	{ MANU_ICS2, PROD_ICS2_IDE },
+	{ 0xffff, 0xffff }
+};
+
+typedef enum {
+	ics_if_unknown,
+	ics_if_arcin_v5,
+	ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+	icside_irqenable_arcin_v5,
+	icside_irqdisable_arcin_v5,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+	icside_irqenable_arcin_v6,
+	icside_irqdisable_arcin_v6,
+	icside_irqpending_arcin_v6,
+	NULL,
+	NULL,
+	NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose  : identify IDE interface type
+ * Notes    : checks the description string
+ */
+static iftype_t __init icside_identifyif (struct expansion_card *ec)
+{
+	unsigned int addr;
+	iftype_t iftype;
+	int id = 0;
+
+	iftype = ics_if_unknown;
+
+	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+	id = inb(addr) & 1;
+	id |= (inb(addr + 1) & 1) << 1;
+	id |= (inb(addr + 2) & 1) << 2;
+	id |= (inb(addr + 3) & 1) << 3;
+
+	switch (id) {
+	case 0: /* A3IN */
+		printk("icside: A3IN unsupported\n");
+		break;
+
+	case 1: /* A3USER */
+		printk("icside: A3USER unsupported\n");
+		break;
+
+	case 3:	/* ARCIN V6 */
+		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v6;
+		break;
+
+	case 15:/* ARCIN V5 (no id) */
+		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v5;
+		break;
+
+	default:/* we don't know - complain very loudly */
+		printk("icside: ***********************************\n");
+		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+		printk("icside: ***********************************\n");
+		printk("icside: please report this to linux@arm.linux.org.uk\n");
+		printk("icside: defaulting to ARCIN V5\n");
+		iftype = ics_if_arcin_v5;
+		break;
+	}
+
+	return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time.  NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+#define NR_ENTRIES 256
+#define TABLE_SIZE (NR_ENTRIES * 8)
+
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int ddir)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir);
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void icside_destroy_dmatable(ide_drive_t *drive)
+{
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
+
+	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
+static int
+icside_config_if(ide_drive_t *drive, int xfer_mode)
+{
+	int func = ide_dma_off;
+
+	switch (xfer_mode) {
+	case XFER_MW_DMA_2:
+		/*
+		 * The cycle time is limited to 250ns by the r/w
+		 * pulse width (90ns), however we should still
+		 * have a maximum burst transfer rate of 8MB/s.
+		 */
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_1:
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_0:
+		drive->drive_data = 480;
+		break;
+
+	default:
+		drive->drive_data = 0;
+		break;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = (u8) xfer_mode;
+
+	if (drive->drive_data &&
+	    ide_config_drive_speed(drive, (u8) xfer_mode) == 0)
+		func = ide_dma_on;
+	else
+		drive->drive_data = 480;
+
+	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+
+	drive->current_speed = (u8) xfer_mode;
+
+	return func;
+}
+
+static int
+icside_set_speed(ide_drive_t *drive, u8 speed)
+{
+	return icside_config_if(drive, speed);
+}
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+{
+	u8 dma_stat	= HWIF(drive)->ide_dma_end(drive);
+	/* get drive status */
+	u8 stat		= HWIF(drive)->INB(IDE_STATUS_REG);
+	int i;
+
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
+		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * The following is a sick duplication from ide-dma.c ;(
+ *
+ * This should be defined in one place only.
+ */
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+static struct drive_list_entry drive_whitelist [] = {
+	{ "Micropolis 2112A",			"ALL"		},
+	{ "CONNER CTMA 4000",			"ALL"		},
+	{ "CONNER CTT8000-A",			"ALL"		},
+	{ "ST34342A",				"ALL"		},
+	{ NULL,					0		}
+};
+
+static struct drive_list_entry drive_blacklist [] = {
+	{ "WDC AC11000H",			"ALL"		},
+	{ "WDC AC22100H",			"ALL"		},
+	{ "WDC AC32500H",			"ALL"		},
+	{ "WDC AC33100H",			"ALL"		},
+	{ "WDC AC31600H",			"ALL"		},
+	{ "WDC AC32100H",			"24.09P07"	},
+	{ "WDC AC23200L",			"21.10N21"	},
+	{ "Compaq CRD-8241B",			"ALL"		},
+	{ "CRD-8400B",				"ALL"		},
+	{ "CRD-8480B",				"ALL"		},
+	{ "CRD-8480C",				"ALL"		},
+	{ "CRD-8482B",				"ALL"		},
+ 	{ "CRD-84",				"ALL"		},
+	{ "SanDisk SDP3B",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SANYO CD-ROM CRD",			"ALL"		},
+	{ "HITACHI CDR-8",			"ALL"		},
+	{ "HITACHI CDR-8335",			"ALL"		},
+	{ "HITACHI CDR-8435",			"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
+	{ "CD-532E-A",				"ALL"		},
+	{ "E-IDE CD-ROM CR-840",		"ALL"		},
+	{ "CD-ROM Drive/F5A",			"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
+	{ "WPI CDD-820",			"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",			"ALL"		},
+	{ NULL,					0		}
+};
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
+}
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_good_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	return in_drive_list(id, drive_whitelist);
+}
+
+int check_drive_bad_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist)
+		printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+	return(blacklist);
+}
+
+int icside_dma_check(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	int autodma = hwif->autodma;
+	int xfer_mode = XFER_PIO_2;
+
+	if (!id || !(id->capability & 1) || !autodma)
+		return hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * Consult the list of known "bad" drives
+	 */
+	if (check_drive_bad_lists(drive))
+		return hwif->ide_dma_off(drive);
+
+	/*
+	 * Enable DMA on any drive that has multiword DMA
+	 */
+	if (id->field_valid & 2) {
+		if (id->dma_mword & 4) {
+			xfer_mode = XFER_MW_DMA_2;
+		} else if (id->dma_mword & 2) {
+			xfer_mode = XFER_MW_DMA_1;
+		} else if (id->dma_mword & 1) {
+			xfer_mode = XFER_MW_DMA_0;
+		}
+		goto out;
+	}
+
+	/*
+	 * Consult the list of known "good" drives
+	 */
+	if (check_drive_good_lists(drive)) {
+		if (id->eide_dma_time > 150)
+			goto out;
+		xfer_mode = XFER_MW_DMA_1;
+	}
+
+out:
+	if (icside_config_if(drive, xfer_mode))
+		return hwif->ide_dma_on(drive);
+	return hwif->ide_dma_off(drive);
+}
+
+int icside_dma_verbose(ide_drive_t *drive)
+{
+	printk(", DMA");
+	return 1;
+}
+
+int icside_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	return inb((unsigned long)hwif->hw.priv) & 1;
+}
+
+int icside_dma_host_off(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_off_quietly(ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	return icside_dma_host_off(drive);
+}
+
+int icside_dma_off(ide_drive_t *drive)
+{
+	printk("%s: DMA disabled\n", drive->name);
+	return icside_dma_off_quietly(drive);
+}
+
+int icside_dma_host_on(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_on(ide_drive_t *drive)
+{
+	drive->using_dma = 1;
+	return icside_dma_host_on(drive);
+}
+
+int icside_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	enable_dma(hwif->hw.dma);
+	return 0;
+}
+
+int icside_dma_end(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 
+	drive->waiting_for_dma = 0;
+	disable_dma(hwif->hw.dma);
+	icside_destroy_dmatable(drive);
+	return get_dma_residue(hwif->hw.dma) != 0;
+}
+
+int icside_dma_count (ide_drive_t *drive)
+{
+        return icside_dma_begin(drive);
+}
+
+int icside_dma_read(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_FROMDEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_READ);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+		if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+int icside_dma_write(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_TODEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+	printk("    %s: SG-DMA", hwif->name);
+
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+				 GFP_KERNEL);
+	if (!hwif->sg_table)
+		goto failed;
+
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+	hwif->speedproc = icside_set_speed;
+	hwif->autodma = autodma;
+
+	hwif->ide_dma_check = icside_dma_check;
+	hwif->ide_dma_host_off = icside_dma_host_off;
+	hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+	hwif->ide_dma_off = icside_dma_off;
+	hwif->ide_dma_host_on = icside_dma_host_on;
+	hwif->ide_dma_on = icside_dma_on;
+	hwif->ide_dma_read = icside_dma_read;
+	hwif->ide_dma_write = icside_dma_write;
+	hwif->ide_dma_count = icside_dma_count;
+	hwif->ide_dma_begin = icside_dma_begin;
+	hwif->ide_dma_end = icside_dma_end;
+	hwif->ide_dma_verbose = icside_dma_verbose;
+	hwif->ide_dma_bad_drive = check_drive_bad_lists;
+	hwif->ide_dma_good_drive = check_drive_good_lists;
+	hwif->ide_dma_test_irq = icside_dma_test_irq;
+
+	printk(" capable%s\n", autodma ?
+		", auto-enable" : "");
+
+	return 1;
+
+failed:
+	printk(" -- ERROR, unable to allocate DMA table\n");
+	return 0;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+	ide_hwif_t *hwif;
+	int index;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+			goto found;
+	}
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (!hwif->io_ports[IDE_DATA_OFFSET])
+			goto found;
+	}
+
+	return NULL;
+found:
+	return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+	unsigned long port = base + info->dataoffset;
+	ide_hwif_t *hwif;
+
+	hwif = icside_find_hwif(base);
+	if (hwif) {
+		int i;
+
+		memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+			hwif->io_ports[i] = (ide_ioreg_t)port;
+			port += 1 << info->stepping;
+		}
+		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->hw.irq  = irq;
+		hwif->irq     = irq;
+		hwif->hw.dma  = NO_DMA;
+		hwif->noprobe = 0;
+		hwif->chipset = ide_acorn;
+	}
+
+	return hwif;
+}
+
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port;
+	ide_hwif_t *hwif;
+
+	slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+	ec->irqmask  = 1;
+	ec->irq_data = (void *)slot_port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+	return hwif ? 0 : -1;
+}
+
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port, port;
+	ide_hwif_t *hwif, *mate;
+	int sel = 0;
+
+	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+	if (port == 0)
+		port = slot_port;
+	else
+		sel = 1 << 5;
+
+	outb(sel, slot_port);
+
+	ec->irq_data = (void *)port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+	if (ec->dma != NO_DMA) {
+		if (request_dma(ec->dma, hwif->name))
+			goto no_dma;
+
+		if (hwif) {
+			hwif->config_data = slot_port;
+			hwif->select_data = sel;
+			hwif->hw.dma  = ec->dma;
+			hwif->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_1);
+			hwif->channel = 0;
+			icside_setup_dma(hwif, autodma);
+			hwif->drives[0].autodma = autodma;
+			hwif->drives[1].autodma = autodma;
+		}
+		if (mate) {
+			mate->config_data = slot_port;
+			mate->select_data = sel | 1;
+			mate->hw.dma  = ec->dma;
+			mate->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_2);
+			mate->channel = 1;
+			icside_setup_dma(mate, autodma);
+			mate->drives[0].autodma = autodma;
+			mate->drives[1].autodma = autodma;
+		}
+	}
+no_dma:
+#endif
+	return hwif || mate ? 0 : -1;
+}
+
+int __init icside_init(void)
+{
+	int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+	autodma = 1;
+#endif
+
+	ecard_startfind ();
+
+	do {
+		struct expansion_card *ec;
+		int result;
+
+		ec = ecard_find(0, icside_cids);
+		if (ec == NULL)
+			break;
+
+		ecard_claim(ec);
+
+		switch (icside_identifyif(ec)) {
+		case ics_if_arcin_v5:
+			result = icside_register_v5(ec, autodma);
+			break;
+
+		case ics_if_arcin_v6:
+			result = icside_register_v6(ec, autodma);
+			break;
+
+		default:
+			result = -1;
+			break;
+		}
+
+		if (result)
+			ecard_release(ec);
+	} while (1);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/rapide.c linux-2.4.21-rc3/drivers/ide/arm/rapide.c
--- linux-2.4.20/drivers/ide/arm/rapide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/arm/rapide.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,94 @@
+/*
+ * linux/drivers/ide/arm/rapide.c
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ *
+ * Changelog:
+ *  08-06-1996	RMK	Created
+ *  13-04-1998	RMK	Added manufacturer and product IDs
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+
+static card_ids __init rapide_cids[] = {
+	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+	{ 0xffff, 0xffff }
+};
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS];
+
+static inline int rapide_register(struct expansion_card *ec)
+{
+	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+	hw_regs_t hw;
+
+	int i;
+
+	memset(&hw, 0, sizeof(hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw.io_ports[i] = (ide_ioreg_t)port;
+		port += 1 << 4;
+	}
+	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+	hw.irq = ec->irq;
+
+	return ide_register_hw(&hw, NULL);
+}
+
+int __init rapide_init(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		ec[i] = NULL;
+
+	ecard_startfind();
+
+	for (i = 0; ; i++) {
+		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
+			break;
+
+		ecard_claim(ec[i]);
+		result[i] = rapide_register(ec[i]);
+	}
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i] && result[i] < 0) {
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module (void)
+{
+	return rapide_init();
+}
+
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i]) {
+			unsigned long port;
+			port = ecard_address(ec[i], ECARD_MEMC, 0);
+
+			ide_unregister_port(port, ec[i]->irq, 16);
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+		}
+}
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.c linux-2.4.21-rc3/drivers/ide/ataraid.c
--- linux-2.4.20/drivers/ide/ataraid.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ataraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,313 +0,0 @@
-/*
-   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/semaphore.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-#include <linux/kdev_t.h>
-#include <linux/swap.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-                                        
-static int ataraid_hardsect_size[256];
-static int ataraid_blksize_size[256];
-
-static struct raid_device_operations* ataraid_ops[16];
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int ataraid_open(struct inode * inode, struct file * filp);
-static int ataraid_release(struct inode * inode, struct file * filp);
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-struct gendisk ataraid_gendisk;
-static int ataraid_gendisk_sizes[256];
-static int ataraid_readahead[256];
-
-static struct block_device_operations ataraid_fops = {
-	owner:			THIS_MODULE,
-	open:                   ataraid_open,
-	release:                ataraid_release,
-	ioctl:                  ataraid_ioctl,
-};
-                
-
-
-static DECLARE_MUTEX(ataraid_sem);
-
-/* Bitmap for the devices currently in use */
-static unsigned int ataraiduse;
-
-
-/* stub fops functions */
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
-		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
-	return -EINVAL;
-}
-
-static int ataraid_open(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
-		return (ataraid_ops[minor]->open)(inode,filp);
-	return -EINVAL;
-}
-
-
-static int ataraid_release(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
-		return (ataraid_ops[minor]->release)(inode,filp);
-	return -EINVAL;
-}
-
-static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int minor;
-	int retval;
-	minor = MINOR(bh->b_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
-		
-		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
-		if (retval == -1) {
-			ataraid_split_request(q,rw,bh);		
-			return 0;
-		} else
-			return retval;
-	}
-	return -EINVAL;
-}
-
-struct buffer_head *ataraid_get_bhead(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_bhead);
-
-struct ataraid_bh_private *ataraid_get_private(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_private);
-
-void ataraid_end_request(struct buffer_head *bh, int uptodate)
-{
-	struct ataraid_bh_private *private = bh->b_private;
-
-	if (private==NULL)
-		BUG();
-
-	if (atomic_dec_and_test(&private->count)) {
-		private->parent->b_end_io(private->parent,uptodate);
-		private->parent = NULL;
-		kfree(private);
-	}
-	kfree(bh);
-}
-
-EXPORT_SYMBOL(ataraid_end_request);
-
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1,*bh2;
-	struct ataraid_bh_private *private;
-	bh1=ataraid_get_bhead();
-	bh2=ataraid_get_bhead();
-
-	/* If either of those ever fails we're doomed */
-	if ((!bh1)||(!bh2))
-		BUG();
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-	
-	memcpy(bh1, bh, sizeof(*bh));
-	memcpy(bh2, bh, sizeof(*bh));
-	
-	bh1->b_end_io = ataraid_end_request;
-	bh2->b_end_io = ataraid_end_request;
-
-	bh2->b_rsector += bh->b_size >> 10;
-	bh1->b_size /= 2;
-	bh2->b_size /= 2;
-	private->parent = bh;
-
-	bh1->b_private = private;
-	bh2->b_private = private;
-	atomic_set(&private->count,2);
-
-	bh2->b_data +=  bh->b_size/2;
-
-	generic_make_request(rw,bh1);
-	generic_make_request(rw,bh2);
-}
-
-
-
-
-/* device register / release functions */
-
-
-int ataraid_get_device(struct raid_device_operations *fops)
-{
-	int bit;
-	down(&ataraid_sem);
-	if (ataraiduse==~0U) {
-		up(&ataraid_sem);
-		return -ENODEV;
-	}
-	bit=ffz(ataraiduse); 
-	ataraiduse |= 1<<bit;
-	ataraid_ops[bit] = fops;
-	up(&ataraid_sem);
-	return bit;
-}
-
-void ataraid_release_device(int device)
-{
-	down(&ataraid_sem);
-	
-	if ((ataraiduse & (1<<device))==0)
-		BUG();	/* device wasn't registered at all */
-	
-	ataraiduse &= ~(1<<device);
-	ataraid_ops[device] = NULL;
-	up(&ataraid_sem);
-}
-
-void ataraid_register_disk(int device,long size)
-{
-	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
-		&ataraid_fops,size);
-
-}
-
-static __init int ataraid_init(void) 
-{
-	int i;
-        for(i=0;i<256;i++)
-	{
-        	ataraid_hardsect_size[i] = 512;
-		ataraid_blksize_size[i] = 1024;  
-		ataraid_readahead[i] = 1023;
-	}
-	
-	if (blksize_size[ATAMAJOR]==NULL)
-		blksize_size[ATAMAJOR] = ataraid_blksize_size;
-	if (hardsect_size[ATAMAJOR]==NULL)
-		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
-	
-	
-	/* setup the gendisk structure */	
-	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
-	if (ataraid_gendisk.part==NULL) {
-		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
-		return -1;
-	}
-	
-	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
-	
-	
-	ataraid_gendisk.major       = ATAMAJOR;
-	ataraid_gendisk.major_name  = "ataraid";
-	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
-	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
-	ataraid_gendisk.nr_real	    = 16;
-	ataraid_gendisk.fops        = &ataraid_fops;
-	
-	
-	add_gendisk(&ataraid_gendisk);
-			
-	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
-		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
-		return -1;
-	}
-	
-	                
-	
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
-                                                                                     	
-	return 0;                                                        	
-}
-
-
-static void __exit ataraid_exit(void)
-{
-	unregister_blkdev(ATAMAJOR, "ataraid");
-	hardsect_size[ATAMAJOR] = NULL;
-	blk_size[ATAMAJOR] = NULL;
-	blksize_size[ATAMAJOR] = NULL;                       
-	max_readahead[ATAMAJOR] = NULL;
-
-	del_gendisk(&ataraid_gendisk);
-        
-	if (ataraid_gendisk.part) {
-		kfree(ataraid_gendisk.part);
-		ataraid_gendisk.part = NULL;
-	}
-}
-
-module_init(ataraid_init);
-module_exit(ataraid_exit);
-
-
-
-EXPORT_SYMBOL(ataraid_get_device);
-EXPORT_SYMBOL(ataraid_release_device);
-EXPORT_SYMBOL(ataraid_gendisk);
-EXPORT_SYMBOL(ataraid_register_disk);
-MODULE_LICENSE("GPL");
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.h linux-2.4.21-rc3/drivers/ide/ataraid.h
--- linux-2.4.20/drivers/ide/ataraid.h	2001-10-08 20:32:28.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ataraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-/*
-   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/semaphore.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#define ATAMAJOR 114
-#define SHIFT 4
-#define MINOR_MASK 15
-#define MAJOR_MASK 15
-
-                                        
-/* raid_device_operations is a light struct block_device_operations with an
-   added method for make_request */
-struct raid_device_operations {
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
-};
-
-
-struct geom {
-	unsigned char heads;
-	unsigned int cylinders;
-	unsigned char sectors;
-};
-
-/* structure for the splitting of bufferheads */
-
-struct ataraid_bh_private {
-	struct buffer_head *parent;
-	atomic_t count;
-};
-
-extern struct gendisk ataraid_gendisk;
-
-extern int ataraid_get_device(struct raid_device_operations *fops);
-extern void ataraid_release_device(int device);
-extern int get_blocksize(kdev_t dev);
-extern void ataraid_register_disk(int device,long size);
-extern struct buffer_head *ataraid_get_bhead(void);
-extern struct ataraid_bh_private *ataraid_get_private(void);
-extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
-
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/buddha.c linux-2.4.21-rc3/drivers/ide/buddha.c
--- linux-2.4.20/drivers/ide/buddha.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/buddha.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,225 +0,0 @@
-/*
- *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- *  This driver was written based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at
- *  http://www.jschoenfeld.com
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *  TODO:
- *    - test it :-)
- *    - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
-    /*
-     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
-     */
-
-#define BUDDHA_NUM_HWIFS	2
-#define CATWEASEL_NUM_HWIFS	3
-#define XSURF_NUM_HWIFS         2
-
-    /*
-     *  Bases of the IDE interfaces (relative to the board address)
-     */
-
-#define BUDDHA_BASE1	0x800
-#define BUDDHA_BASE2	0xa00
-#define BUDDHA_BASE3	0xc00
-
-#define XSURF_BASE1     0xb000 /* 2.5" Interface */
-#define XSURF_BASE2     0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
-     XSURF_BASE1, XSURF_BASE2
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define BUDDHA_DATA	0x00
-#define BUDDHA_ERROR	0x06		/* see err-bits */
-#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define BUDDHA_SECTOR	0x0e		/* starting sector */
-#define BUDDHA_LCYL	0x12		/* starting cylinder */
-#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
-#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS	0x1e		/* see status-bits */
-#define BUDDHA_CONTROL	0x11a
-#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
-
-    /*
-     *  Other registers
-     */
-
-#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2	0xf40		/* interrupt */
-#define BUDDHA_IRQ3	0xf80
-
-#define XSURF_IRQ1      0x7e
-#define XSURF_IRQ2      0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
-    XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
-
-
-    /*
-     *  Board information
-     */
-
-typedef enum BuddhaType_Enum {
-    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int buddha_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-static int xsurf_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
-    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-    /*
-     *  Probe for a Buddha or Catweasel IDE interface
-     */
-
-void __init buddha_init(void)
-{
-	hw_regs_t hw;
-	int i, index;
-
-	struct zorro_dev *z = NULL;
-	u_long buddha_board = 0;
-	BuddhaType type;
-	int buddha_num_hwifs;
-
-	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-		unsigned long board;
-		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
-			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
-			type=BOARD_BUDDHA;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
-			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
-			type=BOARD_CATWEASEL;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
-			buddha_num_hwifs = XSURF_NUM_HWIFS;
-			type=BOARD_XSURF;
-		} else 
-			continue;
-		
-		board = z->resource.start;
-		
-		if(type != BOARD_XSURF) {
-			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
-				continue;
-		} else {
-			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
-				continue;
-			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
-				goto fail_base2;
-			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
-				release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
-				release_mem_region(board+XSURF_BASE1, 0x1000);
-				continue;
-			}
-		}	  
-		buddha_board = ZTWO_VADDR(board);
-		
-		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
-		/* X-Surf doesn't have this.  IRQs are always on */
-		if (type != BOARD_XSURF)
-			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
-		for(i=0;i<buddha_num_hwifs;i++) {
-			if(type != BOARD_XSURF) {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
-						buddha_offsets, 0,
-						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
-						buddha_ack_intr, IRQ_AMIGA_PORTS);
-			} else {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
-						xsurf_offsets, 0,
-						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
-						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}	
-			
-			index = ide_register_hw(&hw, NULL);
-			if (index != -1) {
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd640.c linux-2.4.21-rc3/drivers/ide/cmd640.c
--- linux-2.4.20/drivers/ide/cmd640.c	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/cmd640.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,856 +0,0 @@
-/*
- *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *  			mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for the advanced features and bugs
- *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- *  These chips are basically fucked by design, and getting this driver
- *  to work on every motherboard design that uses this screwed chip seems
- *  bloody well impossible.  However, we're still trying.
- *
- *  Version 0.97 worked for everybody.
- *
- *  User feedback is essential.  Many thanks to the beta test team:
- *
- *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- *  liug@mama.indstate.edu, and others.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	Fixes for vlb initialization code, enable prefetch
- *			for versions 'B' and 'C' of chip by default,
- *			some code cleanup.
- *
- *  Version 0.03	Added reset of secondary interface,
- *			and black list for devices which are not compatible
- *			with prefetch mode. Separate function for setting
- *			prefetch is added, possibly it will be called some
- *			day from ioctl processing code.
- *
- *  Version 0.04	Now configs/compiles separate from ide.c
- *
- *  Version 0.05	Major rewrite of interface timing code.
- *			Added new function cmd640_set_mode to set PIO mode
- *			from ioctl call. New drives added to black list.
- *
- *  Version 0.06	More code cleanup. Prefetch is enabled only for
- *			detected hard drives, not included in prefetch
- *			black list.
- *
- *  Version 0.07	Changed to more conservative drive tuning policy.
- *			Unknown drives, which report PIO < 4 are set to
- *			(reported_PIO - 1) if it is supported, or to PIO0.
- *			List of known drives extended by info provided by
- *			CMD at their ftp site.
- *
- *  Version 0.08	Added autotune/noautotune support.
- *
- *  Version 0.09	Try to be smarter about 2nd port enabling.
- *  Version 0.10	Be nice and don't reset 2nd port.
- *  Version 0.11	Try to handle more weird situations.
- *
- *  Version 0.12	Lots of bug fixes from Laszlo Peter
- *			irq unmasking disabled for reliability.
- *			try to be even smarter about the second port.
- *			tidy up source code formatting.
- *  Version 0.13	permit irq unmasking again.
- *  Version 0.90	massive code cleanup, some bugs fixed.
- *			defaults all drives to PIO mode0, prefetch off.
- *			autotune is OFF by default, with compile time flag.
- *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- *			 (requires hdparm-3.1 or newer)
- *  Version 0.91	first release to linux-kernel list.
- *  Version 0.92	move initial reg dump to separate callable function
- *			change "readahead" to "prefetch" to avoid confusion
- *  Version 0.95	respect original BIOS timings unless autotuning.
- *			tons of code cleanup and rearrangement.
- *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
- *			prevent use of unmask when prefetch is on
- *  Version 0.96	prevent use of io_32bit when prefetch is off
- *  Version 0.97	fix VLB secondary interface for sjd@slip.net
- *			other minor tune-ups:  0.96 was very good.
- *  Version 0.98	ignore PCI version when disabled by BIOS
- *  Version 0.99	display setup/active/recovery clocks with PIO mode
- *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
- *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
- *			 ("fast" is necessary for 32bit I/O in some systems)
- *  Version 1.02	fix bug that resulted in slow "setup times"
- *			 (patch courtesy of Zoltan Hidvegi)
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-#define CMD640_PREFETCH_MASKS 1
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
- */
-int cmd640_vlb = 0;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID		0x00
-#define DID		0x02
-#define PCMD		0x04
-#define   PCMD_ENA	0x01
-#define PSTTS		0x06
-#define REVID		0x08
-#define PROGIF		0x09
-#define SUBCL		0x0a
-#define BASCL		0x0b
-#define BaseA0		0x10
-#define BaseA1		0x14
-#define BaseA2		0x18
-#define BaseA3		0x1c
-#define INTLINE		0x3c
-#define INPINE		0x3d
-
-#define	CFR		0x50
-#define   CFR_DEVREV		0x03
-#define   CFR_IDE01INTR		0x04
-#define	  CFR_DEVID		0x18
-#define	  CFR_AT_VESA_078h	0x20
-#define	  CFR_DSA1		0x40
-#define	  CFR_DSA0		0x80
-
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define DRWTIM23	0x58
-#define BRST		0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * These are initialized to point at the devices we control
- */
-static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
-static ide_drive_t *cmd_drives[4];
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*put_cmd640_reg)(unsigned short reg, byte val);
-static byte (*get_cmd640_reg)(unsigned short reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg & 3) | 0xcfc);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci1 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p((reg & 3) | 0xcfc);
-	restore_flags(flags);
-	return b;
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci2 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-	return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	outb_p(val, cmd640_key + 4);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_vlb (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	b = inb_p(cmd640_key + 4);
-	restore_flags(flags);
-	return b;
-}
-
-static int __init match_pci_cmd640_device (void)
-{
-	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
-	unsigned int i;
-	for (i = 0; i < 4; i++) {
-		if (get_cmd640_reg(i) != ven_dev[i])
-			return 0;
-	}
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
-	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
-		printk("ide: cmd640 on PCI disabled by BIOS\n");
-		return 0;
-	}
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
-	return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci1;
-	put_cmd640_reg = put_cmd640_reg_pci1;
-	for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci2;
-	put_cmd640_reg = put_cmd640_reg_pci2;
-	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb (void)
-{
-	byte b;
-
-	get_cmd640_reg = get_cmd640_reg_vlb;
-	put_cmd640_reg = put_cmd640_reg_vlb;
-	cmd640_key = 0x178;
-	b = get_cmd640_reg(CFR);
-	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
-		cmd640_key = 0x78;
-		b = get_cmd640_reg(CFR);
-		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
-			return 0;
-	}
-	return 1; /* success */
-}
-
-/*
- *  Returns 1 if an IDE interface/drive exists at 0x170,
- *  Returns 0 otherwise.
- */
-static int __init secondary_port_responding (void)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
-	udelay(100);
-	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
-		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
-		udelay(100);
-		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
-			restore_flags(flags);
-			return 0; /* nothing responded */
-		}
-	}
-	restore_flags(flags);
-	return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers.  May be called from ide.c
- */
-void cmd640_dump_regs (void)
-{
-	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
-	/* Dump current state of chip registers */
-	printk("ide: cmd640 internal register dump:");
-	for (; reg <= 0x59; reg++) {
-		if (!(reg & 0x0f))
-			printk("\n%04x:", reg);
-		printk(" %02x", get_cmd640_reg(reg));
-	}
-	printk("\n");
-}
-#endif
-
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch (unsigned int index)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	byte b = get_cmd640_reg(prefetch_regs[index]);
-
-	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-	} else {
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-	}
-}
-
-/*
- * Figure out which devices we control
- */
-static void __init setup_device_ptrs (void)
-{
-	unsigned int i;
-
-	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
-	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		ide_hwif_t *hwif = &ide_hwifs[i];
-		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
-			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
-				cmd_hwif0 = hwif;
-			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-				cmd_hwif1 = hwif;
-		}
-	}
-	cmd_drives[0] = &cmd_hwif0->drives[0];
-	cmd_drives[1] = &cmd_hwif0->drives[1];
-	cmd_drives[2] = &cmd_hwif1->drives[0];
-	cmd_drives[3] = &cmd_hwif1->drives[1];
-}
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode (unsigned int index, int mode)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	int reg = prefetch_regs[index];
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	b = get_cmd640_reg(reg);
-	if (mode) {	/* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-		b &= ~prefetch_masks[index];	/* enable prefetch */
-	} else {
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-		b |= prefetch_masks[index];	/* disable prefetch */
-	}
-	put_cmd640_reg(reg, b);
-	restore_flags(flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks (unsigned int index)
-{
-	byte active_count, recovery_count;
-
-	active_count = active_counts[index];
-	if (active_count == 1)
-		++active_count;
-	recovery_count = recovery_counts[index];
-	if (active_count > 3 && recovery_count == 1)
-		++recovery_count;
-	if (cmd640_chip_version > 1)
-		recovery_count += 1;  /* cmd640b uses (count + 1)*/
-	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-inline static byte pack_nibbles (byte upper, byte lower)
-{
-	return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine retrieves the initial drive timings from the chipset.
- */
-static void __init retrieve_drive_counts (unsigned int index)
-{
-	byte b;
-
-	/*
-	 * Get the internal setup timing, and convert to clock count
-	 */
-	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
-	switch (b) {
-		case 0x00: b = 4; break;
-		case 0x80: b = 3; break;
-		case 0x40: b = 2; break;
-		default:   b = 5; break;
-	}
-	setup_counts[index] = b;
-
-	/*
-	 * Get the active/recovery counts
-	 */
-	b = get_cmd640_reg(drwtim_regs[index]);
-	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
-	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
-}
-
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts (unsigned int index)
-{
-	unsigned long flags;
-	byte setup_count    = setup_counts[index];
-	byte active_count   = active_counts[index];
-	byte recovery_count = recovery_counts[index];
-
-	/*
-	 * Set up address setup count and drive read/write timing registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * so we merge the timings, using the slowest value for each timing.
-	 */
-	if (index > 1) {
-		unsigned int mate;
-		if (cmd_drives[mate = index ^ 1]->present) {
-			if (setup_count < setup_counts[mate])
-				setup_count = setup_counts[mate];
-			if (active_count < active_counts[mate])
-				active_count = active_counts[mate];
-			if (recovery_count < recovery_counts[mate])
-				recovery_count = recovery_counts[mate];
-		}
-	}
-
-	/*
-	 * Convert setup_count to internal chipset representation
-	 */
-	switch (setup_count) {
-		case 4:	 setup_count = 0x00; break;
-		case 3:	 setup_count = 0x80; break;
-		case 1:
-		case 2:	 setup_count = 0x40; break;
-		default: setup_count = 0xc0; /* case 5 */
-	}
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	save_flags (flags);
-	cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 * (this converts counts of 16 into counts of zero -- okay).
-	 */
-	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
-	put_cmd640_reg(arttim_regs[index], setup_count);
-	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-	restore_flags(flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
-{
-	int setup_time, active_time, recovery_time, clock_time;
-	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = system_bus_clock();
-
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-	if (active_count < 2)
-		active_count = 2; /* minimum allowed by cmd640 */
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count < 2)
-		recovery_count = 2; /* minimum allowed by cmd640 */
-	if (recovery_count > 17) {
-		active_count += recovery_count - 17;
-		recovery_count = 17;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd640 */
-	if (cmd640_chip_version > 1)
-		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
-	if (recovery_count > 16)
-		recovery_count = 16; /* maximum allowed by cmd640 */
-
-	setup_counts[index]    = setup_count;
-	active_counts[index]   = active_count;
-	recovery_counts[index] = recovery_count;
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (index);
-}
-
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
-{
-	byte b;
-	ide_pio_data_t  d;
-	unsigned int index = 0;
-
-	while (drive != cmd_drives[index]) {
-		if (++index > 3) {
-			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
-			return;
-		}
-	}
-	switch (mode_wanted) {
-		case 6: /* set fast-devsel off */
-		case 7: /* set fast-devsel on */
-			mode_wanted &= 1;
-			b = get_cmd640_reg(CNTRL) & ~0x27;
-			if (mode_wanted)
-				b |= 0x27;
-			put_cmd640_reg(CNTRL, b);
-			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			set_prefetch_mode(index, mode_wanted);
-			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
-
-	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-		drive->name,
-		d.pio_mode,
-		d.cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "");
-	display_clocks(index);
-	return;
-}
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
- */
-int __init ide_probe_for_cmd640x (void)
-{
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	int second_port_toggled = 0;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	int second_port_cmd640 = 0;
-	const char *bus_type, *port2;
-	unsigned int index;
-	byte b, cfr;
-
-	if (cmd640_vlb && probe_for_cmd640_vlb()) {
-		bus_type = "VLB";
-	} else {
-		cmd640_vlb = 0;
-		if (probe_for_cmd640_pci1())
-			bus_type = "PCI (type1)";
-		else if (probe_for_cmd640_pci2())
-			bus_type = "PCI (type2)";
-		else
-			return 0;
-	}
-	/*
-	 * Undocumented magic (there is no 0x5b reg in specs)
-	 */
-	put_cmd640_reg(0x5b, 0xbd);
-	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
-		return 0;
-	}
-	put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-
-	/*
-	 * Documented magic begins here
-	 */
-	cfr = get_cmd640_reg(CFR);
-	cmd640_chip_version = cfr & CFR_DEVREV;
-	if (cmd640_chip_version == 0) {
-		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
-		return 0;
-	}
-
-	/*
-	 * Initialize data for primary port
-	 */
-	setup_device_ptrs ();
-	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
-	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
-	cmd_hwif0->chipset = ide_cmd640;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	cmd_hwif0->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-	/*
-	 * Ensure compatibility by always using the slowest timings
-	 * for access to the drive's command register block,
-	 * and reset the prefetch burstsize to default (512 bytes).
-	 *
-	 * Maybe we need a way to NOT do these on *some* systems?
-	 */
-	put_cmd640_reg(CMDTIM, 0);
-	put_cmd640_reg(BRST, 0x40);
-
-	/*
-	 * Try to enable the secondary interface, if not already enabled
-	 */
-	if (cmd_hwif1->noprobe) {
-		port2 = "not probed";
-	} else {
-		b = get_cmd640_reg(CNTRL);
-		if (secondary_port_responding()) {
-			if ((b & CNTRL_ENA_2ND)) {
-				second_port_cmd640 = 1;
-				port2 = "okay";
-			} else if (cmd640_vlb) {
-				second_port_cmd640 = 1;
-				port2 = "alive";
-			} else
-				port2 = "not cmd640";
-		} else {
-			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
-			if (secondary_port_responding()) {
-				second_port_cmd640 = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-				second_port_toggled = 1;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-				port2 = "enabled";
-			} else {
-				put_cmd640_reg(CNTRL, b); /* restore original setting */
-				port2 = "not responding";
-			}
-		}
-	}
-
-	/*
-	 * Initialize data for secondary cmd640 port, if enabled
-	 */
-	if (second_port_cmd640) {
-		cmd_hwif0->serialized = 1;
-		cmd_hwif1->serialized = 1;
-		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif0->mate = cmd_hwif1;
-		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->channel = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		cmd_hwif1->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
-		cmd_hwif0->serialized ? "" : "not ", port2);
-
-	/*
-	 * Establish initial timings/prefetch for all drives.
-	 * Do not unnecessarily disturb any prior BIOS setup of these.
-	 */
-	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
-		ide_drive_t *drive = cmd_drives[index];
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-	 		/*
-	 		 * Reset timing to the slowest speed and turn off prefetch.
-			 * This way, the drive identify code has a better chance.
-			 */
-			setup_counts    [index] = 4;	/* max possible */
-			active_counts   [index] = 16;	/* max possible */
-			recovery_counts [index] = 16;	/* max possible */
-			program_drive_counts (index);
-			set_prefetch_mode (index, 0);
-			printk("cmd640: drive%d timings/prefetch cleared\n", index);
-		} else {
-			/*
-			 * Record timings/prefetch without changing them.
-			 * This preserves any prior BIOS setup.
-			 */
-			retrieve_drive_counts (index);
-			check_prefetch (index);
-			printk("cmd640: drive%d timings/prefetch(%s) preserved",
-				index, drive->no_io_32bit ? "off" : "on");
-			display_clocks(index);
-		}
-#else
-		/*
-		 * Set the drive unmask flags to match the prefetch setting
-		 */
-		check_prefetch (index);
-		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
-			index, drive->no_io_32bit ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-	return 1;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd64x.c linux-2.4.21-rc3/drivers/ide/cmd64x.c
--- linux-2.4.20/drivers/ide/cmd64x.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1163 +0,0 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
- *
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Note, this driver is not used at all on other systems because
- *           there the "BIOS" has done all of the following already.
- *           Due to massive hardware bugs, UltraDMA is only supported
- *           on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998       David S. Miller (davem@redhat.com)
- * Copyright (C) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define CMD_DEBUG 0
-
-#if CMD_DEBUG
-#define cmdprintk(x...)	printk(##x)
-#else
-#define cmdprintk(x...)
-#endif
-
-/*
- * CMD64x specific registers definition.
- */
-
-#define CFR		0x50
-#define   CFR_INTR_CH0		0x02
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define   ARTTIM23_INTR_CH1	0x10
-#define ARTTIM2		0x57
-#define ARTTIM3		0x57
-#define DRWTIM23	0x58
-#define DRWTIM2		0x58
-#define BRST		0x59
-#define DRWTIM3		0x5b
-
-#define BMIDECR0	0x70
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
-#define UDIDETCR0	0x73
-#define DTPR0		0x74
-#define BMIDECR1	0x78
-#define BMIDECSR	0x79
-#define BMIDESR1	0x7A
-#define UDIDETCR1	0x7B
-#define DTPR1		0x7C
-
-#define DISPLAY_CMD64X_TIMINGS
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#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;
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
-	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 0, reg71 = 0;			/* extra */
-	u8 hi_byte = 0, lo_byte = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_CMD_649:
-			p += sprintf(p, "\n                                CMD649 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_648:
-			p += sprintf(p, "\n                                CMD648 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			p += sprintf(p, "\n                                CMD646 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_643:
-			p += sprintf(p, "\n                                CMD643 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                CMD64? Chipse.\n");
-			break;
-	}
-	(void) pci_read_config_byte(bmide_dev, CFR,       &reg50);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM3,   &reg5b);
-	(void) pci_read_config_byte(bmide_dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR1, &reg7b);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no ");
-	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
-		(reg72&0x20)?(  ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
-				((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
-				((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
-		(reg72&0x40)?(	((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
-				((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
-				((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):"X"):"?",
-		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x20)?(	((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
-				((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
-				((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x40)?(	((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
-				((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
-				((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):"X"):"?" );
-	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
-		"?", "?", "?", "?");
-	p += sprintf(p, "                %s                     %s\n",
-		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
-		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
-		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
-
-	SPLIT_BYTE(reg50, hi_byte, lo_byte);
-	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
-	SPLIT_BYTE(reg57, hi_byte, lo_byte);
-	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
-	SPLIT_BYTE(reg71, hi_byte, lo_byte);
-	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	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	/* 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:
- */
-#if 0
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
- */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
-{
-	unsigned long flags;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	byte temp_b;
-	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const byte recovery_counts[] =
-		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const byte arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const byte drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
-
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
-		active_count, recovery_count, drive->present);
-	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
-	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
-	}
-
-	/*
-	 * Convert values to internal chipset representation
-	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
-
-	cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count);
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	__save_flags (flags);
-	__cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
-		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
-		(byte) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
-	__restore_flags(flags);
-}
-
-/*
- * Attempts to set the interface PIO mode.
- * The preferred method of selecting PIO modes (e.g. mode 4) is 
- * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
- * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
- * Called with 255 at boot time.
- */
-static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
-	byte recovery_count2, cycle_count;
-	int setup_count, active_count, recovery_count;
-	int bus_speed = system_bus_clock();
-	/*byte b;*/
-	ide_pio_data_t  d;
-
-	switch (mode_wanted) {
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			/*set_prefetch_mode(index, mode_wanted);*/
-			cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	pio_mode = d.pio_mode;
-	cycle_time = d.cycle_time;
-
-	/*
-	 * I copied all this complicated stuff from cmd640.c and made a few minor changes.
-	 * For now I am just going to pray that it is correct.
-	 */
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd646 */
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
-
-	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n",
-		drive->name, pio_mode, mode_wanted, cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
-}
-
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
-{
-	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;
-	if (set_speed)
-		(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
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
-	u8 regU			= 0;
-	u8 regD			= 0;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return 1;
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	regD &= ~(unit ? 0x40 : 0x20);
-	regU &= ~(unit ? 0xCA : 0x35);
-	(void) pci_write_config_byte(dev, pciD, regD);
-	(void) pci_write_config_byte(dev, pciU, regU);
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	switch(speed) {
-		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
-		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
-		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
-		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
-		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
-		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
-		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-#else
-	int err			= 0;
-
-		switch(speed) {
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
-
-		default:
-			return 1;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	(void) pci_write_config_byte(dev, pciU, regU);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-
-	drive->current_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	regD |= (unit ? 0x40 : 0x20);
-	(void) pci_write_config_byte(dev, pciD, regD);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	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_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);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	byte udma_33		= ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= 0;
-	int rval;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_646:
-		case PCI_DEVICE_ID_CMD_643:
-		default:
-			break;
-	}
-
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
-		return ((int) ide_dma_off);
-	}
-
-	/* UltraDMA only supported on PCI646U and PCI646U2,
-	 * which correspond to revisions 0x03, 0x05 and 0x07 respectively.
-	 * Actually, although the CMD tech support people won't
-	 * tell me the details, the 0x03 revision cannot support
-	 * UDMA correctly without hardware modifications, and even
-	 * then it only works with Quantum disks due to some
-	 * hold time assumptions in the 646U part which are fixed
-	 * in the 646U2.
-	 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-	 */
-	if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-		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 {
-		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 (cmd64x_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((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_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;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev	= 0;
-	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:
-			can_ultra_66  = 1;
-		case PCI_DEVICE_ID_CMD_643:
-			can_ultra_33  = 1;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			can_ultra_33  = (class_rev >= 0x05) ? 1 : 0;
-			can_ultra_66  = 0;
-			can_ultra_100 = 0;
-			break;
-		default:
-			return hwif->dmaproc(ide_dma_off, drive);
-	}
-
-	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->media == ide_disk)) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (can_ultra_33)) {
-			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) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, class_rev, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, class_rev, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive, 1);
-	}
-	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;
-	byte dma_alt_stat	= 0;
-	byte mask		= (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			if (jack_slap) {
-				byte dma_intr	= 0;
-				byte dma_mask	= (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (HWIF(drive)->channel) ? ARTTIM2 : CFR;
-				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-				/*
-				 * DAMN BMIDE is not connected to PCI space!
-				 * Have to manually jack-slap that bitch!
-				 * To allow the PCI side to read incoming interrupts.
-				 */
-				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);	/* clear the INTR bit */
-			}
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
-#ifdef DEBUG
-			printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask);
-#endif
-			if (!(dma_alt_stat & mask)) {
-				return 0;
-			}
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-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;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-#ifdef __i386__
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_byte(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);
-	}
-#endif
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_643:
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", name, class_rev);
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:
-					printk("UltraDMA Capable");
-					break;
-				case 0x03:
-					printk("MultiWord DMA Force Limited");
-					break;
-				case 0x01:
-				default:
-					printk("MultiWord DMA Limited, IRQ workaround enabled");
-					break;
-				}
-			printk("\n");
-                        break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			break;
-		default:
-			break;
-	}
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-
-	/* Setup interrupts. */
-	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
-	mrdmode &= ~(0x30);
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
-
-	/* Use MEMORY READ LINE for reads.
-	 * NOTE: Although not mentioned in the PCI0646U specs,
-	 *       these bits are write only and won't be read
-	 *       back as set or not.  The PCI0646U2 specs clarify
-	 *       this point.
-	 */
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#ifdef CONFIG_PPC
-	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
-#endif /* CONFIG_PPC */
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd64x_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-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;
-
-	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
-	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;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#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->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc = &cmd64x_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			hwif->chipset = ide_cmd646;
-			if (class_rev == 0x01) {
-				hwif->dmaproc = &cmd646_1_dmaproc;
-			} else {
-				hwif->dmaproc = &cmd64x_dmaproc;
-			}
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc	= &cmd64x_tune_chipset;
-			break;
-		default:
-			break;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cs5530.c linux-2.4.21-rc3/drivers/ide/cs5530.c
--- linux-2.4.20/drivers/ide/cs5530.c	2001-01-03 00:58:45.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/cs5530.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,374 +0,0 @@
-/*
- * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
- *
- * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
- * Ditto of GNU General Public License.
- *
- * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- */
-
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_CS5530_TIMINGS
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cs5530_get_info(char *, char **, off_t, int);
-extern int (*cs5530_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 cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                Cyrix 5530 Chipset.\n");
-	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");
-
-	return p-buffer;
-}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-byte cs5530_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-	int error = 0;
-
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
-	error = ide_config_drive_speed(drive, mode);
-
-	return error;
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] =
-	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
-	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
- *
- * The ide_init_cs5530() routine guarantees that all drives
- * will have valid default PIO timings set up before we get here.
- */
-static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	unsigned int	format, basereg = CS5530_BASEREG(hwif);
-	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
-		format = (inl(basereg+4) >> 31) & 1;
-		outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
- * for both the chipset and drive.
- */
-static int cs5530_config_dma (ide_drive_t *drive)
-{
-	int			udma_ok = 1, mode = 0;
-	ide_hwif_t		*hwif = HWIF(drive);
-	int			unit = drive->select.b.unit;
-	ide_drive_t		*mate = &hwif->drives[unit^1];
-	struct hd_driveid	*id = drive->id;
-	unsigned int		basereg, reg, timings;
-
-
-	/*
-	 * Default to DMA-off in case we run into trouble here.
-	 */
-	(void)hwif->dmaproc(ide_dma_off_quietly, drive);	/* turn off DMA while we fiddle */
-	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
-
-	/*
-	 * The CS5530 specifies that two drives sharing a cable cannot
-	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
-	 * though different timings can still be chosen for each drive.
-	 * We could set the appropriate timing bits on the fly,
-	 * but that might be a bit confusing.  So, for now we statically
-	 * handle this requirement by looking at our mate drive to see
-	 * what it is capable of, before choosing a mode for our own drive.
-	 */
-	if (mate->present) {
-		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) {
-			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
-				udma_ok = 1;
-			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
-				udma_ok = 0;
-			else
-				udma_ok = 1;
-		}
-	}
-
-	/*
-	 * Now see what the current drive is capable of,
-	 * selecting UDMA only if the mate said it was ok.
-	 */
-	if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) {
-		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
-			if      (id->dma_ultra & 4)
-				mode = XFER_UDMA_2;
-			else if (id->dma_ultra & 2)
-				mode = XFER_UDMA_1;
-			else if (id->dma_ultra & 1)
-				mode = XFER_UDMA_0;
-		}
-		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
-			if      (id->dma_mword & 4)
-				mode = XFER_MW_DMA_2;
-			else if (id->dma_mword & 2)
-				mode = XFER_MW_DMA_1;
-			else if (id->dma_mword & 1)
-				mode = XFER_MW_DMA_0;
-		}
-	}
-
-	/*
-	 * Tell the drive to switch to the new mode; abort on failure.
-	 */
-	if (!mode || cs5530_set_xfer_mode(drive, mode))
-		return 1;	/* failure */
-
-	/*
-	 * Now tune the chipset to match the drive:
-	 */
-	switch (mode) {
-		case XFER_UDMA_0:	timings = 0x00921250; break;
-		case XFER_UDMA_1:	timings = 0x00911140; break;
-		case XFER_UDMA_2:	timings = 0x00911030; break;
-		case XFER_MW_DMA_0:	timings = 0x00077771; break;
-		case XFER_MW_DMA_1:	timings = 0x00012121; break;
-		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		default:
-			printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode);
-			return 1;	/* failure */
-	}
-	basereg = CS5530_BASEREG(hwif);
-	reg = inl(basereg+4);			/* get drive0 config register */
-	timings |= reg & 0x80000000;		/* preserve PIO format bit */
-	if (unit == 0) {			/* are we configuring drive0? */
-		outl(timings, basereg+4);	/* write drive0 config register */
-	} else {
-		if (timings & 0x00100000)
-			reg |=  0x00100000;	/* enable UDMA timings for both drives */
-		else
-			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
-		outl(reg,     basereg+4);	/* write drive0 config register */
-		outl(timings, basereg+12);	/* write drive1 config register */
-	}
-	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
-
-	/*
-	 * Finally, turn DMA on in software, and exit.
-	 */
-	return hwif->dmaproc(ide_dma_on, drive);	/* success */
-}
-
-/*
- * This is a CS5530-specific wrapper for the standard ide_dmaproc().
- * We need it for our custom "ide_dma_check" function.
- * All other requests are forwarded to the standard ide_dmaproc().
- */
-int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cs5530_config_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-	unsigned short pcicmd = 0;
-	unsigned long flags;
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cs5530_proc) {
-		cs5530_proc = 1;
-		bmide_dev = dev;
-		cs5530_display_info = &cs5530_get_info;
-	}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-	pci_for_each_dev (dev) {
-		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
-			switch (dev->device) {
-				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
-					master_0 = dev;
-					break;
-				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-					cs5530_0 = dev;
-					break;
-			}
-		}
-	}
-	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", name);
-		return 0;
-	}
-	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", name);
-		return 0;
-	}
-
-	save_flags(flags);
-	cli();	/* all CPUs (there should only be one CPU with this chipset) */
-
-	/*
-	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
-	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
-	 */
-	pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd);
-	pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
-
-	/*
-	 * Set PCI CacheLineSize to 16-bytes:
-	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
-	 */
-	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
-	/*
-	 * Disable trapping of UDMA register accesses (Win98 hack):
-	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
-	 */
-	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
-	/*
-	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
-	 * The other settings are what is necessary to get the register
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x40, 0x1e);
-
-	/* 
-	 * Set max PCI burst size (16-bytes seems to work best):
-	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
-	 *	all others: clear bit-1 at 0x41, and do:
-	 *	  128bytes: OR 0x00 at 0x41
-	 *	  256bytes: OR 0x04 at 0x41
-	 *	  512bytes: OR 0x08 at 0x41
-	 *	 1024bytes: OR 0x0c at 0x41
-	 */
-	pci_write_config_byte(master_0, 0x41, 0x14);
-
-	/*
-	 * These settings are necessary to get the chip
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x42, 0x00);
-	pci_write_config_byte(master_0, 0x43, 0xc1);
-
-	restore_flags(flags);
-
-	return 0;
-}
-
-/*
- * This gets invoked by the IDE driver once for each channel,
- * and performs channel-specific pre-initialization before drive probing.
- */
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
-{
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-	if (!hwif->dma_base) {
-		hwif->autodma = 0;
-	} else {
-		unsigned int basereg, d0_timings;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		hwif->dmaproc  = &cs5530_dmaproc;
-#else
-		hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-		hwif->tuneproc = &cs5530_tuneproc;
-		basereg = CS5530_BASEREG(hwif);
-		d0_timings = inl(basereg+0);
-		if (CS5530_BAD_PIO(d0_timings)) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
-			if (!hwif->drives[0].autotune)
-				hwif->drives[0].autotune = 1;	/* needs autotuning later */
-		}
-		if (CS5530_BAD_PIO(inl(basereg+8))) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
-			if (!hwif->drives[1].autotune)
-				hwif->drives[1].autotune = 1;	/* needs autotuning later */
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cy82c693.c linux-2.4.21-rc3/drivers/ide/cy82c693.c
--- linux-2.4.20/drivers/ide/cy82c693.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,449 +0,0 @@
-/*
- * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
- *
- *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>, Integrater
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- * Writting the driver was quite simple, since most of the job is
- * done by the generic pci-ide support. 
- * The hard part was finding the CY82C693's datasheet on Cypress's
- * web page :-(. But Altavista solved this problem :-).
- *
- *
- * Notes:
- * - I recently got a 16.8G IBM DTTA, so I was able to test it with
- *   a large and fast disk - the results look great, so I'd say the
- *   driver is working fine :-)
- *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
- * - this is my first linux driver, so there's probably a lot  of room 
- *   for optimizations and bug fixing, so feel free to do it.
- * - use idebus=xx parameter to set PCI bus speed - needed to calc
- *   timings for PIO modes (default will be 40)
- * - if using PIO mode it's a good idea to set the PIO mode and 
- *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
- * - I had some problems with my IBM DHEA with PIO modes < 2
- *   (lost interrupts) ?????
- * - first tests with DMA look okay, they seem to work, but there is a
- *   problem with sound - the BusMaster IDE TimeOut should fixed this
- *
- *
- * History:
- * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
- * ASK@1999-01-23: v0.33 made a few minor code clean ups
- *                       removed DMA clock speed setting by default
- *                       added boot message
- * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
- *                       added support to set DMA Controller Clock Speed
- * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive
- * ASK@1998-10-29: v0.3 added support to set DMA modes
- * ASK@1998-10-28: v0.2 added support to set PIO modes
- * ASK@1998-10-27: v0.1 first version - chipset detection
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
-/*
- *	The following are used to debug the driver.
- */
-#define	CY82C693_DEBUG_LOGS	0
-#define	CY82C693_DEBUG_INFO	0
-
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
-/*
- * note: the value for busmaster timeout is tricky and i got it by trial and error !
- *       using a to low value will cause DMA timeouts and drop IDE performance
- *       using a to high value will cause audio playback to scatter
- *       if you know a better value or how to calc it, please let me know 
- */
-#define BUSMASTER_TIMEOUT	0x50	/* twice the value written in cy82c693ub datasheet */
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG		0x04
-#define CY82_IDE_ADDRSETUP	0x48
-#define CY82_IDE_MASTER_IOR	0x4C	
-#define CY82_IDE_MASTER_IOW	0x4D	
-#define CY82_IDE_SLAVE_IOR	0x4E	
-#define CY82_IDE_SLAVE_IOW	0x4F
-#define CY82_IDE_MASTER_8BIT	0x50	
-#define CY82_IDE_SLAVE_8BIT	0x51	
-
-#define CY82_INDEX_PORT		0x22
-#define CY82_DATA_PORT		0x23
-
-#define CY82_INDEX_CTRLREG1	0x01
-#define CY82_INDEX_CHANNEL0	0x30
-#define CY82_INDEX_CHANNEL1	0x31
-#define CY82_INDEX_TIMEOUT	0x32
-
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO	4
-
-/* the min and max PCI bus speed in MHz - from datasheet */
-#define CY82C963_MIN_BUS_SPEED	25
-#define CY82C963_MAX_BUS_SPEED	33
-
-/* the struct for the PIO mode timings */
-typedef struct pio_clocks_s {
-        byte	address_time;		/* Address setup (clocks) */
-	byte	time_16r;		/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_16w;		/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_8;			/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
-} pio_clocks_t;
-
-/*
- * calc clocks using bus_speed
- * returns (rounded up) time in bus clocks for time in ns
- */
-static int calc_clk (int time, int bus_speed)
-{
-	int clocks;
-
-	clocks = (time*bus_speed+999)/1000 -1;
-
-	if (clocks < 0)
-		clocks = 0;
-
-	if (clocks > 0x0F)
-		clocks = 0x0F;
-
-	return clocks;
-}
-
-/*
- * compute the values for the clock registers for PIO
- * mode and pci_clk [MHz] speed
- *
- * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
- *       for mode 3 and 4 drives 8 and 16-bit timings are the same
- *
- */ 
-static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
-{
-	int clk1, clk2;
-	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
-
-	/* we don't check against CY82C693's min and max speed,
-	 * so you can play with the idebus=xx parameter
-	 */
-
-	if (pio > CY82C693_MAX_PIO)
-		pio = CY82C693_MAX_PIO;
-
-	/* let's calc the address setup time clocks */
-	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
-
-	/* let's calc the active and recovery time clocks */
-	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
-
-	/* calc recovery timing */
-	clk2 =	ide_pio_timings[pio].cycle_time -
-		ide_pio_timings[pio].active_time -
-		ide_pio_timings[pio].setup_time;
-
-	clk2 = calc_clk(clk2, bus_speed);
-
-	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
-
-	/* note: we use the same values for 16bit IOR and IOW
-         *	those are all the same, since I don't have other
-	 *	timings than those from ide_modes.h
-	 */
-
-	p_pclk->time_16r = (byte)clk1;
-	p_pclk->time_16w = (byte)clk1;
-
-	/* what are good values for 8bit ?? */
-	p_pclk->time_8 = (byte)clk1;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * set DMA mode a specific channel for CY82C693
- */
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
-{
-        byte index;
-	byte data;
-
-        if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-        index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
-
-#if CY82C693_DEBUG_LOGS
-       	/* for debug let's show the previous values */
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	data = IN_BYTE(CY82_DATA_PORT);
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
-	data = (byte)mode|(byte)(single<<2);
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
-#endif /* CY82C693_DEBUG_INFO */
-
-	/* 
-	 * note: below we set the value for Bus Master IDE TimeOut Register
-	 * I'm not absolutly sure what this does, but it solved my problem
-	 * with IDE DMA and sound, so I now can play sound and work with
-	 * my IDE driver at the same time :-)
-	 *
-	 * If you know the correct (best) value for this register please
-	 * let me know - ASK
-	 */
-
-	data = BUSMASTER_TIMEOUT;
-	OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO	
-	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	/*
-	 * if the function is dma on, set dma mode for drive everything
-	 * else is done by the defaul func
-	 */
-	if (func == ide_dma_on) {
-		struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-		printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-		if (id != NULL) {		
-                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
-                       if (id->field_valid & 2) {       /* regular DMA */
-			       int mmode, smode;
-
-			       mmode = id->dma_mword & (id->dma_mword >> 8);
-			       smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-		               if (mmode != 0)
-				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
-			       else if (smode != 0)
-				     cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
-			}
-		}
-	}
-        return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	pio_clocks_t pclk;
-	unsigned int addrCtrl;
-
-	/* select primary or secondary channel */
-	if (hwif->index > 0) {  /* drive is on the secondary channel */
-		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
-		if (!dev) {
-			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
-			return;
-		}
-	}
-
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the register values */
-	
-       	if (drive->select.b.unit == 0) {
-		/*
-		 * get master drive registers               	
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
-		addrCtrl &= 0x0F;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-	} else {
-		/*
-		 * set slave drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= 0xF0;
-		addrCtrl >>= 4;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-	}
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
-        /* first let's calc the pio modes */
-	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
-        compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
-
-	/* now let's write  the clocks registers */
-	if (drive->select.b.unit == 0) {
-		/*
-		 * set master drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-		
-		addrCtrl &= (~0xF);
-		addrCtrl |= (unsigned int)pclk.address_time;
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-		
-		addrCtrl &= 0xF;
-	} else {
-		/*
-		 * set slave drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= (~0xF0);
-		addrCtrl |= ((unsigned int)pclk.address_time<<4);
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
-
-		addrCtrl >>= 4;
-		addrCtrl &= 0xF;
-	}	
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-/*
- * FIXME! "pci_init_cy82c693" really should replace
- * the "init_cy82c693_chip", it is the correct location to tinker/setup
- * the device prior to INIT.
- */
-
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
-{
-#ifdef CY82C693_SETDMA_CLOCK
-        byte data;
-#endif /* CY82C693_SETDMA_CLOCK */ 
-
-	/* write info about this verion of the driver */
-	printk (KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-        
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        data = IN_BYTE(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-        /*
-	 * for some reason sometimes the DMA controller
-	 * speed is set to ATCLK/2 ???? - we fix this here
-	 * 
-	 * note: i don't know what causes this strange behaviour,
-	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed 
-	 * 
-	 *       if anybody knows what goes wrong with my machine, please
-	 *       let me know - ASK
-         */
-
-	data |= 0x03;
-
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-	return 0;
-}
-
-/*
- * the init function - called for each ide channel once
- */
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
-{
-	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &cy82c693_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/dtc2278.c linux-2.4.21-rc3/drivers/ide/dtc2278.c
--- linux-2.4.20/drivers/ide/dtc2278.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,134 +0,0 @@
-/*
- *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed.  If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
-	int i;
-
-	for(i = 0; i < 3; ++i) {
-		inb(0x3f6);
-		outb_p(b,0xb0);
-		inb(0x3f6);
-		outb_p(c,0xb4);
-		inb(0x3f6);
-		if(inb(0xb4) == c) {
-			outb_p(7,0xb0);
-			inb(0x3f6);
-			return;	/* success */
-		}
-	}
-}
-
-static void tune_dtc2278 (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	if (pio >= 3) {
-		save_flags(flags);	/* all CPUs */
-		cli();			/* all CPUs */
-		/*
-		 * This enables PIO mode4 (3?) on the first interface
-		 */
-		sub22(1,0xc3);
-		sub22(0,0xa0);
-		restore_flags(flags);	/* all CPUs */
-	} else {
-		/* we don't know how to set it back again.. */
-	}
-
-	/*
-	 * 32bit I/O has to be enabled for *both* drives at the same time.
-	 */
-	drive->io_32bit = 1;
-	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
-}
-
-void __init init_dtc2278 (void)
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/*
-	 * This enables the second interface
-	 */
-	outb_p(4,0xb0);
-	inb(0x3f6);
-	outb_p(0x20,0xb4);
-	inb(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
-	/*
-	 * This enables PIO mode4 (3?) on the first interface
-	 * and may solve start-up problems for some people.
-	 */
-	sub22(1,0xc3);
-	sub22(0,0xa0);
-#endif
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_hwifs[0].serialized = 1;
-	ide_hwifs[1].serialized = 1;
-	ide_hwifs[0].chipset = ide_dtc2278;
-	ide_hwifs[1].chipset = ide_dtc2278;
-	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	ide_hwifs[0].drives[0].no_unmask = 1;
-	ide_hwifs[0].drives[1].no_unmask = 1;
-	ide_hwifs[1].drives[0].no_unmask = 1;
-	ide_hwifs[1].drives[1].no_unmask = 1;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/falconide.c linux-2.4.21-rc3/drivers/ide/falconide.c
--- linux-2.4.20/drivers/ide/falconide.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/falconide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,68 +0,0 @@
-/*
- *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
- *
- *     Created 12 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-
-
-    /*
-     *  Base of the IDE interface
-     */
-
-#define ATA_HD_BASE	0xfff00000
-
-    /*
-     *  Offsets from the above base
-     */
-
-#define ATA_HD_DATA	0x00
-#define ATA_HD_ERROR	0x05		/* see err-bits */
-#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
-#define ATA_HD_SECTOR	0x0d		/* starting sector */
-#define ATA_HD_LCYL	0x11		/* starting cylinder */
-#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
-#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS	0x1d		/* see status-bits */
-#define ATA_HD_CONTROL	0x39
-
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
-    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
-    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
-    /*
-     *  Probe for a Falcon IDE interface
-     */
-
-void __init falconide_init(void)
-{
-    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
-	hw_regs_t hw;
-	int index;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
-			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
-
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/gayle.c linux-2.4.21-rc3/drivers/ide/gayle.c
--- linux-2.4.20/drivers/ide/gayle.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/gayle.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,181 +0,0 @@
-/*
- *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
- *
- *     Created 9 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
-#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define GAYLE_DATA	0x00
-#define GAYLE_ERROR	0x06		/* see err-bits */
-#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define GAYLE_SECTOR	0x0e		/* starting sector */
-#define GAYLE_LCYL	0x12		/* starting cylinder */
-#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
-#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS	0x1e		/* see status-bits */
-#define GAYLE_CONTROL	0x101a
-
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
-    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
-    /*
-     *  These are at different offsets from the base
-     */
-
-#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
-
-
-    /*
-     *  Offset of the secondary port for IDE doublers
-     *  Note that GAYLE_CONTROL is NOT available then!
-     */
-
-#define GAYLE_NEXT_PORT	0x1000
-
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS		1
-#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG	1
-#define GAYLE_IDEREG_SIZE	0x2000
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
-#define GAYLE_NUM_HWIFS		2
-#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
-					       GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
-#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
-int ide_doubler = 0;	/* support IDE doublers? */
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    return 1;
-}
-
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
-    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
-    return 1;
-}
-
-    /*
-     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-     */
-
-void __init gayle_init(void)
-{
-    int a4000, i;
-
-    if (!MACH_IS_AMIGA)
-	return;
-
-    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
-	return;
-
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-	ide_ioreg_t base, ctrlport, irqport;
-	ide_ack_intr_t *ack_intr;
-	hw_regs_t hw;
-	int index;
-	unsigned long phys_base, res_start, res_n;
-
-	if (a4000) {
-	    phys_base = GAYLE_BASE_4000;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
-	    ack_intr = gayle_ack_intr_a4000;
-	} else {
-	    phys_base = GAYLE_BASE_1200;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
-	    ack_intr = gayle_ack_intr_a1200;
-	}
-	phys_base += i*GAYLE_NEXT_PORT;
-
-	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-	res_n = GAYLE_IDEREG_SIZE;
-
-	if (!request_mem_region(res_start, res_n, "IDE"))
-	    continue;
-
-	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
-	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
-
-	ide_setup_ports(&hw, base, gayle_offsets,
-			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
-
-	index = ide_register_hw(&hw, NULL);
-	if (index != -1) {
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
-	} else
-	    release_mem_region(res_start, res_n);
-
-#if 1 /* TESTING */
-	if (i == 1) {
-	    volatile u_short *addr = (u_short *)base;
-	    u_short data;
-	    printk("+++ Probing for IDE doubler... ");
-	    *addr = 0xffff;
-	    data = *addr;
-	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
-	}
-#endif /* TESTING */
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hd.c linux-2.4.21-rc3/drivers/ide/hd.c
--- linux-2.4.20/drivers/ide/hd.c	2001-10-15 20:27:42.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/hd.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/ide/hd.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * This is the low-level hd interrupt support. It traverses the
- * request-list, using interrupts to jump between functions. As
- * all the functions are called within interrupts, we may not
- * sleep. Special care is recommended.
- * 
- *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *
- *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  in the early extended-partition checks and added DM partitions
- *
- *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  and general streamlining by Mark Lord.
- *
- *  Removed 99% of above. Use Mark's ide driver for those options.
- *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
- *
- *  Modified 1995 Russell King for ARM processor.
- *
- *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
- *  off in a hurry once you queue things up - Paul G. 02/2001
- */
-  
-/* Uncomment the following if you want verbose error reports. */
-/* #define VERBOSE_ERRORS */
-  
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/mc146818rtc.h> /* CMOS defines */
-#include <linux/init.h>
-#include <linux/blkpg.h>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR HD_MAJOR
-#include <linux/blk.h>
-
-#ifdef __arm__
-#undef  HD_IRQ
-#endif
-#include <asm/irq.h>
-#ifdef __arm__
-#define HD_IRQ IRQ_HARDDISK
-#endif
-
-static int revalidate_hddisk(kdev_t, int);
-
-#define	HD_DELAY	0
-
-#define MAX_ERRORS     16	/* Max read/write errors/sector */
-#define RESET_FREQ      8	/* Reset controller every 8th retry */
-#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
-#define MAX_HD		2
-
-#define STAT_OK		(READY_STAT|SEEK_STAT)
-#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
-
-static void recal_intr(void);
-static void bad_rw_intr(void);
-
-static char recalibrate[MAX_HD];
-static char special_op[MAX_HD];
-static int access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int reset;
-static int hd_error;
-
-#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
-
-/*
- *  This struct defines the HD's and their types.
- */
-struct hd_i_struct {
-	unsigned int head,sect,cyl,wpcom,lzone,ctl;
-};
-	
-#ifdef HD_TYPE
-static struct hd_i_struct hd_info[] = { HD_TYPE };
-static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
-#else
-static struct hd_i_struct hd_info[MAX_HD];
-static int NR_HD;
-#endif
-
-static struct hd_struct hd[MAX_HD<<6];
-static int hd_sizes[MAX_HD<<6];
-static int hd_blocksizes[MAX_HD<<6];
-static int hd_hardsectsizes[MAX_HD<<6];
-static int hd_maxsect[MAX_HD<<6];
-
-static struct timer_list device_timer;
-
-#define SET_TIMER 							\
-	do {								\
-		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
-	} while (0)
-
-#define CLEAR_TIMER del_timer(&device_timer);
-
-#undef SET_INTR
-
-#define SET_INTR(x) \
-if ((DEVICE_INTR = (x)) != NULL) \
-	SET_TIMER; \
-else \
-	CLEAR_TIMER;
-
-
-#if (HD_DELAY > 0)
-unsigned long last_req;
-
-unsigned long read_timer(void)
-{
-	unsigned long t, flags;
-	int i;
-
-	save_flags(flags);
-	cli();
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	restore_flags(flags);
-	return(t - i);
-}
-#endif
-
-void __init hd_setup(char *str, int *ints)
-{
-	int hdind = 0;
-
-	if (ints[0] != 3)
-		return;
-	if (hd_info[0].head != 0)
-		hdind=1;
-	hd_info[hdind].head = ints[2];
-	hd_info[hdind].sect = ints[3];
-	hd_info[hdind].cyl = ints[1];
-	hd_info[hdind].wpcom = 0;
-	hd_info[hdind].lzone = ints[1];
-	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
-	NR_HD = hdind+1;
-}
-
-static void dump_status (const char *msg, unsigned int stat)
-{
-	unsigned long flags;
-	char devc;
-
-	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
-	save_flags (flags);
-	sti();
-#ifdef VERBOSE_ERRORS
-	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
-	if (stat & BUSY_STAT)	printk("Busy ");
-	if (stat & READY_STAT)	printk("DriveReady ");
-	if (stat & WRERR_STAT)	printk("WriteFault ");
-	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("}\n");
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
-		if (hd_error & BBD_ERR)		printk("BadSector ");
-		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
-		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
-		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
-		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
-		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
-		printk("}");
-		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
-			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
-				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-			if (!QUEUE_EMPTY)
-				printk(", sector=%ld", CURRENT->sector);
-		}
-		printk("\n");
-	}
-#else
-	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
-	}
-#endif	/* verbose errors */
-	restore_flags (flags);
-}
-
-void check_status(void)
-{
-	int i = inb_p(HD_STATUS);
-
-	if (!OK_STATUS(i)) {
-		dump_status("check_status", i);
-		bad_rw_intr();
-	}
-}
-
-static int controller_busy(void)
-{
-	int retries = 100000;
-	unsigned char status;
-
-	do {
-		status = inb_p(HD_STATUS);
-	} while ((status & BUSY_STAT) && --retries);
-	return status;
-}
-
-static int status_ok(void)
-{
-	unsigned char status = inb_p(HD_STATUS);
-
-	if (status & BUSY_STAT)
-		return 1;	/* Ancient, but does it make sense??? */
-	if (status & WRERR_STAT)
-		return 0;
-	if (!(status & READY_STAT))
-		return 0;
-	if (!(status & SEEK_STAT))
-		return 0;
-	return 1;
-}
-
-static int controller_ready(unsigned int drive, unsigned int head)
-{
-	int retry = 100;
-
-	do {
-		if (controller_busy() & BUSY_STAT)
-			return 0;
-		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
-		if (status_ok())
-			return 1;
-	} while (--retry);
-	return 0;
-}
-
-static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
-		unsigned int head,unsigned int cyl,unsigned int cmd,
-		void (*intr_addr)(void))
-{
-	unsigned short port;
-
-#if (HD_DELAY > 0)
-	while (read_timer() - last_req < HD_DELAY)
-		/* nothing */;
-#endif
-	if (reset)
-		return;
-	if (!controller_ready(drive, head)) {
-		reset = 1;
-		return;
-	}
-	SET_INTR(intr_addr);
-	outb_p(hd_info[drive].ctl,HD_CMD);
-	port=HD_DATA;
-	outb_p(hd_info[drive].wpcom>>2,++port);
-	outb_p(nsect,++port);
-	outb_p(sect,++port);
-	outb_p(cyl,++port);
-	outb_p(cyl>>8,++port);
-	outb_p(0xA0|(drive<<4)|head,++port);
-	outb_p(cmd,++port);
-}
-
-static void hd_request (void);
-
-static int drive_busy(void)
-{
-	unsigned int i;
-	unsigned char c;
-
-	for (i = 0; i < 500000 ; i++) {
-		c = inb_p(HD_STATUS);
-		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
-			return 0;
-	}
-	dump_status("reset timed out", c);
-	return 1;
-}
-
-static void reset_controller(void)
-{
-	int	i;
-
-	outb_p(4,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	if (drive_busy())
-		printk("hd: controller still busy\n");
-	else if ((hd_error = inb(HD_ERROR)) != 1)
-		printk("hd: controller reset failed: %02x\n",hd_error);
-}
-
-static void reset_hd(void)
-{
-	static int i;
-
-repeat:
-	if (reset) {
-		reset = 0;
-		i = -1;
-		reset_controller();
-	} else {
-		check_status();
-		if (reset)
-			goto repeat;
-	}
-	if (++i < NR_HD) {
-		special_op[i] = recalibrate[i] = 1;
-		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
-			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
-		if (reset)
-			goto repeat;
-	} else
-		hd_request();
-}
-
-/*
- * Ok, don't know what to do with the unexpected interrupts: on some machines
- * doing a reset and a retry seems to result in an eternal loop. Right now I
- * ignore it, and just set the timeout.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- */
-void unexpected_hd_interrupt(void)
-{
-	unsigned int stat = inb_p(HD_STATUS);
-
-	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
-		dump_status ("unexpected interrupt", stat);
-		SET_TIMER;
-	}
-}
-
-/*
- * bad_rw_intr() now tries to be a bit smarter and does things
- * according to the error returned by the controller.
- * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
- */
-static void bad_rw_intr(void)
-{
-	int dev;
-
-	if (QUEUE_EMPTY)
-		return;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-		end_request(0);
-		special_op[dev] = recalibrate[dev] = 1;
-	} else if (CURRENT->errors % RESET_FREQ == 0)
-		reset = 1;
-	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
-		special_op[dev] = recalibrate[dev] = 1;
-	/* Otherwise just retry */
-}
-
-static inline int wait_DRQ(void)
-{
-	int retries = 100000, stat;
-
-	while (--retries > 0)
-		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
-			return 0;
-	dump_status("wait_DRQ", stat);
-	return -1;
-}
-
-static void read_intr(void)
-{
-	int i, retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if (i & DRQ_STAT)
-			goto ok_to_read;
-	} while (--retries > 0);
-	dump_status("read_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_read:
-	insw(HD_DATA,CURRENT->buffer,256);
-	CURRENT->sector++;
-	CURRENT->buffer += 512;
-	CURRENT->errors = 0;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-#ifdef DEBUG
-	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
-		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
-		(unsigned long) CURRENT->buffer+512));
-#endif
-	if (CURRENT->current_nr_sectors <= 0)
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&read_intr);
-		return;
-	}
-	(void) inb_p(HD_STATUS);
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	if (!QUEUE_EMPTY)
-		hd_request();
-	return;
-}
-
-static void write_intr(void)
-{
-	int i;
-	int retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
-			goto ok_to_write;
-	} while (--retries > 0);
-	dump_status("write_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_write:
-	CURRENT->sector++;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-	CURRENT->buffer += 512;
-	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&write_intr);
-		outsw(HD_DATA,CURRENT->buffer,256);
-		sti();
-	} else {
-#if (HD_DELAY > 0)
-		last_req = read_timer();
-#endif
-		hd_request();
-	}
-	return;
-}
-
-static void recal_intr(void)
-{
-	check_status();
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	hd_request();
-}
-
-/*
- * This is another of the error-routines I don't know what to do with. The
- * best idea seems to just set reset, and start all over again.
- */
-static void hd_times_out(unsigned long dummy)
-{
-	unsigned int dev;
-
-	DEVICE_INTR = NULL;
-	if (QUEUE_EMPTY)
-		return;
-	disable_irq(HD_IRQ);
-	sti();
-	reset = 1;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	printk("hd%c: timeout\n", dev+'a');
-	if (++CURRENT->errors >= MAX_ERRORS) {
-#ifdef DEBUG
-		printk("hd%c: too many errors\n", dev+'a');
-#endif
-		end_request(0);
-	}
-	cli();
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-int do_special_op (unsigned int dev)
-{
-	if (recalibrate[dev]) {
-		recalibrate[dev] = 0;
-		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
-		return reset;
-	}
-	if (hd_info[dev].head > 16) {
-		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
-		end_request(0);
-	}
-	special_op[dev] = 0;
-	return 1;
-}
-
-/*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is disabled before entering hd_request(),
- * and (b) the timeout-interrupt is disabled before the sti().
- *
- * Interrupts are still masked (by default) whenever we are exchanging
- * data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O. The IDE driver has support to unmask
- * interrupts for non-broken hardware, so use that driver if required.
- */
-static void hd_request(void)
-{
-	unsigned int dev, block, nsect, sec, track, head, cyl;
-
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
-	if (DEVICE_INTR)
-		return;
-repeat:
-	del_timer(&device_timer);
-	sti();
-	INIT_REQUEST;
-	if (reset) {
-		cli();
-		reset_hd();
-		return;
-	}
-	dev = MINOR(CURRENT->rq_dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
-	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
-#ifdef DEBUG
-		if (dev >= (NR_HD<<6))
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
-#endif
-		end_request(0);
-		goto repeat;
-	}
-	block += hd[dev].start_sect;
-	dev >>= 6;
-	if (special_op[dev]) {
-		if (do_special_op(dev))
-			goto repeat;
-		return;
-	}
-	sec   = block % hd_info[dev].sect + 1;
-	track = block / hd_info[dev].sect;
-	head  = track % hd_info[dev].head;
-	cyl   = track / hd_info[dev].head;
-#ifdef DEBUG
-	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
-		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
-		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
-#endif
-	if (CURRENT->cmd == READ) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}
-	if (CURRENT->cmd == WRITE) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
-		if (reset)
-			goto repeat;
-		if (wait_DRQ()) {
-			bad_rw_intr();
-			goto repeat;
-		}
-		outsw(HD_DATA,CURRENT->buffer,256);
-		return;
-	}
-	panic("unknown hd-command");
-}
-
-static void do_hd_request (request_queue_t * q)
-{
-	disable_irq(HD_IRQ);
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-static int hd_ioctl(struct inode * inode, struct file * file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct hd_geometry *loc = (struct hd_geometry *) arg;
-	int dev;
-
-	if ((!inode) || !(inode->i_rdev))
-		return -EINVAL;
-	dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= NR_HD)
-		return -EINVAL;
-	switch (cmd) {
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g; 
-			if (!loc)  return -EINVAL;
-			g.heads = hd_info[dev].head;
-			g.sectors = hd_info[dev].sect;
-			g.cylinders = hd_info[dev].cyl;
-			g.start = hd[MINOR(inode->i_rdev)].start_sect;
-			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
-		}
-
-         	case BLKGETSIZE:   /* Return device size */
-			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
-					(unsigned long *) arg);
-         	case BLKGETSIZE64:
-			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
-					(u64 *) arg);
-
-		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return revalidate_hddisk(inode->i_rdev, 1);
-
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKFLSBUF:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target;
-	target =  DEVICE_NR(inode->i_rdev);
-
-	if (target >= NR_HD)
-		return -ENODEV;
-	while (busy[target])
-		sleep_on(&busy_wait);
-	access_count[target]++;
-	return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int hd_release(struct inode * inode, struct file * file)
-{
-        int target =  DEVICE_NR(inode->i_rdev);
-	access_count[target]--;
-	return 0;
-}
-
-extern struct block_device_operations hd_fops;
-
-static struct gendisk hd_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"hd",
-	minor_shift:	6,
-	max_p:		1 << 6,
-	part:		hd,
-	sizes:		hd_sizes,
-	fops:		&hd_fops,
-};
-	
-static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	void (*handler)(void) = DEVICE_INTR;
-
-	DEVICE_INTR = NULL;
-	del_timer(&device_timer);
-	if (!handler)
-		handler = unexpected_hd_interrupt;
-	handler();
-	sti();
-}
-
-static struct block_device_operations hd_fops = {
-	open:		hd_open,
-	release:	hd_release,
-	ioctl:		hd_ioctl,
-};
-
-/*
- * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
- * means we run the IRQ-handler with interrupts disabled:  this is bad for
- * interrupt latency, but anything else has led to problems on some
- * machines.
- *
- * We enable interrupts in some of the routines after making sure it's
- * safe.
- */
-static void __init hd_geninit(void)
-{
-	int drive;
-
-	for(drive=0; drive < (MAX_HD << 6); drive++) {
-		hd_blocksizes[drive] = 1024;
-		hd_hardsectsizes[drive] = 512;
-		hd_maxsect[drive]=255;
-	}
-	blksize_size[MAJOR_NR] = hd_blocksizes;
-	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
-	max_sectors[MAJOR_NR] = hd_maxsect;
-
-#ifdef __i386__
-	if (!NR_HD) {
-		extern struct drive_info drive_info;
-		unsigned char *BIOS = (unsigned char *) &drive_info;
-		unsigned long flags;
-		int cmos_disks;
-
-		for (drive=0 ; drive<2 ; drive++) {
-			hd_info[drive].cyl = *(unsigned short *) BIOS;
-			hd_info[drive].head = *(2+BIOS);
-			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
-			hd_info[drive].ctl = *(8+BIOS);
-			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
-			hd_info[drive].sect = *(14+BIOS);
-#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
-			if (hd_info[drive].cyl && NR_HD == drive)
-				NR_HD++;
-#endif
-			BIOS += 16;
-		}
-
-	/*
-		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
-		BIOS table, but not register compatible, and therefore
-		not present in CMOS.
-
-		Furthermore, we will assume that our ST-506 drives
-		<if any> are the primary drives in the system, and 
-		the ones reflected as drive 1 or 2.
-
-		The first drive is stored in the high nibble of CMOS
-		byte 0x12, the second in the low nibble.  This will be
-		either a 4 bit drive type or 0xf indicating use byte 0x19 
-		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
-		Needless to say, a non-zero value means we have 
-		an AT controller hard disk for that drive.
-
-		Currently the rtc_lock is a bit academic since this
-		driver is non-modular, but someday... ?         Paul G.
-	*/
-
-		spin_lock_irqsave(&rtc_lock, flags);
-		cmos_disks = CMOS_READ(0x12);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		if (cmos_disks & 0xf0) {
-			if (cmos_disks & 0x0f)
-				NR_HD = 2;
-			else
-				NR_HD = 1;
-		}
-	}
-#endif /* __i386__ */
-#ifdef __arm__
-	if (!NR_HD) {
-		/* We don't know anything about the drive.  This means
-		 * that you *MUST* specify the drive parameters to the
-		 * kernel yourself.
-		 */
-		printk("hd: no drives specified - use hd=cyl,head,sectors"
-			" on kernel command line\n");
-	}
-#endif
-
-	for (drive=0 ; drive < NR_HD ; drive++) {
-		hd[drive<<6].nr_sects = hd_info[drive].head *
-			hd_info[drive].sect * hd_info[drive].cyl;
-		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
-			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
-			hd_info[drive].head, hd_info[drive].sect);
-	}
-	if (!NR_HD)
-		return;
-
-	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
-		printk("hd: unable to get IRQ%d for the hard disk driver\n",
-			HD_IRQ);
-		NR_HD = 0;
-		return;
-	}
-	request_region(HD_DATA, 8, "hd");
-	request_region(HD_CMD, 1, "hd(cmd)");
-
-	hd_gendisk.nr_real = NR_HD;
-
-	for(drive=0; drive < NR_HD; drive++)
-		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
-			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
-			hd_info[drive].cyl);
-}
-
-int __init hd_init(void)
-{
-	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
-		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
-		return -1;
-	}
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
-	add_gendisk(&hd_gendisk);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
-	return 0;
-}
-
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
-#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
-/* We assume that the BIOS parameters do not change, so the disk capacity
-   will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-static int revalidate_hddisk(kdev_t dev, int maxusage)
-{
-	int target;
-	struct gendisk * gdev;
-	int max_p;
-	int start;
-	int i;
-	long flags;
-
-	target = DEVICE_NR(dev);
-	gdev = &GENDISK_STRUCT;
-
-	save_flags(flags);
-	cli();
-	if (DEVICE_BUSY || USAGE > maxusage) {
-		restore_flags(flags);
-		return -EBUSY;
-	}
-	DEVICE_BUSY = 1;
-	restore_flags(flags);
-
-	max_p = gdev->max_p;
-	start = target << gdev->minor_shift;
-
-	for (i=max_p - 1; i >=0 ; i--) {
-		int minor = start + i;
-		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
-		gdev->part[minor].start_sect = 0;
-		gdev->part[minor].nr_sects = 0;
-	}
-
-#ifdef MAYBE_REINIT
-	MAYBE_REINIT;
-#endif
-
-	grok_partitions(gdev, target, 1<<6, CAPACITY);
-
-	DEVICE_BUSY = 0;
-	wake_up(&busy_wait);
-	return 0;
-}
-
-static int parse_hd_setup (char *line) {
-	int ints[6];
-
-	(void) get_options(line, ARRAY_SIZE(ints), ints);
-	hd_setup(NULL, ints);
-
-	return 1;
-}
-__setup("hd=", parse_hd_setup);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt34x.c linux-2.4.21-rc3/drivers/ide/hpt34x.c
--- linux-2.4.20/drivers/ide/hpt34x.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,437 +0,0 @@
-/*
- * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
- *
- * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * ide-pci.c reference
- *
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
-
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO		0
-
-#undef DISPLAY_HPT34X_TIMINGS
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int hpt34x_get_info(char *, char **, off_t, int);
-extern int (*hpt34x_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 hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                HPT34X Chipset.\n");
-	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");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte hpt34x_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int			err;
-	byte			hi_speed, lo_speed;
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-	if (hi_speed & 7) {
-		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-	} else {
-		lo_speed <<= 5;
-		lo_speed >>= 5;
-	}
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = ((hi_speed << drive->dn) | reg2);
-	err = ide_config_drive_speed(drive, speed);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-	drive->current_speed = speed;
-	return(err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	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;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 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 {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-		}
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	hpt34x_clear_chipset(drive);
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	hpt34x_clear_chipset(drive);
-
-	if ((id->dma_ultra & 0x0010) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0004) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && ultra) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && ultra) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-        } else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt34x_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x0007) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	if (dma_func == ide_dma_on)
-		dma_func = ide_dma_off;
-#endif /* CONFIG_HPT34X_AUTODMA */
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT343 UDMA bios-less chipset
- * and HPT345 UDMA bios chipset (stamped HPT363)
- * by HighPoint|Triones Technologies, Inc.
- */
-
-int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	unsigned int count, reading = 0;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			reading |= 0x01;
-			outb(reading, dma_base);		/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define	HPT34X_PCI_INIT_REG		0x80
-
-unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
-{
-	int i = 0;
-	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
-	unsigned short cmd;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	if (cmd & PCI_COMMAND_MEMORY) {
-		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start);
-		}
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-	} else {
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
-
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	dev->resource[0].start = (hpt34xIoBase + 0x20);
-	dev->resource[1].start = (hpt34xIoBase + 0x34);
-	dev->resource[2].start = (hpt34xIoBase + 0x28);
-	dev->resource[3].start = (hpt34xIoBase + 0x3c);
-	for(i=0; i<4; i++)
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-	/*
-	 * Since 20-23 can be assigned and are R/W, we correct them.
-	 */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	__restore_flags(flags);	/* local CPU only */
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt34x_proc) {
-		hpt34x_proc = 1;
-		bmide_dev = dev;
-		hpt34x_display_info = &hpt34x_get_info;
-	}
-#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
-
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		if (!noautodma)
-			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		else
-			hwif->autodma = 0;
-
-		hwif->dmaproc = &hpt34x_dmaproc;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt366.c linux-2.4.21-rc3/drivers/ide/hpt366.c
--- linux-2.4.20/drivers/ide/hpt366.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/hpt366.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1233 +0,0 @@
-/*
- * 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.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- * 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>
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#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>
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
-const char *quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP LM20.5",
-        NULL
-};
-
-const char *bad_ata100_5[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_4[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_3[] = {
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata33[] = {
-	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
-	"Maxtor 90510D4",
-	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
-	NULL
-};
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	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	},
-	{	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	},
-	{	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	},
-	{	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,	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 int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	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 long 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) */
-
-static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x02) ? 1 : 0);
-}
-
-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x01) ? 1 : 0);
-}
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 1;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-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 chipset_table->chipset_settings;
-		}
-	return chipset_table->chipset_settings;
-}
-
-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;
-			/*
-			 * since the channel is always 0 it does not matter.
-			 */
-
-	unsigned int reg1	= 0;
-	unsigned int reg2	= 0;
-	byte drive_fast		= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction. 
-	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
-			break;
-		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
-			break;
-		default:
-		case 7:
-			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)
-	 */
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
-}
-
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	unsigned int list_conf	= 0;
-	unsigned int drive_conf = 0;
-	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0x40 + (drive->dn * 4);
-	byte new_fast, drive_fast		= 0;
-	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	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);
-
-	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);
-	
-	if (speed < XFER_MW_DMA_0) {
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	}
-
-	pci_write_config_dword(dev, drive_pci, list_conf);
-}
-
-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed);
-        } else {
-                hpt366_tune_chipset(drive, speed);
-        }
-	drive->current_speed = speed;
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	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;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 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 {
-		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;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	int  rval;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0020) &&
-	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
-	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
-	    (ultra66)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) &&
-		   (!check_in_drive_lists(drive, bad_ata66_4)) &&
-		   (HPT366_ALLOW_ATA66_4) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) &&
-		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
-		   (HPT366_ALLOW_ATA66_3) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
-		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 {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-int hpt3xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, quirk_drives));
-}
-
-void hpt3xx_intrproc (ide_drive_t *drive)
-{
-	if (drive->quirk_list) {
-		/* drives in the quirk_list may not like intr setups/cleanups */
-	} else {
-		OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-	}
-}
-
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
-{
-	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-			byte reg5a = 0;
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
-		} else {
-			if (mask) {
-				disable_irq(HWIF(drive)->irq);
-			} else {
-				enable_irq(HWIF(drive)->irq);
-			}
-		}
-	} else {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
-	}
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if (id->dma_mword & 0x0007) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT366 UDMA bios chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-	unsigned long dma_base = HWIF(drive)->dma_base;
-
-	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_lostirq:
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
-			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-				drive->name,
-				ide_dmafunc_verbose(func),
-				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:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-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;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#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
-}
-
-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;
-}
-
-/* 
- * 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;
-
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		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 (test != (L1_CACHE_BYTES / 4))
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-	if (test != 0x78)
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-
-	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-	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;
-		hpt366_display_info = &hpt366_get_info;
-	}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
-{
-	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 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-	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 (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;
-		} else {
-			hwif->dmaproc = &hpt366_dmaproc;
-		}
-		if (!noautodma)
-			hwif->autodma = 1;
-		else
-			hwif->autodma = 0;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = inb(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
-
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) outb(dma_new, dmabase+2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.c linux-2.4.21-rc3/drivers/ide/hptraid.c
--- linux-2.4.20/drivers/ide/hptraid.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/hptraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,436 +0,0 @@
-/*
-   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-
-   Based on work
-   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
-	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
-   Based on work done by Søren Schmidt for FreeBSD
-
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int hptraid_open(struct inode * inode, struct file * filp);
-static int hptraid_release(struct inode * inode, struct file * filp);
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-
-struct hptdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-};
-
-struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct hptdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];	
-};
-
-static struct raid_device_operations hptraid_ops = {
-	open:                   hptraid_open,
-	release:                hptraid_release,
-	ioctl:			hptraid_ioctl,
-	make_request:		hptraid_make_request
-};
-
-static struct hptraid raid[16];
-
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned char val;
-	unsigned long sectors;
-	
-	if (!inode || !inode->i_rdev) 	
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-         	case BLKGETSIZE:   /* Return device size */
-			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl;
-			
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val=63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			unsigned int bios_cyl;
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val = 63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-			
-		default:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-	};
-
-	return 0;
-}
-
-
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;
-	}
-			
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-	
-	/* All but the first disk have a 10 sector offset */
-	if (i>0)
-		rsect+=10;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	 
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-
-#include "hptraid.h"
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	
-	if (blksize_size[major]==NULL)	 /* device doesn't exist */
-		return -EINVAL;
-	
-
-	/* Superblock is at 4096+412 bytes */
-	set_blocksize (dev, 4096);
-	bh = bread (dev, 1, 4096);
-
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "hptraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned long maxsectors (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity);
-
-	return lba;
-}
-
-static void __init probedisk(int major, int minor,int device)
-{
-	int i;
-        struct highpoint_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-	
-	if (maxsectors(major,minor)==0)
-		return;
-	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct highpoint_raid_conf*)&block[512];
-                
-        if (prom->magic!=  0x5a7816f0)
-        	return;
-        if (prom->type) {
-        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
-        }
-
-	i = prom->disk_number;
-	if (i<0)
-		return;
-	if (i>8) 
-		return;
-
-	bdev = bdget(MKDEV(major,minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = bdev;
-        	/* This is supposed to prevent others from stealing our underlying disks */
-		/* now blank the /proc/partitions table for the wrong partition table,
-		   so that scripts don't accidentally mount it and crash the kernel */
-		 /* XXX: the 0 is an utter hack  --hch */
-		gd=get_gendisk(MKDEV(major, 0));
-		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
-		}
-        }
-	raid[device].disk[i].device = MKDEV(major,minor);
-	raid[device].disk[i].sectors = maxsectors(major,minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs;
-			
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-		
-		smallest = smallest * count;		
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-		
-	}
-}
-
-
-static __init int hptraid_init_one(int device)
-{
-	int i,count;
-
-	probedisk(IDE0_MAJOR,  0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR,  0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR,  0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR,  0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-	probedisk(IDE4_MAJOR,  0, device);
-	probedisk(IDE4_MAJOR, 64, device);
-	probedisk(IDE5_MAJOR,  0, device);
-	probedisk(IDE5_MAJOR, 64, device);
-
-	fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);
-
-	count=0;
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
-		
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-				i,raid[device].disk[i].sectors/2048);
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
-		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
-	}
-	
-}
-
-static __init int hptraid_init(void)
-{
-	int retval,device;
-	
-	device=ataraid_get_device(&hptraid_ops);
-	if (device<0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
-}
-
-static void __exit hptraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++)  {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}       
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int hptraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int hptraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(hptraid_init);
-module_exit(hptraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.h linux-2.4.21-rc3/drivers/ide/hptraid.h
--- linux-2.4.20/drivers/ide/hptraid.h	2001-10-11 16:43:29.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/hptraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-                            
-struct highpoint_raid_conf
-{
-       int8_t  filler1[32];
-       u_int32_t       magic;
-#define HPT_MAGIC_OK   0x5a7816f0
-#define HPT_MAGIC_BAD  0x5a7816fd  
-
-       u_int32_t       magic_0;
-       u_int32_t       magic_1;
-       u_int32_t       order;  
-#define HPT_O_MIRROR   0x01  
-#define HPT_O_STRIPE   0x02
-#define HPT_O_OK       0x04
-
-       u_int8_t        raid_disks;
-       u_int8_t        raid0_shift; 
-       u_int8_t        type;
-#define HPT_T_RAID_0   0x00 
-#define HPT_T_RAID_1   0x01
-#define HPT_T_RAID_01_RAID_0   0x02
-#define HPT_T_SPAN             0x03
-#define HPT_T_RAID_3           0x04   
-#define HPT_T_RAID_5           0x05
-#define HPT_T_SINGLEDISK       0x06
-#define HPT_T_RAID_01_RAID_1   0x07
-
-       u_int8_t        disk_number;
-       u_int32_t       total_secs; 
-       u_int32_t       disk_mode;  
-       u_int32_t       boot_mode;
-       u_int8_t        boot_disk; 
-       u_int8_t        boot_protect;
-       u_int8_t        error_log_entries;
-       u_int8_t        error_log_index;  
-       struct
-       {
-               u_int32_t       timestamp;
-               u_int8_t        reason;   
-#define HPT_R_REMOVED          0xfe      
-#define HPT_R_BROKEN           0xff      
-
-               u_int8_t        disk;
-               u_int8_t        status;
-               u_int8_t        sectors;
-               u_int32_t       lba;
-       } errorlog[32];
-       u_int8_t        filler[60];
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ht6560b.c linux-2.4.21-rc3/drivers/ide/ht6560b.c
--- linux-2.4.20/drivers/ide/ht6560b.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,343 +0,0 @@
-/*
- *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
- *
- *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
- *
- *  Version 0.01        Initial version hacked out of ide.c
- *
- *  Version 0.02        Added support for PIO modes, auto-tune
- *
- *  Version 0.03        Some cleanups
- *
- *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
- *
- *  Version 0.06        Prefetch mode now defaults no OFF. To set
- *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
- *                      Unmask irq is disabled when prefetch mode
- *                      is enabled.
- *
- *  Version 0.07        Trying to fix CD-ROM detection problem.
- *                      "Prefetch" mode bit OFF for ide disks and
- *                      ON for anything else.
- *
- *
- *  HT-6560B EIDE-controller support
- *  To activate controller support use kernel parameter "ide0=ht6560b".
- *  Use hdparm utility to enable PIO mode support.
- *
- *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
- *             Jan Evert van Grootheest   <janevert@iae.nl>
- *
- *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
- */
-
-#define HT6560B_VERSION "v0.07"
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* #define DEBUG */  /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit2 (0x04): "1" enables FIFO function
- *    bit5 (0x20): "1" enables prefetched data read function  (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit1 (0x02): "1" enables prefetched data read function
- *    bit2 (0x04): "0" enables multi-master system	      (?)
- *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
- */
-#define HT_CONFIG_PORT	  0x3e6
-#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF	  0x01
-#define HT_PREFETCH_MODE  0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use IDE_SELECT_REG to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives.   [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
- * of the value is the Active Time  (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- *	High nibble:  Recovery Cycle Time  (rt)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- *	Low nibble:   Active Cycle Time	   (at)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_selectproc (ide_drive_t *drive)
-{
-	unsigned long flags;
-	static byte current_select = 0;
-	static byte current_timing = 0;
-	byte select, timing;
-	
-	__save_flags (flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	
-	select = HT_CONFIG(drive);
-	timing = HT_TIMING(drive);
-	
-	if (select != current_select || timing != current_timing) {
-		current_select = select;
-		current_timing = timing;
-		if (drive->media != ide_disk || !drive->present)
-			select |= HT_PREFETCH_MODE;
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		outb(select, HT_CONFIG_PORT);
-		/*
-		 * Set timing for this drive:
-		 */
-		outb(timing, IDE_SELECT_REG);
-		(void) inb(IDE_STATUS_REG);
-#ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
-#endif
-	}
-	__restore_flags (flags);	/* local CPU only */
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-	byte orig_value;
-	int i;
-	
-	/* Autodetect ht6560b */
-	if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
-		return 0;
-	
-	for (i=3;i>0;i--) {
-		outb(0x00, HT_CONFIG_PORT);
-		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
-			outb(orig_value, HT_CONFIG_PORT);
-			return 0;
-		}
-	}
-	outb(0x00, HT_CONFIG_PORT);
-	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
-		outb(orig_value, HT_CONFIG_PORT);
-		return 0;
-	}
-	/*
-	 * Ht6560b autodetected
-	 */
-	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
-	(void) inb(0x1f7);               /* IDE_STATUS_REG */
-	
-	printk("\nht6560b " HT6560B_VERSION
-	       ": chipset detected and initialized"
-#ifdef DEBUG
-	       " with debug enabled"
-#endif
-		);
-	return 1;
-}
-
-static byte ht_pio2timings(ide_drive_t *drive, byte pio)
-{
-	int active_time, recovery_time;
-	int active_cycles, recovery_cycles;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-	
-        if (pio) {
-		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-		
-		/*
-		 *  Just like opti621.c we try to calculate the
-		 *  actual cycle time for recovery and activity
-		 *  according system bus speed.
-		 */
-		active_time = ide_pio_timings[pio].active_time;
-		recovery_time = d.cycle_time 
-			- active_time
-			- ide_pio_timings[pio].setup_time;
-		/*
-		 *  Cycle times should be Vesa bus cycles
-		 */
-		active_cycles   = (active_time   * bus_speed + 999) / 1000;
-		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
-		/*
-		 *  Upper and lower limits
-		 */
-		if (active_cycles   < 2)  active_cycles   = 2;
-		if (recovery_cycles < 2)  recovery_cycles = 2;
-		if (active_cycles   > 15) active_cycles   = 15;
-		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-		
-		return (byte)((recovery_cycles << 4) | active_cycles);
-	} else {
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-		
-		return HT_TIMING_DEFAULT;    /* default setting */
-	}
-}
-
-/*
- *  Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, byte state)
-{
-	unsigned long flags;
-	int t = HT_PREFETCH_MODE << 8;
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	/*
-	 *  Prefetch mode and unmask irq seems to conflict
-	 */
-	if (state) {
-		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-	} else {
-		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->no_unmask = 0;
-	}
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void tune_ht6560b (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	byte timing;
-	
-	switch (pio) {
-	case 8:         /* set prefetch off */
-	case 9:         /* set prefetch on */
-		ht_set_prefetch(drive, pio & 1);
-		return;
-	}
-	
-	timing = ht_pio2timings(drive, pio);
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-void __init init_ht6560b (void)
-{
-	int t;
-	
-	if (check_region(HT_CONFIG_PORT,1)) {
-		printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
-	} else {
-		if (try_to_init_ht6560b()) {
-			request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
-			ide_hwifs[0].chipset = ide_ht6560b;
-			ide_hwifs[1].chipset = ide_ht6560b;
-			ide_hwifs[0].selectproc = &ht6560b_selectproc;
-			ide_hwifs[1].selectproc = &ht6560b_selectproc;
-			ide_hwifs[0].tuneproc = &tune_ht6560b;
-			ide_hwifs[1].tuneproc = &tune_ht6560b;
-			ide_hwifs[0].serialized = 1;  /* is this needed? */
-			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].mate = &ide_hwifs[1];
-			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].channel = 1;
-			
-			/*
-			 * Setting default configurations for drives
-			 */
-			t = (HT_CONFIG_DEFAULT << 8);
-			t |= HT_TIMING_DEFAULT;
-			ide_hwifs[0].drives[0].drive_data = t;
-			ide_hwifs[0].drives[1].drive_data = t;
-			t |= (HT_SECONDARY_IF << 8);
-			ide_hwifs[1].drives[0].drive_data = t;
-			ide_hwifs[1].drives[1].drive_data = t;
-		} else
-			printk(KERN_ERR "ht6560b: not found\n");
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/icside.c linux-2.4.21-rc3/drivers/ide/icside.c
--- linux-2.4.20/drivers/ide/icside.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/icside.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,766 +0,0 @@
-/*
- * linux/drivers/ide/icside.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- *  08-Jun-1996	RMK	Created
- *  12-Sep-1997	RMK	Added interrupt enable/disable
- *  17-Apr-1999	RMK	Added support for V6 EASI
- *  22-May-1999	RMK	Added support for V6 DMA
- */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS	2
-
-#define ICS_IDENT_OFFSET		0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT		0x000
-#define ICS_ARCIN_V5_INTROFFSET		0x001
-#define ICS_ARCIN_V5_IDEOFFSET		0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
-#define ICS_ARCIN_V5_IDESTEPPING	4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
-#define ICS_ARCIN_V6_INTROFFSET_1	0x880
-#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
-#define ICS_ARCIN_V6_IDESTEPPING	4
-
-struct cardinfo {
-	unsigned int dataoffset;
-	unsigned int ctrloffset;
-	unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
-	ICS_ARCIN_V5_IDEOFFSET,
-	ICS_ARCIN_V5_IDEALTOFFSET,
-	ICS_ARCIN_V5_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
-	ICS_ARCIN_V6_IDEOFFSET_1,
-	ICS_ARCIN_V6_IDEALTOFFSET_1,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
-	ICS_ARCIN_V6_IDEOFFSET_2,
-	ICS_ARCIN_V6_IDEALTOFFSET_2,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static const card_ids icside_cids[] = {
-	{ MANU_ICS,  PROD_ICS_IDE  },
-	{ MANU_ICS2, PROD_ICS2_IDE },
-	{ 0xffff, 0xffff }
-};
-
-typedef enum {
-	ics_if_unknown,
-	ics_if_arcin_v5,
-	ics_if_arcin_v6
-} iftype_t;
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-	icside_irqenable_arcin_v5,
-	icside_irqdisable_arcin_v5,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose  : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-	icside_irqenable_arcin_v6,
-	icside_irqdisable_arcin_v6,
-	icside_irqpending_arcin_v6,
-	NULL,
-	NULL,
-	NULL
-};
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t __init icside_identifyif (struct expansion_card *ec)
-{
-	unsigned int addr;
-	iftype_t iftype;
-	int id = 0;
-
-	iftype = ics_if_unknown;
-
-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-	id = inb (addr) & 1;
-	id |= (inb (addr + 1) & 1) << 1;
-	id |= (inb (addr + 2) & 1) << 2;
-	id |= (inb (addr + 3) & 1) << 3;
-
-	switch (id) {
-	case 0: /* A3IN */
-		printk("icside: A3IN unsupported\n");
-		break;
-
-	case 1: /* A3USER */
-		printk("icside: A3USER unsupported\n");
-		break;
-
-	case 3:	/* ARCIN V6 */
-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v6;
-		break;
-
-	case 15:/* ARCIN V5 (no id) */
-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v5;
-		break;
-
-	default:/* we don't know - complain very loudly */
-		printk("icside: ***********************************\n");
-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-		printk("icside: ***********************************\n");
-		printk("icside: please report this to linux@arm.linux.org.uk\n");
-		printk("icside: defaulting to ARCIN V5\n");
-		iftype = ics_if_arcin_v5;
-		break;
-	}
-
-	return iftype;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time.  NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-#define NR_ENTRIES 256
-#define TABLE_SIZE (NR_ENTRIES * 8)
-
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
-{
-	struct buffer_head *bh;
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
-
-	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
-}
-
-static int
-icside_build_dmatable(ide_drive_t *drive, int reading)
-{
-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void icside_destroy_dmatable(ide_drive_t *drive)
-{
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
-
-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
-}
-
-static int
-icside_config_if(ide_drive_t *drive, int xfer_mode)
-{
-	int func = ide_dma_off;
-
-	switch (xfer_mode) {
-	case XFER_MW_DMA_2:
-		/*
-		 * The cycle time is limited to 250ns by the r/w
-		 * pulse width (90ns), however we should still
-		 * have a maximum burst transfer rate of 8MB/s.
-		 */
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_1:
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_0:
-		drive->drive_data = 480;
-		break;
-
-	default:
-		drive->drive_data = 0;
-		break;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = (byte) xfer_mode;
-
-	if (drive->drive_data &&
-	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
-		func = ide_dma_on;
-	else
-		drive->drive_data = 480;
-
-	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
-		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
-	drive->current_speed = (byte) xfer_mode;
-
-	return func;
-}
-
-static int
-icside_set_speed(ide_drive_t *drive, byte speed)
-{
-	return icside_config_if(drive, speed);
-}
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
-{
-	int i;
-	byte stat, dma_stat;
-
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
-	}
-	return ide_error(drive, "dma_intr", stat);
-}
-
-/*
- * The following is a sick duplication from ide-dma.c ;(
- *
- * This should be defined in one place only.
- */
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-static struct drive_list_entry drive_whitelist [] = {
-	{ "Micropolis 2112A",			"ALL"		},
-	{ "CONNER CTMA 4000",			"ALL"		},
-	{ "CONNER CTT8000-A",			"ALL"		},
-	{ "ST34342A",				"ALL"		},
-	{ NULL,					0		}
-};
-
-static struct drive_list_entry drive_blacklist [] = {
-	{ "WDC AC11000H",			"ALL"		},
-	{ "WDC AC22100H",			"ALL"		},
-	{ "WDC AC32500H",			"ALL"		},
-	{ "WDC AC33100H",			"ALL"		},
-	{ "WDC AC31600H",			"ALL"		},
-	{ "WDC AC32100H",			"24.09P07"	},
-	{ "WDC AC23200L",			"21.10N21"	},
-	{ "Compaq CRD-8241B",			"ALL"		},
-	{ "CRD-8400B",				"ALL"		},
-	{ "CRD-8480B",				"ALL"		},
-	{ "CRD-8480C",				"ALL"		},
-	{ "CRD-8482B",				"ALL"		},
- 	{ "CRD-84",				"ALL"		},
-	{ "SanDisk SDP3B",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SANYO CD-ROM CRD",			"ALL"		},
-	{ "HITACHI CDR-8",			"ALL"		},
-	{ "HITACHI CDR-8335",			"ALL"		},
-	{ "HITACHI CDR-8435",			"ALL"		},
-	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
-	{ "CD-532E-A",				"ALL"		},
-	{ "E-IDE CD-ROM CR-840",		"ALL"		},
-	{ "CD-ROM Drive/F5A",			"ALL"		},
-	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
-	{ "WPI CDD-820",			"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
-	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
-	{ "_NEC DV5800A",			"ALL"		},
-	{ NULL,					0		}
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!strcmp(drive_table->id_firmware, "ALL"))))
-			return 1;
-	return 0;
-}
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-static int check_drive_lists(ide_drive_t *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-	return 0;
-}
-
-static int
-icside_dma_check(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	int autodma = hwif->autodma;
-	int xfer_mode = XFER_PIO_2;
-	int func = ide_dma_off_quietly;
-
-	if (!id || !(id->capability & 1) || !autodma)
-		goto out;
-
-	/*
-	 * Consult the list of known "bad" drives
-	 */
-	if (check_drive_lists(drive, 0)) {
-		func = ide_dma_off;
-		goto out;
-	}
-
-	/*
-	 * Enable DMA on any drive that has multiword DMA
-	 */
-	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
-			func = ide_dma_on;
-		}
-		goto out;
-	}
-
-	/*
-	 * Consult the list of known "good" drives
-	 */
-	if (check_drive_lists(drive, 1)) {
-		if (id->eide_dma_time > 150)
-			goto out;
-		xfer_mode = XFER_MW_DMA_1;
-		func = ide_dma_on;
-	}
-
-out:
-	func = icside_config_if(drive, xfer_mode);
-
-	return hwif->dmaproc(func, drive);
-}
-
-static int
-icside_dma_verbose(ide_drive_t *drive)
-{
-	printk(", DMA");
-	return 1;
-}
-
-static int
-icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int count, reading = 0;
-
-	switch (func) {
-	case ide_dma_off:
-		printk("%s: DMA disabled\n", drive->name);
-		/*FALLTHROUGH*/
-
-	case ide_dma_off_quietly:
-	case ide_dma_on:
-		drive->using_dma = (func == ide_dma_on);
-		return 0;
-
-	case ide_dma_check:
-		return icside_dma_check(drive);
-
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		count = icside_build_dmatable(drive, reading);
-		if (!count)
-			return 1;
-		disable_dma(hwif->hw.dma);
-
-		/* Route the DMA signals to
-		 * to the correct interface.
-		 */
-		outb(hwif->select_data, hwif->config_data);
-
-		/* Select the correct timing
-		 * for this drive
-		 */
-		set_dma_speed(hwif->hw.dma, drive->drive_data);
-
-		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
-		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
-			     : DMA_MODE_WRITE);
-
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
-			 IDE_COMMAND_REG);
-
-	case ide_dma_begin:
-		enable_dma(hwif->hw.dma);
-		return 0;
-
-	case ide_dma_end:
-		drive->waiting_for_dma = 0;
-		disable_dma(hwif->hw.dma);
-		icside_destroy_dmatable(drive);
-		return get_dma_residue(hwif->hw.dma) != 0;
-
-	case ide_dma_test_irq:
-		return inb((unsigned long)hwif->hw.priv) & 1;
-
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-
-	case ide_dma_verbose:
-		return icside_dma_verbose(drive);
-
-	case ide_dma_timeout:
-	default:
-		printk("icside_dmaproc: unsupported %s func: %d\n",
-			ide_dmafunc_verbose(func), func);
-	}
-	return 1;
-}
-
-static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
-{
-	printk("    %s: SG-DMA", hwif->name);
-
-	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
-				 GFP_KERNEL);
-	if (!hwif->sg_table)
-		goto failed;
-
-	hwif->dmatable_cpu = NULL;
-	hwif->dmatable_dma = 0;
-	hwif->speedproc = icside_set_speed;
-	hwif->dmaproc = icside_dmaproc;
-	hwif->autodma = autodma;
-
-	printk(" capable%s\n", autodma ?
-		", auto-enable" : "");
-
-	return 1;
-
-failed:
-	printk(" -- ERROR, unable to allocate DMA table\n");
-	return 0;
-}
-#endif
-
-static ide_hwif_t *
-icside_find_hwif(unsigned long dataport)
-{
-	ide_hwif_t *hwif;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
-			goto found;
-	}
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (!hwif->io_ports[IDE_DATA_OFFSET])
-			goto found;
-	}
-
-	return NULL;
-found:
-	return hwif;
-}
-
-static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, int irq)
-{
-	unsigned long port = base + info->dataoffset;
-	ide_hwif_t *hwif;
-
-	hwif = icside_find_hwif(base);
-	if (hwif) {
-		int i;
-
-		memset(&hwif->hw, 0, sizeof(hw_regs_t));
-
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
-			hwif->io_ports[i] = (ide_ioreg_t)port;
-			port += 1 << info->stepping;
-		}
-		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->hw.irq  = irq;
-		hwif->irq     = irq;
-		hwif->hw.dma  = NO_DMA;
-		hwif->noprobe = 0;
-		hwif->chipset = ide_acorn;
-	}
-
-	return hwif;
-}
-
-static int __init icside_register_v5(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port;
-	ide_hwif_t *hwif;
-
-	slot_port = ecard_address(ec, ECARD_MEMC, 0);
-
-	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
-	ec->irqmask  = 1;
-	ec->irq_data = (void *)slot_port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
-
-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
-
-	return hwif ? 0 : -1;
-}
-
-static int __init icside_register_v6(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port, port;
-	ide_hwif_t *hwif, *mate;
-	int sel = 0;
-
-	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
-
-	if (port == 0)
-		port = slot_port;
-	else
-		sel = 1 << 5;
-
-	outb(sel, slot_port);
-
-	ec->irq_data = (void *)port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
-
-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-	if (ec->dma != NO_DMA) {
-		if (request_dma(ec->dma, hwif->name))
-			goto no_dma;
-
-		if (hwif) {
-			hwif->config_data = slot_port;
-			hwif->select_data = sel;
-			hwif->hw.dma  = ec->dma;
-			hwif->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_1);
-			hwif->channel = 0;
-			icside_setup_dma(hwif, autodma);
-		}
-		if (mate) {
-			mate->config_data = slot_port;
-			mate->select_data = sel | 1;
-			mate->hw.dma  = ec->dma;
-			mate->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_2);
-			mate->channel = 1;
-			icside_setup_dma(mate, autodma);
-		}
-	}
-no_dma:
-#endif
-	return hwif || mate ? 0 : -1;
-}
-
-int __init icside_init(void)
-{
-	int autodma = 0;
-
-#ifdef CONFIG_IDEDMA_ICS_AUTO
-	autodma = 1;
-#endif
-
-	ecard_startfind ();
-
-	do {
-		struct expansion_card *ec;
-		int result;
-
-		ec = ecard_find(0, icside_cids);
-		if (ec == NULL)
-			break;
-
-		ecard_claim(ec);
-
-		switch (icside_identifyif(ec)) {
-		case ics_if_arcin_v5:
-			result = icside_register_v5(ec, autodma);
-			break;
-
-		case ics_if_arcin_v6:
-			result = icside_register_v6(ec, autodma);
-			break;
-
-		default:
-			result = -1;
-			break;
-		}
-
-		if (result)
-			ecard_release(ec);
-	} while (1);
-
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-adma.c linux-2.4.21-rc3/drivers/ide/ide-adma.c
--- linux-2.4.20/drivers/ide/ide-adma.c	2001-08-13 22:44:03.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-adma.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,9 +0,0 @@
-/*
- *  linux/drivers/ide/ide-adma.c         Version 0.00	June 24, 2001
- *
- *  Copyright (c) 2001		Andre Hedrick <andre@linux-ide.org>
- *
- *  Asynchronous DMA -- TBA, this is a holding file.
- *
- */
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.c linux-2.4.21-rc3/drivers/ide/ide-cd.c
--- linux-2.4.20/drivers/ide/ide-cd.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-cd.c	2003-05-22 22:06:42.000000000 +0000
@@ -294,7 +294,7 @@
  *
  *************************************************************************/
  
-#define IDECD_VERSION "4.59"
+#define IDECD_VERSION "4.59-ac1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -540,7 +540,141 @@
 }
 
 
-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
+/*
+ * This is our end_request replacement function.
+ */
+static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+
+	atapi_status_t status;
+	atapi_error_t error;
+
+	status.all = stat;
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (status.b.bsy)
+		printk("Busy ");
+	else {
+		if (status.b.drdy)	printk("DriveReady ");
+		if (status.b.df)	printk("DeviceFault ");
+		if (status.b.dsc)	printk("SeekComplete ");
+		if (status.b.drq)	printk("DataRequest ");
+		if (status.b.corr)	printk("CorrectedError ");
+		if (status.b.idx)	printk("Index ");
+		if (status.b.check)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
+		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
+#if FANCY_STATUS_DUMPS
+		if (error.b.ili)	printk("IllegalLengthIndication ");
+		if (error.b.eom)	printk("EndOfMedia ");
+		if (error.b.abrt)	printk("Aborted Command ");
+		if (error.b.mcr)	printk("MediaChangeRequested ");
+		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
+						error.b.sense_key);
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return error.all;
+}
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_cdrom_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		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 {
+		/* add decoding error stuff */
+	}
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+ide_startstop_t ide_cdrom_abort (ide_drive_t *drive, const char *msg)
+{
+	struct request *rq;
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, BUSY_STAT, 0);
+		return ide_stopped;
+	}
+	rq->errors |= ERROR_RESET;
+	DRIVER(drive)->end_request(drive, 0);
+	return ide_stopped;
+}
+
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -550,11 +684,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if (rq->cmd == READ || rq->cmd == WRITE)
-		if (!rq->current_nr_sectors)
-			uptodate = 1;
+	if (blk_fs_request(rq) && !rq->current_nr_sectors)
+		uptodate = 1;
 
-	ide_end_request (uptodate, HWGROUP(drive));
+	ide_cdrom_end_request(drive, uptodate);
 }
 
 
@@ -568,14 +701,13 @@
 	struct packet_command *pc;
 	
 	/* Check for errors. */
-	stat = GET_STAT();
-	*stat_ret = stat;
+	*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
 	/* Get the IDE error register. */
-	err = GET_ERR();
+	err = HWIF(drive)->INB(IDE_ERROR_REG);
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
@@ -591,8 +723,8 @@
 
 		pc = (struct packet_command *) rq->buffer;
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
-		*startstop = ide_error (drive, "request sense failure", stat);
+		cdrom_end_request(drive, 1);
+		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
 
 	} else if (rq->cmd == PACKET_COMMAND) {
@@ -628,11 +760,11 @@
 		}
 
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
-	} else {
+	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
@@ -641,7 +773,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -650,21 +782,26 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request (0, drive);
+				cdrom_end_request(drive, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
 			ide_dump_status (drive, "command error", stat);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ide_error (drive, "cdrom_decode_status", stat);
+			*startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
 			return 1;
+		} else if (sense_key == MEDIUM_ERROR) {
+			/* No point in re-trying a zillion times on a bad 
+			 * sector...  If we got here the error is not correctable */
+			ide_dump_status (drive, "media error (bad sector)", stat);
+			cdrom_end_request(drive, 0);
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
@@ -723,33 +860,32 @@
 
 	if (info->dma) {
 		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+			info->dma = !HWIF(drive)->ide_dma_read(drive);
 		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+			info->dma = !HWIF(drive)->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);
+	/* FIXME: for Virtual DMA we must check harder */
+	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+		HWIF(drive)->OUTB(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 */
+		/* packet command */
+		ide_execute_command(drive, WIN_PACKETCMD, handler, WAIT_CMD, cdrom_timer_expiry);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*handler) (drive);
 	}
 }
@@ -770,27 +906,34 @@
 	unsigned char *cmd_buf	= pc->c;
 	int cmd_len		= sizeof(pc->c);
 	unsigned int timeout	= pc->timeout;
+	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+	if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+				BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
+	ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
-	atapi_output_bytes (drive, cmd_buf, cmd_len);
+	HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len);
+
+	/* Start the DMA if need be */
+	if (info->dma)
+		(void) HWIF(drive)->ide_dma_begin(drive);
+
 	return ide_started;
 }
 
@@ -828,7 +971,7 @@
 	/* Read the data into the buffer. */
 	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
-		atapi_input_bytes (drive, dest, SECTOR_SIZE);
+		HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
 		--sectors_to_transfer;
 		++info->nsectors_buffered;
@@ -838,7 +981,7 @@
 	/* Throw away any remaining data. */
 	while (sectors_to_transfer > 0) {
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 		--sectors_to_transfer;
 	}
 }
@@ -864,14 +1007,14 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
 		 * info is available. just get it and ignore.
 		 */
-		GET_STAT();
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
 		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -879,7 +1022,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request (0, drive);
+	cdrom_end_request(drive, 0);
 	return -1;
 }
 
@@ -891,6 +1034,7 @@
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
+	u8 lowcyl = 0, highcyl = 0;
 	int i, dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
@@ -899,8 +1043,8 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
+			HWIF(drive)->ide_dma_off(drive);
 	}
 
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -910,16 +1054,19 @@
 		if (!dma_error) {
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				ide_cdrom_end_request(drive, 1);
 			}
 			return ide_stopped;
 		} else
-			return ide_error (drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -928,9 +1075,9 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		return ide_stopped;
 	}
 
@@ -944,13 +1091,13 @@
 	if ((len % SECTOR_SIZE) != 0) {
 		printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
 			drive->name, len);
-		if (CDROM_CONFIG_FLAGS (drive)->limit_nframes)
+		if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
 			printk ("  This drive is not supported by this version of the driver\n");
 		else {
 			printk ("  Trying to limit transfer sizes\n");
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		}
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -965,7 +1112,7 @@
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 
 		--rq->current_nr_sectors;
 		--nskip;
@@ -979,7 +1126,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -996,7 +1143,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+				HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -1007,8 +1154,7 @@
 		}
 	}
 
-	/* Done moving data!
-	   Wait for another interrupt. */
+	/* Done moving data!  Wait for another interrupt. */
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -1031,7 +1177,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1046,13 +1192,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1060,9 +1206,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+		printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
 			drive->name, rq->sector);
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return -1;
 	}
 
@@ -1101,7 +1247,7 @@
 			(rq->sector % CD_FRAMESIZE != 0)) {
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 		sector -= nskip;
@@ -1147,7 +1293,7 @@
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
-	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
+	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0) {
 			/*
 			 * this condition is far too common, to bother
@@ -1189,7 +1335,7 @@
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
 }
 
 static inline int cdrom_merge_requests(struct request *rq, struct request *nxt)
@@ -1263,7 +1409,7 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
-	int minor = MINOR (rq->rq_dev);
+	int minor = MINOR(rq->rq_dev);
 
 	/* If the request is relative to a partition, fix it up to refer to the
 	   absolute address.  */
@@ -1313,14 +1459,18 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
+	u8 lowcyl = 0, highcyl = 0;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed.
 	   Complain if we still have data left to transfer. */
@@ -1337,7 +1487,7 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		else {
 			/* Comment this out, because this always happens 
 			   right after a reset occurs, and it is annoying to 
@@ -1347,7 +1497,7 @@
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
@@ -1359,14 +1509,14 @@
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
 		/* Transfer the data. */
-		atapi_output_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1378,14 +1528,14 @@
 	else if ((ireason & 3) == 2) {
 
 		/* Transfer the data. */
-		atapi_input_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_input_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1399,7 +1549,7 @@
 	}
 
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
@@ -1430,7 +1580,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1462,7 +1612,7 @@
 		ide_init_drive_cmd (&req);
 		req.cmd = PACKET_COMMAND;
 		req.buffer = (char *)pc;
-		ide_do_drive_cmd (drive, &req, ide_wait);
+		ide_do_drive_cmd(drive, &req, ide_wait);
 		/* FIXME: we should probably abort/retry or something 
 		 * in case of failure */
 		if (pc->stat != 0) {
@@ -1472,7 +1622,7 @@
 			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
-				cdrom_saw_media_change (drive);
+				cdrom_saw_media_change(drive);
 			else if (reqbuf->sense_key == NOT_READY &&
 				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
@@ -1513,7 +1663,7 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes(drive, &dum, sizeof(dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
 			len -= sizeof(dum);
 		}
 	} else {
@@ -1522,7 +1672,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(0, drive);
+	cdrom_end_request(drive, 0);
 	return 1;
 }
 
@@ -1531,6 +1681,7 @@
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma_error = 0, dma = info->dma;
+	u8 lowcyl = 0, highcyl = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1538,9 +1689,9 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
 			printk("ide-cd: write dma error\n");
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			HWIF(drive)->ide_dma_off(drive);
 		}
 	}
 
@@ -1554,19 +1705,22 @@
 	 */
 	if (dma) {
 		if (dma_error)
-			return ide_error(drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 
 		rq = HWGROUP(drive)->rq;
 		for (i = rq->nr_sectors; i > 0;) {
 			i -= rq->current_nr_sectors;
-			ide_end_request(1, HWGROUP(drive));
+			ide_cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE(IDE_NSECTOR_REG);
-	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -1579,7 +1733,7 @@
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(uptodate, drive);
+		cdrom_end_request(drive, uptodate);
 		return ide_stopped;
 	}
 
@@ -1607,7 +1761,7 @@
 		this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);
 
 		while (this_transfer > 0) {
-			atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+			HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
 			rq->buffer += SECTOR_SIZE;
 			--rq->nr_sectors;
 			--rq->current_nr_sectors;
@@ -1620,7 +1774,7 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 	}
 
 	/* re-arm handler */
@@ -1662,7 +1816,7 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -1698,11 +1852,10 @@
 		case WRITE:
 		case READ: {
 			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-				unsigned long elpased = jiffies - info->start_seek;
-				int stat = GET_STAT();
+				int stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 				if ((stat & SEEK_STAT) != SEEK_STAT) {
-					if (elpased < IDECD_SEEK_TIMEOUT) {
+					if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) {
 						ide_stall_queue(drive, IDECD_SEEK_TIMER);
 						return ide_stopped;
 					}
@@ -1711,9 +1864,9 @@
 				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
 			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-				action = cdrom_start_seek (drive, block);
+				action = cdrom_start_seek(drive, block);
 			else {
-				if (rq->cmd == READ)
+				if (rq_data_dir(rq) == READ)
 					action = cdrom_start_read(drive, block);
 				else
 					action = cdrom_start_write(drive, rq);
@@ -1728,13 +1881,13 @@
 		}
 
 		case RESET_DRIVE_COMMAND: {
-			cdrom_end_request(1, drive);
+			cdrom_end_request(drive, 1);
 			return ide_do_reset(drive);
 		}
 
 		default: {
 			printk("ide-cd: bad cmd %d\n", rq->cmd);
-			cdrom_end_request(0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 	}
@@ -1836,7 +1989,7 @@
 		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command (drive, &pc);
+		stat = cdrom_queue_packet_command(drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1846,7 +1999,7 @@
 	    (sense->asc == 0x24 || sense->asc == 0x20)) {
 		printk ("%s: door locking not supported\n",
 			drive->name);
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 		stat = 0;
 	}
 	
@@ -1855,7 +2008,7 @@
 		stat = 0;
 
 	if (stat == 0)
-		CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
+		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
 
 	return stat;
 }
@@ -1880,7 +2033,7 @@
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1929,7 +2082,7 @@
 	if (msf_flag)
 		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1969,9 +2122,9 @@
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
@@ -2009,7 +2162,7 @@
 			return stat;
 		}
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
+		if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
 			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
 			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
 		} else
@@ -2026,18 +2179,18 @@
 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
 	for (i=0; i<=ntracks; i++) {
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) {
-			if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd)
-				toc->ent[i].track = bcd2bin (toc->ent[i].track);
-			msf_from_bcd (&toc->ent[i].addr.msf);
+		if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+			if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+				toc->ent[i].track = bcd2bin(toc->ent[i].track);
+			msf_from_bcd(&toc->ent[i].addr.msf);
 		}
 #endif  /* not STANDARD_ATAPI */
 		toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
@@ -2059,7 +2212,7 @@
 	}
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
+	if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
 		msf_from_bcd (&ms_tmp.ent.addr.msf);
 #endif  /* not STANDARD_ATAPI */
 
@@ -2082,7 +2235,7 @@
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 
 	/* Remember that we've read this stuff. */
-	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid = 1;
 
 	return 0;
 }
@@ -2308,7 +2461,7 @@
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
-		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce);
+		stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
 		if (stat) return stat;
 
 		tocentry->cdte_ctrl = toce->control;
@@ -2380,10 +2533,10 @@
 	struct request_sense sense;
 	int stat;
 
-	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
+	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
 		return stat;
 
-        cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
         return 0;
 }
 
@@ -2476,8 +2629,8 @@
 	
 	if (slot_nr == CDSL_CURRENT) {
 		(void) cdrom_check_status(drive, NULL);
-		retval = CDROM_STATE_FLAGS (drive)->media_changed;
-		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		retval = CDROM_STATE_FLAGS(drive)->media_changed;
+		CDROM_STATE_FLAGS(drive)->media_changed = 0;
 		return retval;
 	} else {
 		return -EINVAL;
@@ -2535,30 +2688,30 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = MKDEV(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
 	devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
 	
 	/* set capability mask to match the probe. */
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
 		devinfo->mask |= CDC_CD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
 		devinfo->mask |= CDC_CD_RW;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd)
 		devinfo->mask |= CDC_DVD;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
 		devinfo->mask |= CDC_DVD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		devinfo->mask |= CDC_DVD_RAM;
-	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
+	if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
 		devinfo->mask |= CDC_SELECT_DISC;
-	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
+	if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
 		devinfo->mask |= CDC_PLAY_AUDIO;
-	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+	if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
@@ -2581,11 +2734,9 @@
 	 * ACER50 (and others?) require the full spec length mode sense
 	 * page capabilities size, but older drives break.
 	 */
-	if (drive->id) {
-		if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
-		    !strcmp(drive->id->model, "WPI CDS-32X")))
-			size -= sizeof(cap->pad);
-	}
+	if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+	    !strcmp(drive->id->model, "WPI CDS-32X")))
+		size -= sizeof(cap->pad);
 
 	/* we have to cheat a little here. the packet will eventually
 	 * be queued with ide_cdrom_packet(), which extracts the
@@ -2612,9 +2763,9 @@
 	struct atapi_capabilities_page cap;
 	int nslots = 1;
 
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
+	if (CDROM_CONFIG_FLAGS(drive)->nec260) {
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;       
 		return nslots;
 	}
 
@@ -2622,38 +2773,38 @@
 		return 0;
 
 	if (cap.lock == 0)
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 	if (cap.eject)
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
 	if (cap.cd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
 	if (cap.cd_rw_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
 	if (cap.test_write)
-		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
+		CDROM_CONFIG_FLAGS(drive)->test_write = 1;
 	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
-		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
 	if (cap.dvd_ram_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
 	if (cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
 	if (cap.audio_play)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
-		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
+		CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
 
 	/* Some drives used by Apple don't advertise audio play
 	 * but they do support reading TOC & audio datas
 	 */
-	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+	if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
 	if (cdi->sanyo_slot > 0) {
-		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
+		CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
 		nslots = 3;
 	}
 
@@ -2662,51 +2813,52 @@
 	if (cap.mechtype == mechtype_individual_changer ||
 	    cap.mechtype == mechtype_cartridge_changer) {
 		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
-			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
-			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
+			CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+			CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
 		}
 	}
 
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+	if (!drive->id->model[0] &&
+	    !strncmp(drive->id->fw_rev, "241N", 4)) {
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(((unsigned int)cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(ntohs(cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
 
 	/* don't print speed if the drive reported 0.
 	 */
-	printk("%s: ATAPI", drive->name);
+	printk(KERN_INFO "%s: ATAPI", drive->name);
 	if (CDROM_CONFIG_FLAGS(drive)->max_speed)
 		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-        	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
-        	printk (" CD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+	if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+        	printk(" DVD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+
+        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+        	printk(" CD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
 
-        if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
-        	printk (" changer w/%d slots", nslots);
+        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
+        	printk(" changer w/%d slots", nslots);
         else 	
-        	printk (" drive");
+        	printk(" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
+	printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -2741,106 +2893,95 @@
 	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
-	CDROM_STATE_FLAGS (drive)->media_changed = 1;
-	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
-	CDROM_STATE_FLAGS (drive)->door_locked   = 0;
+	CDROM_STATE_FLAGS(drive)->media_changed = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
+	CDROM_STATE_FLAGS(drive)->door_locked   = 0;
 
 #if NO_DOOR_LOCKING
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 #else
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
 #endif
 
-	if (drive->id != NULL)
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
-			((drive->id->config & 0x0060) == 0x20);
-	else
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0;
+	CDROM_CONFIG_FLAGS(drive)->drq_interrupt =
+		((drive->id->config & 0x0060) == 0x20);
 
-	CDROM_CONFIG_FLAGS (drive)->is_changer = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
-	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
-	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
-	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
-	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
-	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
+	CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+	CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
 	
 	/* limit transfer size per interrupt. */
-	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
-	if (drive->id != NULL) {
-		/* a testament to the nice quality of Samsung drives... */
-		if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
-		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
-		/* the 3231 model does not support the SET_CD_SPEED command */
-		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
-			cdi->mask |= CDC_SELECT_SPEED;
-	}
+	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
+
+	/* a testament to the nice quality of Samsung drives... */
+	if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
+		CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+	else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
+		CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+	/* the 3231 model does not support the SET_CD_SPEED command */
+	else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
+		cdi->mask |= CDC_SELECT_SPEED;
 
 #if ! STANDARD_ATAPI
 	/* by default Sanyo 3 CD changer support is turned off and
            ATAPI Rev 2.2+ standard support for CD changers is used */
 	cdi->sanyo_slot = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->nec260 = 0;
-	CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 0;
-
-	if (drive->id != NULL) {
-		if (strcmp (drive->id->model, "V003S0DS") == 0 &&
-		    drive->id->fw_rev[4] == '1' &&
-		    drive->id->fw_rev[6] <= '2') {
-			/* Vertos 300.
-			   Some versions of this drive like to talk BCD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-		}
-
-		else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
-		    drive->id->fw_rev[4] == '1' &&
-		    drive->id->fw_rev[6] <= '2') {
-			/* Vertos 600 ESD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-		}
-
-		else if (strcmp (drive->id->model,
-				 "NEC CD-ROM DRIVE:260") == 0 &&
-			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
-			/* Old NEC260 (not R).
-			   This drive was released before the 1.2 version
-			   of the spec. */
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->nec260         = 1;
-		}
-
-		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
-			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
-			/* Wearnes */
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-		}
-
-                /* Sanyo 3 CD changer uses a non-standard command
-                    for CD changing */
-                 else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
-                         (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
-                         (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
-                        /* uses CD in slot 0 when value is set to 3 */
-                        cdi->sanyo_slot = 3;
-                }
-
-
+	CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+	CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
+
+	if (strcmp (drive->id->model, "V003S0DS") == 0 &&
+	    drive->id->fw_rev[4] == '1' &&
+	    drive->id->fw_rev[6] <= '2') {
+		/* Vertos 300.
+		   Some versions of this drive like to talk BCD. */
+		CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+	}
+	else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
+	    drive->id->fw_rev[4] == '1' &&
+    	    drive->id->fw_rev[6] <= '2') {
+		/* Vertos 600 ESD. */
+		CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+	}
+
+	else if (strcmp(drive->id->model,
+			 "NEC CD-ROM DRIVE:260") == 0 &&
+		 strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+		/* Old NEC260 (not R).
+		   This drive was released before the 1.2 version
+		   of the spec. */
+		CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
+	}
+	else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+		 strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+		/* Wearnes */
+		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+	}
+        /* Sanyo 3 CD changer uses a non-standard command
+	   for CD changing */
+	else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
+		(strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
+		(strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
+			/* uses CD in slot 0 when value is set to 3 */
+			cdi->sanyo_slot = 3;
 	}
 #endif /* not STANDARD_ATAPI */
 
@@ -2857,7 +2998,16 @@
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
 
-	if (ide_cdrom_register (drive, nslots)) {
+#if 0
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
+			drive->name);
+		drive->dsc_overlap = 0;
+	}
+#endif
+
+	if (ide_cdrom_register(drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
 		info->devinfo.handle = NULL;
 		return 1;
@@ -2872,7 +3022,7 @@
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	return cdrom_ioctl (inode, file, cmd, arg);
+	return cdrom_ioctl(inode, file, cmd, arg);
 }
 
 static
@@ -2902,7 +3052,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(MKDEV (HWIF(drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2950,22 +3100,26 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to ide_unregister_subdriver\n",
+			__FUNCTION__, drive->name);
 		return 1;
+	}
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
 		kfree(info->toc);
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
-	if (devinfo->handle == drive && unregister_cdrom (devinfo))
-		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
+	if (devinfo->handle == drive && unregister_cdrom(devinfo))
+		printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree(info);
 	drive->driver_data = NULL;
 	return 0;
 }
 
-int ide_cdrom_reinit (ide_drive_t *drive);
+int ide_cdrom_init(void);
+int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
@@ -2976,9 +3130,14 @@
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
-	end_request:		NULL,
+	end_request:		ide_cdrom_end_request,
+	sense:			ide_cdrom_dump_status,
+	error:			ide_cdrom_error,
+	abort:			ide_cdrom_abort,
 	ioctl:			ide_cdrom_ioctl,
 	open:			ide_cdrom_open,
 	release:		ide_cdrom_release,
@@ -2988,12 +3147,12 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			ide_cdrom_reinit,
+	init:			ide_cdrom_init,
+	attach:			ide_cdrom_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -3007,35 +3166,46 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int ide_cdrom_reinit (ide_drive_t *drive)
+int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	int failed = 0;
 
+	if (drive->scsi) {
+		printk("ide-cd: passing drive %s to ide-scsi emulation.\n",
+			drive->name);
+		return 1;
+	}
+
 	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);
+		printk("%s: Can't allocate a cdrom structure\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		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);
+	if (ide_register_subdriver(drive,
+			&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-cd: %s: Failed to register the driver "
+			"with ide.c\n", drive->name);
+		kfree(info);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	memset (info, 0, sizeof (struct cdrom_info));
+	memset(info, 0, sizeof(struct cdrom_info));
 	drive->driver_data = info;
 	DRIVER(drive)->busy++;
-	if (ide_cdrom_setup (drive)) {
+	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);
+		if (ide_cdrom_cleanup(drive))
+			printk("%s: ide_cdrom_cleanup failed in "
+				"ide_cdrom_init\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
 	DRIVER(drive)->busy--;
 	failed--;
 
-	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -3045,41 +3215,51 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
-		if (ide_cdrom_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_cdrom, ide_cdrom_driver.name,
+			&ide_cdrom_driver, failed)) != NULL)
+		if (ide_cdrom_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
-	ide_unregister_module (&ide_cdrom_module);
+	ide_unregister_module(&ide_cdrom_module);
 }
- 
+
 int ide_cdrom_init(void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	struct cdrom_info *info;
 	int failed = 0;
-
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_cdrom,
+			ide_cdrom_driver.name, NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
 		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
-				printk("ide-cd: ignoring drive %s\n", drive->name);
+				printk("ide-cd: ignoring drive %s\n",
+					drive->name);
 				continue;
 			}
 		}
 		if (drive->scsi) {
-			printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+			printk("ide-cd: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
 		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);
+			printk ("%s: Can't allocate a cdrom structure\n",
+				drive->name);
 			continue;
 		}
-		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);
+		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);
 			continue;
 		}
 		memset (info, 0, sizeof (struct cdrom_info));
@@ -3088,12 +3268,14 @@
 		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);
+				printk ("%s: ide_cdrom_cleanup failed in "
+					"ide_cdrom_init\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.h linux-2.4.21-rc3/drivers/ide/ide-cd.h
--- linux-2.4.20/drivers/ide/ide-cd.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-cd.h	2003-05-22 22:06:52.000000000 +0000
@@ -437,7 +437,7 @@
 
 	byte     curlba[3];
 	byte     nslots;
-	__u8 short slot_tablelen;
+	__u16	slot_tablelen;
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cs.c linux-2.4.21-rc3/drivers/ide/ide-cs.c
--- linux-2.4.20/drivers/ide/ide-cs.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,492 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA IDE/ATA disk cards
-
-    ide_cs.c 1.26 1999/11/16 02:10:49
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/major.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static const char ide_major[] = {
-    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
-#ifdef IDE4_MAJOR
-    IDE4_MAJOR, IDE5_MAJOR
-#endif
-};
-
-typedef struct ide_info_t {
-    dev_link_t	link;
-    int		ndev;
-    dev_node_t	node;
-    int		hd;
-} ide_info_t;
-
-static void ide_config(dev_link_t *link);
-static void ide_release(u_long arg);
-static int ide_event(event_t event, int priority,
-		     event_callback_args_t *args);
-
-static dev_info_t dev_info = "ide-cs";
-
-static dev_link_t *ide_attach(void);
-static void ide_detach(dev_link_t *);
-
-static dev_link_t *dev_list = NULL;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
-static dev_link_t *ide_attach(void)
-{
-    ide_info_t *info;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int i, ret;
-    
-    DEBUG(0, "ide_attach()\n");
-
-    /* Create new ide device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
-    if (!info) return NULL;
-    memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
-
-    link->release.function = &ide_release;
-    link->release.data = (u_long)link;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-    link->io.IOAddrLines = 3;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-	link->irq.IRQInfo2 = irq_mask;
-    else
-	for (i = 0; i < 4; i++)
-	    link->irq.IRQInfo2 |= 1 << irq_list[i];
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ide_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = CardServices(RegisterClient, &link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-	cs_error(link->handle, RegisterClient, ret);
-	ide_detach(link);
-	return NULL;
-    }
-    
-    return link;
-} /* ide_attach */
-
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
-static void ide_detach(dev_link_t *link)
-{
-    dev_link_t **linkp;
-    int ret;
-
-    DEBUG(0, "ide_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
-
-    del_timer(&link->release);
-    if (link->state & DEV_CONFIG)
-	ide_release((u_long)link);
-    
-    if (link->handle) {
-	ret = CardServices(DeregisterClient, link->handle);
-	if (ret != CS_SUCCESS)
-	    cs_error(link->handle, DeregisterClient, ret);
-    }
-    
-    /* Unlink, free device structure */
-    *linkp = link->next;
-    kfree(link->priv);
-    
-} /* ide_detach */
-
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-#define CFG_CHECK(fn, args...) \
-if (CardServices(fn, args) != 0) goto next_entry
-
-int idecs_register (int arg1, int arg2, int irq)
-{
-        hw_regs_t hw;
-        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 */
-        return ide_register_hw(&hw, NULL);
-}
-
-void ide_config(dev_link_t *link)
-{
-    client_handle_t handle = link->handle;
-    ide_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    config_info_t conf;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
-    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
-
-    DEBUG(0, "ide_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    CS_CHECK(GetTupleData, handle, &tuple);
-    CS_CHECK(ParseTuple, handle, &tuple, &parse);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, handle, &conf);
-    link->conf.Vcc = conf.Vcc;
-    
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    while (1) {
-	CFG_CHECK(GetTupleData, handle, &tuple);
-	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-	/* Check for matching Vcc, unless we're desperate */
-	if (!pass) {
-	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    }
-	}
-	
-	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-	
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	    if (io->nwin == 2) {
-		link->io.NumPorts1 = 8;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = 1;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort2;
-	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-		link->io.NumPorts1 = io->win[0].len;
-		link->io.NumPorts2 = 0;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort1+0x0e;
-	    } else goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-	
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	if (pass) {
-	    CS_CHECK(GetNextTuple, handle, &tuple);
-	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, handle, &tuple);
-	    memset(&dflt, 0, sizeof(dflt));
-	    pass++;
-	}
-    }
-    
-    CS_CHECK(RequestIRQ, handle, &link->irq);
-    CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-    /* deal with brain dead IDE resource management */
-    release_region(link->io.BasePort1, link->io.NumPorts1);
-    if (link->io.NumPorts2)
-	release_region(link->io.BasePort2, link->io.NumPorts2);
-
-    /* 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) {
-		io_base += 0x10; ctl_base += 0x10;
-		break;
-	    }
-	}
-	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/10);
-    }
-    
-    if (hd < 0) {
-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
-	       ", irq %u failed\n", io_base, ctl_base,
-	       link->irq.AssignedIRQ);
-	goto failed;
-    }
-
-    MOD_INC_USE_COUNT;
-    info->ndev = 1;
-    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
-    info->node.major = ide_major[hd];
-    info->node.minor = 0;
-    info->hd = hd;
-    link->dev = &info->node;
-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
-	   link->conf.Vpp1/10, link->conf.Vpp1%10);
-
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
-cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
-failed:
-    ide_release((u_long)link);
-
-} /* ide_config */
-
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
-void ide_release(u_long arg)
-{
-    dev_link_t *link = (dev_link_t *)arg;
-    ide_info_t *info = link->priv;
-    
-    DEBUG(0, "ide_release(0x%p)\n", link);
-
-    if (info->ndev) {
-	ide_unregister(info->hd);
-	MOD_DEC_USE_COUNT;
-    }
-
-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
-    if (link->io.NumPorts2)
-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-    
-    info->ndev = 0;
-    link->dev = NULL;
-    
-    CardServices(ReleaseConfiguration, link->handle);
-    CardServices(ReleaseIO, link->handle, &link->io);
-    CardServices(ReleaseIRQ, link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
-
-} /* ide_release */
-
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-    
-======================================================================*/
-
-int ide_event(event_t event, int priority,
-	      event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-
-    DEBUG(1, "ide_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-	    mod_timer(&link->release, jiffies + HZ/20);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	ide_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG)
-	    CardServices(ReleaseConfiguration, link->handle);
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (DEV_OK(link))
-	    CardServices(RequestConfiguration, link->handle, &link->conf);
-	break;
-    }
-    return 0;
-} /* ide_event */
-
-/*====================================================================*/
-
-static int __init init_ide_cs(void)
-{
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
-}
-
-static void __exit exit_ide_cs(void)
-{
-    DEBUG(0, "ide_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
-}
-
-module_init(init_ide_cs);
-module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-default.c linux-2.4.21-rc3/drivers/ide/ide-default.c
--- linux-2.4.20/drivers/ide/ide-default.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-default.c	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,97 @@
+/*
+ *	ide-default		-	Driver for unbound ide devices
+ *
+ *	This provides a clean way to bind a device to default operations
+ *	by having an actual driver class that rather than special casing
+ *	"no driver" all over the IDE code
+ *
+ *	Copyright (C) 2003, Red Hat <alan@redhat.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/delay.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/slab.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/bitops.h>
+
+#define IDEDEFAULT_VERSION	"0.9.newide"
+/*
+ *	Driver initialization.
+ */
+
+static void idedefault_setup (ide_drive_t *drive)
+{
+}
+
+int idedefault_init (void);
+int idedefault_attach(ide_drive_t *drive);
+
+/*
+ *	IDE subdriver functions, registered with ide.c
+ */
+
+ide_driver_t idedefault_driver = {
+	name:			"ide-default",
+	version:		IDEDEFAULT_VERSION,
+	media:			0,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
+	init:			idedefault_init,
+	attach:			idedefault_attach,
+};
+
+static ide_module_t idedefault_module = {
+	IDE_DRIVER_MODULE,
+	idedefault_init,
+	&idedefault_driver,
+	NULL
+};
+
+int idedefault_attach (ide_drive_t *drive)
+{
+	int ret = 0;
+	MOD_INC_USE_COUNT;
+	if (ide_register_subdriver(drive,
+			&idedefault_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-default: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	DRIVER(drive)->busy++;
+	idedefault_setup(drive);
+	DRIVER(drive)->busy--;
+
+bye_game_over:
+	MOD_DEC_USE_COUNT;
+	return ret;
+}
+
+MODULE_DESCRIPTION("IDE Default Driver");
+
+int idedefault_init (void)
+{
+	ide_register_module(&idedefault_module);
+	return 0;
+}
+
+module_init(idedefault_init);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-disk.c linux-2.4.21-rc3/drivers/ide/ide-disk.c
--- linux-2.4.20/drivers/ide/ide-disk.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-disk.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,7 +1,12 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.18	Mar 05, 2003
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1998-2002  Linux ATA Developemt
+ *				Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003	     Red Hat <alan@redhat.com>
+ *
+ *
  */
 
 /*
@@ -29,10 +34,16 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
- *			Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.13		added standby and flush-cache for notifier
+ * Version 1.14		added acoustic-wcache
+ * Version 1.15		convert all calls to ide_raw_taskfile
+ *				since args will return register content.
+ * Version 1.16		added suspend-resume-checkpower
+ * Version 1.17		do flush on standy, do flush on ATA < ATA6
+ *			fix wcache setup.
  */
 
-#define IDEDISK_VERSION	"1.12"
+#define IDEDISK_VERSION	"1.17"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -49,6 +60,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+
+#define _IDE_DISK
+
 #include <linux/ide.h>
 
 #include <asm/byteorder.h>
@@ -56,48 +70,27 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
-#else
-#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
-#endif
+/* FIXME: some day we shouldnt need to look in here! */
 
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  undef __TASKFILE__IO /* define __TASKFILE__IO */
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
+#include "legacy/pdc4030.h"
 
-#ifndef __TASKFILE__IO
+static int driver_blocked;
 
-static void idedisk_bswap_data (void *buffer, int wcount)
+static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
-
-static 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);
+#if 0
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
+#else
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+#endif
 }
 
-#endif /* __TASKFILE__IO */
+static int idedisk_end_request(ide_drive_t *drive, int uptodate);
 
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
@@ -127,7 +120,7 @@
 	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
 	    id->sectors == 63 &&
 	    (id->heads == 15 || id->heads == 16) &&
-	    id->lba_capacity >= 16383*63*id->heads)
+	    (id->lba_capacity >= 16383*63*id->heads))
 		return 1;
 
 	lba_sects   = id->lba_capacity;
@@ -149,31 +142,30 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-#ifndef __TASKFILE__IO
+#ifndef CONFIG_IDE_TASKFILE_IO
 
 /*
  * 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;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 i = 0, nsect	= 0, msect = drive->mult_count;
 	struct request *rq;
+	unsigned long flags;
+	u8 stat;
 	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat=hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "read_intr", stat);
+			return DRIVER(drive)->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) {
@@ -183,22 +175,29 @@
 	} else
 		nsect = 1;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	taskfile_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));
+		idedisk_end_request(drive, 1);
+	/*
+	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
+	 * If passed back up on multimode read, BAD DATA could be ACKED
+	 * to FILE SYSTEMS above ...
+	 */
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
                 return ide_started;
 	}
         return ide_stopped;
@@ -209,13 +208,16 @@
  */
 static ide_startstop_t write_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-
-	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);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= hwgroup->rq;
+	u32 i = 0;
+	u8 stat;
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			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",
@@ -228,20 +230,21 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
+				idedisk_end_request(drive, 1);
 			if (i > 0) {
 				unsigned long flags;
 				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
+				taskfile_output_data(drive, to, SECTOR_WORDS);
 				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
                         return ide_stopped;
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "write_intr", stat);
+	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
 
 /*
@@ -254,22 +257,27 @@
  * 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!
+ *
+ * The update and return to BH is a BLOCK Layer Fakey to get more data
+ * to satisfy the hardware atomic segment.  If the hardware atomic segment
+ * is shorter or smaller than the BH segment then we should be OKAY.
+ * This is only valid if we can rewind the rq->current_nr_sectors counter.
  */
 int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
+ 	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;
@@ -285,6 +293,7 @@
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
 				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer             = bh->b_data;
 			}
 		}
 
@@ -292,7 +301,7 @@
 		 * Ok, we're all setup for the interrupt
 		 * re-entering us on the last transfer.
 		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
+		taskfile_output_data(drive, buffer, nsect<<7);
 		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
@@ -304,12 +313,14 @@
  */
 static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= &hwgroup->wrq;
+	u32 i = 0;
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			/*
 			 *	The drive wants data. Remember rq is the copy
@@ -318,7 +329,7 @@
 			if (rq->nr_sectors) {
 				if (ide_multwrite(drive, drive->mult_count))
 					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+				ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
 		} else {
@@ -328,256 +339,49 @@
 			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
-				for (i = rq->nr_sectors; i > 0;){
+				for (i = rq->nr_sectors; i > 0;) {
 					i -= rq->current_nr_sectors;
-					ide_end_request(1, hwgroup);
+					idedisk_end_request(drive, 1);
 				}
 				return ide_stopped;
 			}
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "multwrite_intr", stat);
+	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
-#endif /* __TASKFILE__IO */
 
-#ifdef __TASKFILE__IO
-
-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);
 
 /*
- * do_rw_disk() issues READ and WRITE commands to a disk,
+ * __ide_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 do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	if (rq->cmd == READ)
-		goto good_command;
-	if (rq->cmd == WRITE)
-		goto good_command;
-
-	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
-
-good_command:
-
-#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 */
-
-	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);
-
-	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
-	return chs_rw_disk(drive, rq, (unsigned long) block);
-}
-
-static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
-{
-	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
-
-#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;
-}
-
-static ide_startstop_t chs_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;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-	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));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_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;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==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
-
-	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;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_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;
-
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==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
-
-	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);
-}
-
-/*
- * 268435455  == 137439 MB or 28bit limit
- * 320173056  == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
 
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+ide_startstop_t __ide_do_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;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	hobfile.sector_count	= (rq->nr_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;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+	ata_nsector_t		nsectors;
 
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==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
+	nsectors.all		= (u16) rq->nr_sectors;
 
-	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 (driver_blocked)
+		panic("Request while ide driver is blocked?");
 
-	return do_rw_taskfile(drive, &args);
-}
-
-#else /* !__TASKFILE__IO */
-/*
- * 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 do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+		hwif->OUTB(drive->ctl, IDE_CONTROL_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 */
-
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+		if (drive->addressing == 1) {
 			task_ioreg_t tasklets[10];
 
 			tasklets[0] = 0;
 			tasklets[1] = 0;
-			tasklets[2] = rq->nr_sectors;
-			tasklets[3] = (rq->nr_sectors>>8);
-			if (rq->nr_sectors == 65536) {
-				tasklets[2] = 0x00;
-				tasklets[3] = 0x00;
-			}
+			tasklets[2] = nsectors.b.low;
+			tasklets[3] = nsectors.b.high;
 			tasklets[4] = (task_ioreg_t) block;
 			tasklets[5] = (task_ioreg_t) (block>>8);
 			tasklets[6] = (task_ioreg_t) (block>>16);
@@ -587,7 +391,8 @@
 //			tasklets[8] = (task_ioreg_t) (block>>32);
 //			tasklets[9] = (task_ioreg_t) (block>>40);
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
+				"buffer=0x%08lx, LBAsect=0x%012lx\n",
 				drive->name,
 				(rq->cmd==READ)?"read":"writ",
 				block,
@@ -599,87 +404,88 @@
 				tasklets[9], tasklets[8], tasklets[7],
 				tasklets[6], tasklets[5], tasklets[4]);
 #endif
-			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
-
-			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
-			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
+
+			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
 		} else {
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+				"buffer=0x%08lx\n",
 				drive->name, (rq->cmd==READ)?"read":"writ",
-				block, rq->nr_sectors, (unsigned long) rq->buffer);
+				block, rq->nr_sectors,
+				(unsigned long) rq->buffer);
 #endif
-			OUT_BYTE(0x00, IDE_FEATURE_REG);
-			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-			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);
+			hwif->OUTB(0x00, IDE_FEATURE_REG);
+			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			hwif->OUTB(block, IDE_SECTOR_REG);
+			hwif->OUTB(block>>=8, IDE_LCYL_REG);
+			hwif->OUTB(block>>=8, IDE_HCYL_REG);
+			hwif->OUTB(((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);
+		hwif->OUTB(sect, IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
 
-		OUT_BYTE(0x00, IDE_FEATURE_REG);
-		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-		OUT_BYTE(cyl,IDE_LCYL_REG);
-		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+		hwif->OUTB(0x00, IDE_FEATURE_REG);
+		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		hwif->OUTB(cyl, IDE_LCYL_REG);
+		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+		hwif->OUTB(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->cmd==READ)?"read":"writ", cyl,
 			head, sect, rq->nr_sectors, (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->cmd == READ) {
+
+	if (rq_data_dir(rq) == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+		if (drive->using_dma && !hwif->ide_dma_read(drive))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		}
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTREAD_EXT : WIN_MULTREAD) :
+			   ((lba48) ? WIN_READ_EXT : WIN_READ));
+	
+		ide_execute_command(drive, command, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
-	}
-	if (rq->cmd == WRITE) {
+	} else 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)))
+		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
-		} else {
-			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,
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) :
+			   ((lba48) ? WIN_WRITE_EXT : WIN_WRITE));
+		hwif->OUTB(command, 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 */
+			local_irq_disable();
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	/*
@@ -690,6 +496,8 @@
 	 * before returning.  Fortunately, this NEVER happens (right?).
 	 *
 	 * Except when you get an error it seems...
+	 *
+	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
 	 */
 			hwgroup->wrq = *rq; /* scratchpad */
 			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
@@ -703,65 +511,268 @@
 			}
 		} else {
 			unsigned long flags;
-			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);
+			char *to = ide_map_buffer(rq, &flags);
+			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+			taskfile_output_data(drive, to, SECTOR_WORDS);
+			ide_unmap_buffer(to, &flags);
 		}
 		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
+	idedisk_end_request(drive, 0);
 	return ide_stopped;
 }
 
-#endif /* __TASKFILE__IO */
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long);
+
+/*
+ * __ide_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.
+ */
+ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	if (!blk_fs_request(rq)) {
+		printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+		idedisk_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	/*
+	 * 268435455  == 137439 MB or 28bit limit
+	 *
+	 * need to add split taskfile operations based on 28bit threshold.
+	 */
+
+	if (drive->addressing == 1)		/* 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);
+
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
+}
+
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+
+#if 1
+	lba48bit = (drive->addressing == 1) ? 1 : 0;
+#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;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	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);
+
+	nsectors.all = (u16) rq->nr_sectors;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
+	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
+	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= head;
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	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)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	if (hwif->rw_disk)
+		return hwif->rw_disk(drive, rq, block);
+	else 
+		return __ide_do_rw_disk(drive, rq, block);
+}
+
+EXPORT_SYMBOL_GPL(__ide_do_rw_disk);
 
 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));
-		taskfile.command = WIN_DOORLOCK;
+		ide_task_t args;
+		int cf;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		check_disk_change(inode->i_rdev);
 		/*
 		 * 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_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
+		drive->wcache = 0;
+		/* Cache enabled ? */
+		if (drive->id->csfo & 1)
+			drive->wcache = 1;
+		/* Cache command set available ? */
+		if (drive->id->cfs_enable_1 & (1<<5))
+			drive->wcache = 1;
+		/* ATA6 cache extended commands */
+		cf = drive->id->command_set_2 >> 24;
+		if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0)
+			drive->wcache = 1;
 	}
 	return 0;
 }
 
 static int do_idedisk_flushcache(ide_drive_t *drive);
 
+static int ide_cacheflush_p(ide_drive_t *drive)
+{
+	if(drive->wcache)
+	{
+		if (do_idedisk_flushcache(drive))
+		{
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
+			return -EIO;
+		}
+		return 1;
+	}
+	return 0;
+}
+
 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));
-		taskfile.command = WIN_DOORUNLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		invalidate_bdev(inode->i_bdev, 0);
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, 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);
+	ide_cacheflush_p(drive);
 	MOD_DEC_USE_COUNT;
 }
 
 static int idedisk_media_change (ide_drive_t *drive)
 {
-	return drive->removable;	/* if removable, always assume it was changed */
+	/* if removable, always assume it was changed */
+	return drive->removable;
 }
 
 static void idedisk_revalidate (ide_drive_t *drive)
@@ -771,6 +782,230 @@
 			current_capacity(drive));
 }
 
+static int idedisk_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	u8 err = 0;
+
+	local_irq_set(flags);
+	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 = hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)
+			printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+		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->addressing == 1) {
+				__u64 sectors = 0;
+				u32 low = 0, high = 0;
+				low = idedisk_read_24(drive);
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+				high = idedisk_read_24(drive);
+				sectors = ((__u64)high << 24) | low;
+				printk(", LBAsect=%llu, high=%d, low=%d",
+				       (unsigned long long) sectors,
+				       high, low);
+			} else {
+				u8 cur = hwif->INB(IDE_SELECT_REG);
+				if (cur & 0x40) {	/* using LBA? */
+					printk(", LBAsect=%ld", (unsigned long)
+					 ((cur&0xf)<<24)
+					 |(hwif->INB(IDE_HCYL_REG)<<16)
+					 |(hwif->INB(IDE_LCYL_REG)<<8)
+					 | hwif->INB(IDE_SECTOR_REG));
+				} else {
+					printk(", CHS=%d/%d/%d",
+					 (hwif->INB(IDE_HCYL_REG)<<8) +
+					  hwif->INB(IDE_LCYL_REG),
+					  cur & 0xf,
+					  hwif->INB(IDE_SECTOR_REG));
+				}
+			}
+			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+				printk(", sector=%ld",
+					HWGROUP(drive)->rq->sector);
+		}
+	}
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	local_irq_restore(flags);
+	return err;
+}
+
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	err = idedisk_dump_status(drive, msg, stat);
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	switch (rq->cmd) {
+		case IDE_DRIVE_CMD:
+		case IDE_DRIVE_TASK:
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_drive_cmd(drive, stat, err);
+			return ide_stopped;
+#if 0
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_taskfile(drive, stat, err);
+			return ide_stopped;
+#endif
+		default:
+			break;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else if (stat & ERR_STAT) {
+		/* err has different meaning on cdrom and tape */
+		if (err == ABRT_ERR) {
+			if (drive->select.b.lba &&
+			    /* some newer drives don't support WIN_SPECIFY */
+			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)
+				return ide_stopped;
+		} else if ((err & BAD_CRC) == BAD_CRC) {
+			/* UDMA crc error, just retry the operation */
+			drive->crc_count++;
+		} 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;
+		}
+	}
+	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
+		/*
+		 * 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*.
+		 */
+		while (i > 0) {
+			u32 buffer[16];
+			unsigned int wcount = (i > 16) ? 16 : i;
+			i -= wcount;
+			taskfile_input_data(drive, buffer, wcount);
+		}
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX)
+		DRIVER(drive)->end_request(drive, 0);
+	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;
+}
+
+ide_startstop_t idedisk_abort(ide_drive_t *drive, const char *msg)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	switch (rq->cmd) {
+		case IDE_DRIVE_CMD:
+		case IDE_DRIVE_TASK:
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_drive_cmd(drive, BUSY_STAT, 0);
+			return ide_stopped;
+#if 0
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_taskfile(drive, BUSY_STAT, 0);
+			return ide_stopped;
+#endif
+		default:
+			break;
+	}
+
+	rq->errors |= ERROR_RESET;
+	DRIVER(drive)->end_request(drive, 0);
+	return ide_stopped;
+}
+
 /*
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
@@ -780,16 +1015,11 @@
 	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;
-
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
@@ -814,8 +1044,7 @@
 
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
@@ -851,7 +1080,7 @@
 	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;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
@@ -883,7 +1112,7 @@
 	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;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
@@ -899,6 +1128,8 @@
 	return addr_set;
 }
 
+#endif /* CONFIG_IDEDISK_STROKE */
+
 /*
  * Tests if the drive supports Host Protected Area feature.
  * Returns true if supported, false otherwise.
@@ -906,12 +1137,11 @@
 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);
+	if (flag)
+		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.
@@ -926,6 +1156,7 @@
  * in above order (i.e., if value of higher priority is available,
  * reset will be ignored).
  */
+#define IDE_STROKE_LIMIT	(32000*1024*2)
 static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -937,6 +1168,8 @@
 	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	(void) idedisk_supports_host_protected_area(drive);
+
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
 		drive->head		= drive->bios_head = 255;
@@ -944,7 +1177,7 @@
 		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->select.b.lba	= 1;
 		set_max_ext = idedisk_read_native_max_address_ext(drive);
-		if (set_max_ext > capacity_2) {
+		if (set_max_ext > capacity_2 && capacity_2 > IDE_STROKE_LIMIT) {
 #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);
@@ -955,10 +1188,11 @@
 				drive->id->lba_capacity_2 = capacity_2;
                         }
 #else /* !CONFIG_IDEDISK_STROKE */
-			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+			printk(KERN_INFO "%s: setmax_ext LBA %llu, native  %llu\n",
 				drive->name, set_max_ext, capacity_2);
 #endif /* CONFIG_IDEDISK_STROKE */
 		}
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->bios_cyl		= drive->cyl;
 		drive->capacity48	= capacity_2;
 		drive->capacity		= (unsigned long) capacity_2;
@@ -970,7 +1204,7 @@
 		drive->select.b.lba = 1;
 	}
 
-	if (set_max > capacity) {
+	if (set_max > capacity && capacity > IDE_STROKE_LIMIT) {
 #ifdef CONFIG_IDEDISK_STROKE
 		set_max = idedisk_read_native_max_address(drive);
 		set_max = idedisk_set_max_address(drive, set_max);
@@ -981,7 +1215,7 @@
 			drive->id->lba_capacity = capacity;
 		}
 #else /* !CONFIG_IDEDISK_STROKE */
-		printk("%s: setmax LBA %lu, native  %lu\n",
+		printk(KERN_INFO "%s: setmax LBA %lu, native  %lu\n",
 			drive->name, set_max, capacity);
 #endif /* CONFIG_IDEDISK_STROKE */
 	}
@@ -989,7 +1223,7 @@
 	drive->capacity = capacity;
 
 	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
-                drive->capacity48 = id->lba_capacity_2;
+		drive->capacity48 = id->lba_capacity_2;
 		drive->head = 255;
 		drive->sect = 63;
 		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
@@ -1008,47 +1242,40 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		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);
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
-		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
 		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));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
-		if (drive->id && drive->mult_req > drive->id->max_multsect)
+		if (drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
 		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, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -1078,45 +1305,44 @@
 
 static int smart_enable(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.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;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
-static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+static int get_smart_thresholds(ide_drive_t *drive, u8 *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;
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -1126,7 +1352,7 @@
 	char		*out = page;
 	int		len;
 
-	if (drive->id)
+	if (drive->id_read)
 		len = sprintf(out,"%i\n", drive->id->buf_size / 2);
 	else
 		len = sprintf(out,"(none)\n");
@@ -1185,23 +1411,12 @@
 
 #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)
 {
-#ifdef __TASKFILE__IO
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-
-	if (drive->special.b.set_multmode)
-		return -EBUSY;
-
-	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;
-	drive->mult_req		= arg;
-	drive->special.b.set_multmode = 1;
-	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else /* !__TASKFILE__IO */
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
@@ -1211,7 +1426,6 @@
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif /* __TASKFILE__IO */
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
@@ -1227,57 +1441,112 @@
 
 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;
+	ide_task_t args;
 
 	if (!(drive->id->cfs_enable_2 & 0x3000))
 		return 1;
 
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) ide_raw_taskfile(drive, &args, NULL);
+
 	drive->wcache = arg;
 	return 0;
 }
 
+static int call_idedisk_standby (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= standby;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
 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);
+	return call_idedisk_standby(drive, 0);
+}
+
+static int call_idedisk_suspend (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= suspend;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int do_idedisk_suspend (ide_drive_t *drive)
+{
+	if (drive->suspend_reset)
+		return 1;
+	ide_cacheflush_p(drive);
+	return call_idedisk_suspend(drive, 0);
+}
+
+#if 0
+static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= ckpw;
+	args.command_type			= ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
+#if 0
+if (errno != EIO || args[0] != 0 || args[1] != 0)
+   state = "unknown";
+else
+   state = "sleeping";
+} else {
+   state = (args[2] == 255) ? "active/idle" : "standby";
+#endif
+	return 0;
+}
+
+static int do_idedisk_checkpower (ide_drive_t *drive)
+{
+	return call_idedisk_checkpower(drive, 0);
+}
+#endif
+
+static int do_idedisk_resume (ide_drive_t *drive)
+{
+	if (!drive->suspend_reset)
+		return 1;
+	return 0;
 }
 
 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);
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	if (drive->id->cfs_enable_2 & 0x2400)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+	args.command_type	 		= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, 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;
+	ide_task_t args;
 
-	taskfile.command	= WIN_SETFEATURES;
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+							  SETFEATURES_DIS_AAM;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type = ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -1286,9 +1555,11 @@
 {
 	drive->addressing =  0;
 
+	if (HWIF(drive)->addressing)
+		return 0;
+
 	if (!(drive->id->cfs_enable_2 & 0x0400))
                 return -EIO;
-
 	drive->addressing = arg;
 	return 0;
 }
@@ -1321,23 +1592,41 @@
  	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
+static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
+		struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+HDIO_GET_ADDRESS
+HDIO_SET_ADDRESS
+HDIO_GET_WCACHE
+HDIO_SET_WCACHE
+HDIO_GET_ACOUSTIC
+HDIO_SET_ACOUSTIC
+HDIO_GET_MULTCOUNT
+HDIO_SET_MULTCOUNT
+HDIO_GET_NOWERR
+HDIO_SET_NOWERR
+#endif
+	return -EINVAL;
+}
+
 static void idedisk_setup (ide_drive_t *drive)
 {
 	int i;
 	
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity;
-	
+
 	idedisk_add_settings(drive);
 
-	if (id == NULL)
+	if (drive->id_read == 0)
 		return;
 
 	/*
 	 * CompactFlash cards and their brethern look just like hard drives
 	 * to us, but they are removable and don't have a doorlock mechanism.
 	 */
-	if (drive->removable && !drive_is_flashcard(drive)) {
+	if (drive->removable && !(drive->is_flash)) {
 		/*
 		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
 		 */
@@ -1355,6 +1644,14 @@
 		break;
 	}
 
+#if 1
+	(void) probe_lba_addressing(drive, 1);
+#else
+	/* if using 48-bit addressing bump the request size up */
+	if (probe_lba_addressing(drive, 1))
+		blk_queue_max_sectors(&drive->queue, 2048);
+#endif
+
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
 		drive->cyl     = drive->bios_cyl  = id->cyls;
@@ -1402,41 +1699,30 @@
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
-#ifdef CONFIG_IDEDISK_MULTI_MODE
 		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
 		id->multsect_valid = id->multsect ? 1 : 0;
 		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
 		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
-#else	/* original, pre IDE-NFG, per request of AC */
-		drive->mult_req = INITIAL_MULT_COUNT;
-		if (drive->mult_req > id->max_multsect)
-			drive->mult_req = id->max_multsect;
-		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
-			drive->special.b.set_multmode = 1;
-#endif	/* CONFIG_IDEDISK_MULTI_MODE */
 	}
 	drive->no_io_32bit = id->dword_io ? 1 : 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)
+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);
+	ide_cacheflush_p(drive);
 	return ide_unregister_subdriver(drive);
 }
 
-int idedisk_reinit(ide_drive_t *drive);
+int idedisk_init (void);
+int idedisk_attach(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
@@ -1450,10 +1736,15 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
 	standby:		do_idedisk_standby,
+	suspend:		do_idedisk_suspend,
+	resume:			do_idedisk_resume,
 	flushcache:		do_idedisk_flushcache,
-	do_request:		do_rw_disk,
-	end_request:		NULL,
-	ioctl:			NULL,
+	do_request:		ide_do_rw_disk,
+	end_request:		idedisk_end_request,
+	sense:			idedisk_dump_status,
+	error:			idedisk_error,
+	abort:			idedisk_abort,
+	ioctl:			idedisk_ioctl,
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
@@ -1462,12 +1753,12 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	reinit:			idedisk_reinit,
+	init:			idedisk_init,
+	attach:			idedisk_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idedisk_init (void);
 static ide_module_t idedisk_module = {
 	IDE_DRIVER_MODULE,
 	idedisk_init,
@@ -1477,30 +1768,30 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-int idedisk_reinit (ide_drive_t *drive)
+int idedisk_attach (ide_drive_t *drive)
 {
-	int failed = 0;
+	int ret = 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;
+	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);
+		ret= 1;
+		goto bye_game_over;
 	}
 	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);
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			drive->name, drive->head);
 		(void) idedisk_cleanup(drive);
-		DRIVER(drive)->busy--;
-		return 1;
+		ret= 1;
 	}
 	DRIVER(drive)->busy--;
-	failed--;
-
-	ide_register_module(&idedisk_module);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 static void __exit idedisk_exit (void)
@@ -1508,14 +1799,17 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ide_disk, idedisk_driver.name,
+			&idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
-			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+			printk(KERN_ERR "%s: cleanup_module() called while "
+				"still busy\n", drive->name);
 			failed++;
 		}
-		/* We must remove proc entries defined in this module.
-		   Otherwise we oops while accessing these entries */
 #ifdef CONFIG_PROC_FS
+		/* We must remove proc entries defined in this module.
+		 * Otherwise we oops while accessing these entries
+		 */
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
@@ -1525,19 +1819,28 @@
 
 int idedisk_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	int failed = 0;
-	
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
-		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);
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_disk,
+			idedisk_driver.name, NULL, failed++)) != NULL) {
+		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);
 			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);
+		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;
@@ -1545,11 +1848,85 @@
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	ide_register_module(&idedisk_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+ide_startstop_t panic_box(ide_drive_t *drive)
+{
+#if 0
+	panic("%s: Attempted to corrupt something: ide operation "
+#else
+	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
+#endif
+		"was pending accross suspend/resume.\n", drive->name);
+	return ide_stopped;
+}
+
+int ide_disks_busy(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+		if (!hwgroup) continue;
+		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
+			return 1;
+	}
+	return 0;
+}
+
+void ide_disk_suspend(void)
+{
+	int i;
+	while (ide_disks_busy()) {
+		printk("*");
+		schedule();
+	}
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler_save = hwgroup->handler;
+		hwgroup->handler = panic_box;
+	}
+	driver_blocked = 1;
+	if (ide_disks_busy())
+		panic("How did you get that request through?!");
+}
+
+/* unsuspend and resume should be equal in the ideal world */
+
+void ide_disk_unsuspend(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler = NULL; /* hwgroup->handler_save; */
+		hwgroup->handler_save = NULL;
+	}
+	driver_blocked = 0;
+}
+
+void ide_disk_resume(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		if (hwgroup->handler != panic_box)
+			panic("Handler was not set to panic?");
+		hwgroup->handler_save = NULL;
+		hwgroup->handler = NULL;
+	}
+	driver_blocked = 0;
+}
+
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-dma.c linux-2.4.21-rc3/drivers/ide/ide-dma.c
--- linux-2.4.20/drivers/ide/ide-dma.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-dma.c	2003-05-22 22:06:28.000000000 +0000
@@ -70,14 +70,13 @@
  *
  * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
  *
- * check_drive_lists(ide_drive_t *drive, int good_bad)
- *
  * ATA-66/100 and recovery functions, I forgot the rest......
- * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
  *
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -86,22 +85,12 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed.  Oh the things we forget.  I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+#define CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
@@ -123,7 +112,6 @@
 
 	{ "WDC AC11000H"	,	"ALL"		},
 	{ "WDC AC22100H"	,	"ALL"		},
-	{ "WDC AC31000H"	,	"ALL"		},
 	{ "WDC AC32500H"	,	"ALL"		},
 	{ "WDC AC33100H"	,	"ALL"		},
 	{ "WDC AC31600H"	,	"ALL"		},
@@ -159,11 +147,20 @@
 
 };
 
-int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+/**
+ *	in_drive_list	-	look for drive in black/white list
+ *	@id: drive identifier
+ *	@drive_table: list to inspect
+ *
+ *	Look for a drive in the blacklist and the whitelist tables
+ *	Returns 1 if the drive is found in the table.
+ */
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
 {
 	for ( ; drive_table->id_model ; drive_table++)
 		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		    ((strstr(drive_table->id_firmware, id->fw_rev)) ||
 		     (!strcmp(drive_table->id_firmware, "ALL"))))
 			return 1;
 	return 0;
@@ -203,52 +200,52 @@
 
 #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
-/*
- * Our Physical Region Descriptor (PRD) table should be large enough
- * to handle the biggest I/O request we are likely to see.  Since requests
- * can have no more than 256 sectors, and since the typical blocksize is
- * two or more sectors, we could get by with a limit of 128 entries here for
- * the usual worst case.  Most requests seem to include some contiguous blocks,
- * further reducing the number of table entries required.
- *
- * The driver reverts to PIO mode for individual requests that exceed
- * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
- * 100% of all crazy scenarios here is not necessary.
- *
- * As it turns out though, we must allocate a full 4KB page for this,
- * so the two PRD tables (ide0 & ide1) will each get half of that,
- * allowing each to have about 256 entries (8 bytes each) from this.
- */
-#define PRD_BYTES	8
-#define PRD_ENTRIES	(PAGE_SIZE / (2 * PRD_BYTES))
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
+/**
+ *	ide_dma_intr	-	IDE DMA interrupt handler
+ *	@drive: the drive the interrupt is for
+ *
+ *	Handle an interrupt completing a read/write DMA transfer on an 
+ *	IDE device
  */
+ 
 ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
+	u8 stat = 0, dma_stat = 0;
 	int i;
-	byte stat, dma_stat;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
+	//		rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
 		       drive->name, dma_stat);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+/**
+ *	ide_build_sglist	-	map IDE scatter gather for DMA I/O
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *	@ddir: data direction
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a request via PCI DMA. The lower layers of the
+ *	kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
+static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
@@ -258,66 +255,76 @@
 	if (hwif->sg_dma_active)
 		BUG();
 
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-
 	bh = rq->bh;
 	do {
-		struct scatterlist *sge;
+		int contig = 0;
 
-		/*
-		 * continue segment from before?
-		 */
-		if (bh_phys(bh) == lastdataend) {
+		if (bh->b_page) {
+			if (bh_phys(bh) == lastdataend)
+				contig = 1;
+		} else {
+			if ((unsigned long) bh->b_data == lastdataend)
+				contig = 1;
+		}
+
+		if (contig) {
 			sg[nents - 1].length += bh->b_size;
 			lastdataend += bh->b_size;
 			continue;
 		}
 
-		/*
-		 * start new segment
-		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
+		memset(&sg[nents], 0, sizeof(*sg));
 
 		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
+			sg[nents].page = bh->b_page;
+			sg[nents].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 		} else {
-			if (((unsigned long) bh->b_data) < PAGE_SIZE)
+			if ((unsigned long) bh->b_data < PAGE_SIZE)
 				BUG();
 
-			sge->address = bh->b_data;
+			sg[nents].address = bh->b_data;
+			lastdataend = (unsigned long) bh->b_data + bh->b_size;
 		}
 
-		sge->length = bh->b_size;
-		lastdataend = bh_phys(bh) + bh->b_size;
+		sg[nents].length = bh->b_size;
 		nents++;
 	} while ((bh = bh->b_reqnext) != NULL);
 
-	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+	if(nents == 0)
+		BUG();
+		
+	hwif->sg_dma_direction = ddir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
 }
 
+/**
+ *	ide_raw_build_sglist	-	map IDE scatter gather for DMA
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a taskfile request via PCI DMA. The lower layers 
+ *	of the  kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
 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;
-	unsigned char *virt_addr = rq->buffer;
+	u8 *virt_addr = rq->buffer;
 	int sector_count = rq->nr_sectors;
 
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
 	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;
@@ -330,37 +337,54 @@
 	sg[nents].address = virt_addr;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
-   
+#else
+        while (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.
- * May also be invoked from trm290.c
- */
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
-{
-	unsigned int *table = HWIF(drive)->dmatable_cpu;
-#ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
-#else
-	const int is_trm290_chipset = 0;
-#endif
+/**
+ *	ide_build_dmatable	-	build IDE DMA table
+ *
+ *	ide_build_dmatable() prepares a dma request. We map the command
+ *	to get the pci bus addresses of the buffers and then build up
+ *	the PRD table that the IDE layer wants to be fed. The code
+ *	knows about the 64K wrap bug in the CS5530.
+ *
+ *	Returns 0 if all went okay, returns 1 otherwise.
+ *	May also be invoked from trm290.c
+ */
+ 
+int ide_build_dmatable (ide_drive_t *drive, struct request *rq, int ddir)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned int *table	= hwif->dmatable_cpu;
+	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
 	unsigned int count = 0;
 	int i;
 	struct scatterlist *sg;
 
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, rq);
 	else
-		HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_build_sglist(hwif, rq, ddir);
 
 	if (!i)
 		return 0;
 
-	sg = HWIF(drive)->sg_table;
-	while (i) {
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -374,35 +398,36 @@
 		 */
 
 		while (cur_len) {
-			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-			
-			if (count++ >= PRD_ENTRIES)
-				BUG();
+			if (count++ >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
 
-			if (bcount > cur_len)
-				bcount = cur_len;
-			*table++ = cpu_to_le32(cur_addr);
-			xcount = bcount & 0xffff;
-			if (is_trm290_chipset)
-				xcount = ((xcount >> 2) - 1) << 16;
-			if (xcount == 0x0000) {
-				/* 
-				 * Most chipsets correctly interpret a length
-				 * of 0x0000 as 64KB, but at least one
-				 * (e.g. CS5530) misinterprets it as zero (!).
-				 * So here we break the 64KB entry into two
-				 * 32KB entries instead.
-				 */
-				if (count++ >= PRD_ENTRIES)
-					goto use_pio_instead;
-
-				*table++ = cpu_to_le32(0x8000);
-				*table++ = cpu_to_le32(cur_addr + 0x8000);
-				xcount = 0x8000;
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xffff;
+				if (is_trm290)
+					xcount = ((xcount >> 2) - 1) << 16;
+				if (xcount == 0x0000) {
+	/* 
+	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+	 * but at least one (e.g. CS5530) misinterprets it as zero (!).
+	 * So here we break the 64KB entry into two 32KB entries instead.
+	 */
+					if (count++ >= PRD_ENTRIES) {
+						printk("%s: DMA table too small\n", drive->name);
+						goto use_pio_instead;
+					}
+					*table++ = cpu_to_le32(0x8000);
+					*table++ = cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
 			}
-			*table++ = cpu_to_le32(xcount);
-			cur_addr += bcount;
-			cur_len -= bcount;
 		}
 
 		sg++;
@@ -410,21 +435,33 @@
 	}
 
 	if (count) {
-		if (!is_trm290_chipset)
+		if (!is_trm290)
 			*--table |= cpu_to_le32(0x80000000);
 		return count;
 	}
 	printk("%s: empty DMA table?\n", drive->name);
 use_pio_instead:
-	pci_unmap_sg(HWIF(drive)->pci_dev,
-		     HWIF(drive)->sg_table,
-		     HWIF(drive)->sg_nents,
-		     HWIF(drive)->sg_dma_direction);
-	HWIF(drive)->sg_dma_active = 0;
+	pci_unmap_sg(hwif->pci_dev,
+		     hwif->sg_table,
+		     hwif->sg_nents,
+		     hwif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
 	return 0; /* revert to PIO for this request */
 }
 
-/* Teardown mappings after DMA has completed.  */
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ *	ide_destroy_dmatable	-	clean up DMA mapping
+ *	@drive: The drive to unmap
+ *
+ *	Teardown mappings after DMA has completed. This must be called
+ *	after the completion of each use of ide_build_dmatable and before
+ *	the next use of ide_build_dmatable. Failure to do so will cause
+ *	an oops as only one mapping can be live for each target at a given
+ *	time.
+ */
+ 
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
 	struct pci_dev *dev = HWIF(drive)->pci_dev;
@@ -435,336 +472,505 @@
 	HWIF(drive)->sg_dma_active = 0;
 }
 
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+
+/**
+ *	config_drive_for_dma	-	attempt to activate IDE DMA
+ *	@drive: the drive to place in DMA mode
+ *
+ *	If the drive supports at least mode 2 DMA or UDMA of any kind
+ *	then attempt to place it into DMA mode. Drives that are known to
+ *	support DMA but predate the DMA properties or that are known
+ *	to have DMA handling bugs are also set up appropriately based
+ *	on the good/bad drive lists.
  */
-int check_drive_lists (ide_drive_t *drive, int good_bad)
+ 
+static int config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
 
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	const char **list;
+	if ((id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			return hwif->ide_dma_off(drive);
+
+		/*
+		 * Enable DMA on any drive that has
+		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+		 */
+		if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+			return hwif->ide_dma_on(drive);
+		/*
+		 * Enable DMA on any drive that has mode2 DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2)	/* regular DMA */
+			if ((id->dma_mword & 0x404) == 0x404 ||
+			    (id->dma_1word & 0x404) == 0x404)
+				return hwif->ide_dma_on(drive);
 
-	if (good_bad) {
 		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
 	}
-#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	return 0;
+//	if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
+	return hwif->ide_dma_off_quietly(drive);
 }
 
-int report_drive_dmaing (ide_drive_t *drive)
+/**
+ *	dma_timer_expiry	-	handle a DMA timeout
+ *	@drive: Drive that timed out
+ *
+ *	An IDE DMA transfer timed out. In the event of an error we ask
+ *	the driver to resolve the problem, if a DMA transfer is still
+ *	in progress we continue to wait (arguably we need to add a 
+ *	secondary 'I dont care what the drive thinks' timeout here)
+ *	Finally if we have an interrupt but for some reason got the
+ *	timeout first we complete the I/O. This can occur if an 
+ *	interrupt is lost or due to bugs.
+ */
+ 
+static int dma_timer_expiry (ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (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) {
-			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4) {
-		printk(", (U)DMA");	/* Can be BIOS-enabled! */
-	} else {
-		printk(", DMA");
+	printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
+		drive->name, dma_stat);
+
+	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
+		return WAIT_CMD;
+
+	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+
+	/* 1 dmaing, 2 error, 4 intr */
+	
+	if (dma_stat & 2) {	/* ERROR */
+		(void) hwif->ide_dma_end(drive);
+		return DRIVER(drive)->error(drive,
+			"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
 	}
-	return 1;
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+
+	if (dma_stat & 4)	/* Got an Interrupt */
+		HWGROUP(drive)->handler(drive);
+
+	return 0;
 }
 
-static int config_drive_for_dma (ide_drive_t *drive)
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Perform the generic IDE controller DMA off operation. This
+ *	works for most IDE bus mastering controllers
+ */
+
+int __ide_dma_host_off (ide_drive_t *drive)
 {
-	int config_allows_dma = 1;
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->media != ide_disk)
-		config_allows_dma = 0;
-#endif
+	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	return 0;
+}
 
-	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);
+EXPORT_SYMBOL(__ide_dma_host_off);
 
-		/* 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))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Consult the list of known "good" drives */
-		if (ide_dmaproc(ide_dma_good_drive, drive))
-			return hwif->dmaproc(ide_dma_on, drive);
+/**
+ *	__ide_dma_host_off_quietly	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. 
+ */
+
+int __ide_dma_off_quietly (ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	ide_toggle_bounce(drive, 0);
+	return HWIF(drive)->ide_dma_host_off(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. Inform the
+ *	user that DMA has been disabled. 
+ */
+
+int __ide_dma_off (ide_drive_t *drive)
+{
+	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off);
+
+/**
+ *	__ide_dma_host_on	-	Enable DMA on a host
+ *	@drive: drive to enable for DMA
+ *
+ *	Enable DMA on an IDE controller following generic bus mastering
+ *	IDE controller behaviour
+ */
+ 
+int __ide_dma_host_on (ide_drive_t *drive)
+{
+	if (drive->using_dma) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u8 unit			= (drive->select.b.unit & 0x01);
+		u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+		return 0;
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+	return 1;
 }
 
-#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-/*
- * 1 dmaing, 2 error, 4 intr
+EXPORT_SYMBOL(__ide_dma_host_on);
+
+/**
+ *	__ide_dma_on		-	Enable DMA on a device
+ *	@drive: drive to enable DMA on
+ *
+ *	Enable IDE DMA for a device on this IDE controller.
  */
-static int dma_timer_expiry (ide_drive_t *drive)
+ 
+int __ide_dma_on (ide_drive_t *drive)
 {
-	byte dma_stat = inb(HWIF(drive)->dma_base+2);
+	drive->using_dma = 1;
+	ide_toggle_bounce(drive, 1);
+	return HWIF(drive)->ide_dma_host_on(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_on);
 
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif /* DEBUG */
+/**
+ *	__ide_dma_check		-	check DMA setup
+ *	@drive: drive to check
+ *
+ *	Don't use - due for extermination
+ */
+ 
+int __ide_dma_check (ide_drive_t *drive)
+{
+	return config_drive_for_dma(drive);
+}
 
+EXPORT_SYMBOL(__ide_dma_check);
+
+int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 1 << 3;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
 #if 0
-	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #endif
+	/* issue cmd to drive */
+	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+	return HWIF(drive)->ide_dma_count(drive);
+}
 
-	if (dma_stat & 2) {	/* ERROR */
-		byte stat = GET_STAT();
-		return ide_error(drive, "dma_timer_expiry", stat);
+EXPORT_SYMBOL(__ide_dma_read);
+
+int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 0;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_write);
+
+int __ide_dma_begin (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+	/* 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.
+	 */
+	/* start DMA */
+	hwif->OUTB(dma_cmd|1, hwif->dma_command);
 	return 0;
 }
-#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive)
+
+EXPORT_SYMBOL(__ide_dma_begin);
+
+/* returns 1 on error, 0 otherwise */
+int __ide_dma_end (ide_drive_t *drive)
 {
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	ide_hwif_t *hwif	= HWIF(drive);
-	int enable_dma		= drive->using_dma;
-	unsigned long flags;
-	ide_startstop_t startstop;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	u8 dma_stat = 0, dma_cmd = 0;
 
 	drive->waiting_for_dma = 0;
+	/* get dma_command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd&~1, hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
 
-	startstop = ide_do_reset(drive);
+EXPORT_SYMBOL(__ide_dma_end);
 
-	if ((enable_dma) && !(drive->using_dma))
-		(void) hwif->dmaproc(ide_dma_on, drive);
+/* returns 1 if dma irq issued, 0 otherwise */
+int __ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	return startstop;
+#if 0  /* do not set unless you know what you are doing */
+	if (dma_stat & 4) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+	}
+#endif
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+			drive->name, __FUNCTION__);
+#if 0
+	drive->waiting_for_dma++;
+#endif
+	return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
-static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+EXPORT_SYMBOL(__ide_dma_test_irq);
 
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
+int __ide_dma_bad_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist) {
+		printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "bad" drives */
+	list = bad_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model)) {
+			printk("%s: Disabling (U)DMA for %s\n",
+				drive->name, id->model);
+			return 1;
+		}
 	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+int __ide_dma_good_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	blk_queue_bounce_limit(&drive->queue, addr);
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	return in_drive_list(id, drive_whitelist);
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "good" drives */
+	list = good_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model))
+			return 1;
+	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
 }
 
+EXPORT_SYMBOL(__ide_dma_good_drive);
+
 /*
- * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * ide_dma_begin afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- * May also be invoked from trm290.c
- */
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-//	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	ide_hwif_t *hwif		= HWIF(drive);
-	unsigned long dma_base		= hwif->dma_base;
-	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading = 0, set_high = 1;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_off:
-			printk("%s: DMA disabled\n", drive->name);
-		case ide_dma_off_quietly:
-			set_high = 0;
-			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-		case ide_dma_on:
-			drive->using_dma = (func == ide_dma_on);
-			if (drive->using_dma)
-				outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-			ide_toggle_bounce(drive, set_high);
-			return 0;
-		case ide_dma_check:
-			return config_drive_for_dma (drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			SELECT_READ_WRITE(hwif,drive,func);
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			outb(reading, dma_base);			/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);		/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			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 */
-			if ((HWGROUP(drive)->rq->cmd == IDE_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);
+ * Used for HOST FIFO counters for VDMA
+ * PIO over DMA, effective ATA-Bridge operator.
+ */
+int __ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_count);
+
+int __ide_dma_verbose (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (id->field_valid & 4) {
+		if ((id->dma_ultra >> 8) && (id->dma_mword >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
+			if (((id->dma_ultra >> 11) & 0x1F) &&
+			    eighty_ninty_three(drive)) {
+				if ((id->dma_ultra >> 15) & 1) {
+					printk(", UDMA(mode 7)");
+				} else if ((id->dma_ultra >> 14) & 1) {
+					printk(", UDMA(133)");
+				} else if ((id->dma_ultra >> 13) & 1) {
+					printk(", UDMA(100)");
+				} else if ((id->dma_ultra >> 12) & 1) {
+					printk(", UDMA(66)");
+				} else if ((id->dma_ultra >> 11) & 1) {
+					printk(", UDMA(44)");
+				} else
+					goto mode_two;
 			} 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.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			outb(inb(dma_base)|1, dma_base);		/* start DMA */
-			return 0;
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);	/* purge DMA mappings */
-			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 (dma_stat & 4) {
-				byte stat = GET_STAT();
-				outb(dma_base+2, dma_stat & 0xE4);
+		mode_two:
+				if ((id->dma_ultra >> 10) & 1) {
+					printk(", UDMA(33)");
+				} else if ((id->dma_ultra >> 9) & 1) {
+					printk(", UDMA(25)");
+				} else if ((id->dma_ultra >> 8) & 1) {
+					printk(", UDMA(16)");
+				}
 			}
-#endif
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_bad_drive:
-		case ide_dma_good_drive:
-			return check_drive_lists(drive, (func == ide_dma_good_drive));
-		case ide_dma_verbose:
-			return report_drive_dmaing(drive);
-		case ide_dma_timeout:
-			// FIXME: Many IDE chipsets do not permit command file register access
-			// FIXME: while the bus-master function is still active.
-			// FIXME: To prevent deadlock with those chipsets, we must be extremely
-			// FIXME: careful here (and in ide_intr() as well) to NOT access any
-			// FIXME: registers from the 0x1Fx/0x17x sets before terminating the
-			// FIXME: bus-master operation via the bus-master control reg.
-			// FIXME: Otherwise, chipset deadlock will occur, and some systems will
-			// FIXME: lock up completely!!
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			/*
-			 * Have to issue an abort and requeue the request
-			 * DMA engine got turned off by a goofy ASIC, and
-			 * we have to clean up the mess, and here is as good
-			 * as any.  Do it globally for all chipsets.
-			 */
-			outb(0x00, dma_base);		/* stop DMA */
-			dma_stat = inb(dma_base+2);	/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			printk("%s: %s: Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			if (dma_stat & 0xF0)
-				return ide_dma_timeout_revovery(drive);
-
-			printk("%s: %s: (restart_request) Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				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:
-			printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-			return 1;
-		default:
-			printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-			return 1;
+		} else {
+			printk(", (U)DMA");	/* Can be BIOS-enabled! */
+		}
+	} else if (id->field_valid & 2) {
+		if ((id->dma_mword >> 8) && (id->dma_1word >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		printk(", DMA");
+	} else if (id->field_valid & 1) {
+		printk(", BUG");
 	}
+	return 1;
 }
 
+EXPORT_SYMBOL(__ide_dma_verbose);
+
+/**
+ *	__ide_dma_retune	-	default retune handler
+ *	@drive: drive to retune
+ *
+ *	Default behaviour when we decide to return the IDE DMA setup.
+ *	The default behaviour is "we don't"
+ */
+ 
+int __ide_dma_retune (ide_drive_t *drive)
+{
+	printk(KERN_WARNING "%s: chipset supported call only\n", __FUNCTION__);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_retune);
+
+int __ide_dma_lostirq (ide_drive_t *drive)
+{
+	printk("%s: DMA interrupt recovery\n", drive->name);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_lostirq);
+
+int __ide_dma_timeout (ide_drive_t *drive)
+{
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	if (HWIF(drive)->ide_dma_test_irq(drive))
+		return 0;
+	return HWIF(drive)->ide_dma_end(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_timeout);
+
 /*
  * Needed for allowing full modular support of ide-driver
  */
-int ide_release_dma (ide_hwif_t *hwif)
+int ide_release_dma_engine (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
 		pci_free_consistent(hwif->pci_dev,
@@ -777,128 +983,206 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
+	return 1;
+}
+
+int ide_release_mmio_dma (ide_hwif_t *hwif)
+{
+	if ((hwif->dma_extra) && (hwif->channel == 0))
+		release_mem_region((hwif->dma_base + 16), hwif->dma_extra);
+	release_mem_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_mem_region(hwif->dma_base, 8);
+	return 1;
+}
+
+int ide_release_iomio_dma (ide_hwif_t *hwif)
+{
 	if ((hwif->dma_extra) && (hwif->channel == 0))
 		release_region((hwif->dma_base + 16), hwif->dma_extra);
 	release_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_region(hwif->dma_base, 8);
 	return 1;
 }
 
 /*
- *	This can be called for a dynamically installed interface. Don't __init it
+ * Needed for allowing full modular support of ide-driver
  */
- 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+int ide_release_dma (ide_hwif_t *hwif)
 {
-	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
-	if (check_region(dma_base, num_ports)) {
-		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
-		return;
-	}
-	request_region(dma_base, num_ports, hwif->name);
-	hwif->dma_base = dma_base;
-	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
-						    PRD_ENTRIES * PRD_BYTES,
-						    &hwif->dmatable_dma);
-	if (hwif->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
+	if (hwif->chipset == ide_etrax100)
+		return 1;
+
+	ide_release_dma_engine(hwif);
+	if (hwif->mmio)
+		return ide_release_mmio_dma(hwif);
+	return ide_release_iomio_dma(hwif);
+}
 
+int ide_allocate_dma_engine (ide_hwif_t *hwif)
+{
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &hwif->dmatable_dma);
 	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (hwif->sg_table == NULL) {
-		pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
-		goto dma_alloc_failure;
-	}
+				GFP_KERNEL);
 
-	hwif->dmaproc = &ide_dmaproc;
+	if ((hwif->dmatable_cpu) && (hwif->sg_table))
+		return 0;
 
-	if (hwif->chipset != ide_trm290) {
-		byte dma_stat = inb(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	printk(KERN_ERR "%s: -- Error, unable to allocate%s%s table(s).\n",
+		(hwif->dmatable_cpu == NULL) ? " CPU" : "",
+		(hwif->sg_table == NULL) ?  " SG DMA" : " DMA",
+		hwif->cds->name);
+
+	ide_release_dma_engine(hwif);
+	return 1;
+}
+
+int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: MMIO-DMA at 0x%08lx-0x%08lx",
+		hwif->name, base, base + ports - 1);
+	if (check_mem_region(base, ports)) {
+		printk(" -- Error, MMIO ports already in use.\n");
+		return 1;
 	}
-	printk("\n");
-	return;
+	request_mem_region(base, ports, hwif->name);
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!check_mem_region(hwif->dma_base2, ports))
+			request_mem_region(hwif->dma_base2, ports, hwif->name);
+	}
+	return 0;
+}
 
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+int ide_iomio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
+		hwif->name, base, base + ports - 1);
+	if (!request_region(base, ports, hwif->name)) {
+		printk(" -- Error, ports in use.\n");
+		return 1;
+	}
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!request_region(hwif->dma_base2, ports, hwif->name))
+		{
+			printk(" -- Error, secondary ports in use.\n");
+			release_region(base, ports);
+			return 1;
+		}
+	}
+	return 0;
 }
 
 /*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ * 
  */
-unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
+int ide_dma_iobase (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
 {
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
+	if (hwif->mmio)
+		return ide_mmio_dma(hwif, base, ports);
+	return ide_iomio_dma(hwif, base, ports);
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (hwif->mate && hwif->mate->dma_base) {
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-	} else {
-		dma_base = pci_resource_start(dev, 4);
-		if (!dma_base) {
-			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
-			dma_base = 0;
-		}
-	}
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+	if (ide_dma_iobase(hwif, dma_base, num_ports))
+		return;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	if ((!dma_base) && (!second_chance)) {
-		unsigned long set_bmiba = 0;
-		second_chance++;
-		switch(dev->vendor) {
-			case PCI_VENDOR_ID_AL:
-				set_bmiba = DEFAULT_BMALIBA; break;
-			case PCI_VENDOR_ID_VIA:
-				set_bmiba = DEFAULT_BMCRBA; break;
-			case PCI_VENDOR_ID_INTEL:
-				set_bmiba = DEFAULT_BMIBA; break;
-			default:
-				return dma_base;
-		}
-		pci_write_config_dword(dev, 0x20, set_bmiba|1);
-		goto second_chance_to_dma;
+	if (ide_allocate_dma_engine(hwif)) {
+		ide_release_dma(hwif);
+		return;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
 
-	if (dma_base) {
-		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
-			request_region(dma_base+16, extra, name);
-		dma_base += hwif->channel ? 8 : 0;
-		hwif->dma_extra = extra;
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AMD_VIPER_7409:
-			case PCI_DEVICE_ID_CMD_643:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
-				if (inb(dma_base+2) & 0x80) {
-					printk("%s: simplex device: DMA forced\n", name);
-				}
-				break;
-			default:
-				/*
-				 * If the device claims "simplex" DMA,
-				 * this means only one of the two interfaces
-				 * can be trusted with DMA at any point in time.
-				 * So we should enable DMA only on one of the
-				 * two interfaces.
-				 */
-				if ((inb(dma_base+2) & 0x80)) {	/* simplex device? */
-					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					    (hwif->mate && hwif->mate->dma_base)) {
-						printk("%s: simplex device:  DMA disabled\n", name);
-						dma_base = 0;
-					}
-				}
-		}
+	if (!(hwif->dma_command))
+		hwif->dma_command	= hwif->dma_base;
+	if (!(hwif->dma_vendor1))
+		hwif->dma_vendor1	= (hwif->dma_base + 1);
+	if (!(hwif->dma_status))
+		hwif->dma_status	= (hwif->dma_base + 2);
+	if (!(hwif->dma_vendor3))
+		hwif->dma_vendor3	= (hwif->dma_base + 3);
+	if (!(hwif->dma_prdtable))
+		hwif->dma_prdtable	= (hwif->dma_base + 4);
+
+	if (!hwif->ide_dma_off)
+		hwif->ide_dma_off = &__ide_dma_off;
+	if (!hwif->ide_dma_off_quietly)
+		hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+	if (!hwif->ide_dma_host_off)
+		hwif->ide_dma_host_off = &__ide_dma_host_off;
+	if (!hwif->ide_dma_on)
+		hwif->ide_dma_on = &__ide_dma_on;
+	if (!hwif->ide_dma_host_on)
+		hwif->ide_dma_host_on = &__ide_dma_host_on;
+	if (!hwif->ide_dma_check)
+		hwif->ide_dma_check = &__ide_dma_check;
+	if (!hwif->ide_dma_read)
+		hwif->ide_dma_read = &__ide_dma_read;
+	if (!hwif->ide_dma_write)
+		hwif->ide_dma_write = &__ide_dma_write;
+	if (!hwif->ide_dma_count)
+		hwif->ide_dma_count = &__ide_dma_count;
+	if (!hwif->ide_dma_begin)
+		hwif->ide_dma_begin = &__ide_dma_begin;
+	if (!hwif->ide_dma_end)
+		hwif->ide_dma_end = &__ide_dma_end;
+	if (!hwif->ide_dma_test_irq)
+		hwif->ide_dma_test_irq = &__ide_dma_test_irq;
+	if (!hwif->ide_dma_bad_drive)
+		hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
+	if (!hwif->ide_dma_good_drive)
+		hwif->ide_dma_good_drive = &__ide_dma_good_drive;
+	if (!hwif->ide_dma_verbose)
+		hwif->ide_dma_verbose = &__ide_dma_verbose;
+	if (!hwif->ide_dma_timeout)
+		hwif->ide_dma_timeout = &__ide_dma_timeout;
+	if (!hwif->ide_dma_retune)
+		hwif->ide_dma_retune = &__ide_dma_retune;
+	if (!hwif->ide_dma_lostirq)
+		hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+	if (hwif->chipset != ide_trm290) {
+		u8 dma_stat = hwif->INB(hwif->dma_status);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 	}
-	return dma_base;
+	printk("\n");
+
+	if (!(hwif->dma_master))
+		BUG();
 }
+
+EXPORT_SYMBOL_GPL(ide_setup_dma);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-features.c linux-2.4.21-rc3/drivers/ide/ide-features.c
--- linux-2.4.20/drivers/ide/ide-features.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-features.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/*
- * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
- *
- *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *  
- *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- *  Extracts if ide.c to address the evolving transfer rate code for
- *  the SETFEATURES_XFER callouts.  Various parts of any given function
- *  are credited to previous ATA-IDE maintainers.
- *
- *  Auto-CRC downgrade for Ultra DMA(ing)
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#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>
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-char *ide_xfer_verbose (byte xfer_rate)
-{
-	switch(xfer_rate) {
-		case XFER_UDMA_7:	return("UDMA 7");
-		case XFER_UDMA_6:	return("UDMA 6");
-		case XFER_UDMA_5:	return("UDMA 5");
-		case XFER_UDMA_4:	return("UDMA 4");
-		case XFER_UDMA_3:	return("UDMA 3");
-		case XFER_UDMA_2:	return("UDMA 2");
-		case XFER_UDMA_1:	return("UDMA 1");
-		case XFER_UDMA_0:	return("UDMA 0");
-		case XFER_MW_DMA_2:	return("MW DMA 2");
-		case XFER_MW_DMA_1:	return("MW DMA 1");
-		case XFER_MW_DMA_0:	return("MW DMA 0");
-		case XFER_SW_DMA_2:	return("SW DMA 2");
-		case XFER_SW_DMA_1:	return("SW DMA 1");
-		case XFER_SW_DMA_0:	return("SW DMA 0");
-		case XFER_PIO_4:	return("PIO 4");
-		case XFER_PIO_3:	return("PIO 3");
-		case XFER_PIO_2:	return("PIO 2");
-		case XFER_PIO_1:	return("PIO 1");
-		case XFER_PIO_0:	return("PIO 0");
-		case XFER_PIO_SLOW:	return("PIO SLOW");
-		default:		return("XFER ERROR");
-	}
-}
-
-/*
- *
- */
-char *ide_media_verbose (ide_drive_t *drive)
-{
-	switch (drive->media) {
-		case ide_scsi:		return("scsi   ");
-		case ide_disk:		return("disk   ");
-		case ide_optical:	return("optical");
-		case ide_cdrom:		return("cdrom  ");
-		case ide_tape:		return("tape   ");
-		case ide_floppy:	return("floppy ");
-		default:		return("???????");
-	}
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
-{
-	switch (dmafunc) {
-		case ide_dma_read:		return("ide_dma_read");
-		case ide_dma_write:		return("ide_dma_write");
-		case ide_dma_begin:		return("ide_dma_begin");
-		case ide_dma_end:		return("ide_dma_end:");
-		case ide_dma_check:		return("ide_dma_check");
-		case ide_dma_on:		return("ide_dma_on");
-		case ide_dma_off:		return("ide_dma_off");
-		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
-		case ide_dma_test_irq:		return("ide_dma_test_irq");
-		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
-		case ide_dma_good_drive:	return("ide_dma_good_drive");
-		case ide_dma_verbose:		return("ide_dma_verbose");
-		case ide_dma_retune:		return("ide_dma_retune");
-		case ide_dma_lostirq:		return("ide_dma_lostirq");
-		case ide_dma_timeout:		return("ide_dma_timeout");
-		default:			return("unknown");
-	}
-}
-
-/*
- *
- */
-byte ide_auto_reduce_xfer (ide_drive_t *drive)
-{
-	if (!drive->crc_count)
-		return drive->current_speed;
-	drive->crc_count = 0;
-
-	switch(drive->current_speed) {
-		case XFER_UDMA_7:	return XFER_UDMA_6;
-		case XFER_UDMA_6:	return XFER_UDMA_5;
-		case XFER_UDMA_5:	return XFER_UDMA_4;
-		case XFER_UDMA_4:	return XFER_UDMA_3;
-		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:
-		default:		return XFER_PIO_4;
-	}
-}
-
-/*
- * Update the 
- */
-int ide_driveid_update (ide_drive_t *drive)
-{
-	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
-	 */
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
-
-	SELECT_MASK(HWIF(drive), drive, 1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	ide_delay_50ms();
-	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			SELECT_MASK(HWIF(drive), drive, 0);
-			return 0;	/* drive timed-out */
-		}
-		ide_delay_50ms();	/* give drive a breather */
-	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
-	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
-	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(HWIF(drive), drive, 0);
-		printk("%s: CHECK for good STATUS\n", drive->name);
-		return 0;
-	}
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(HWIF(drive), drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		__restore_flags(flags);	/* local CPU only */
-		return 0;
-	}
-	ide_input_data(drive, id, SECTOR_WORDS);
-	(void) GET_STAT();	/* clear drive IRQ */
-	ide__sti();		/* local CPU only */
-	__restore_flags(flags);	/* local CPU only */
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
-	}
-
-	return 1;
-}
-
-/*
- * Verify that we are doing an approved SETFEATURES_XFER with respect
- * to the hardware being able to support request.  Since some hardware
- * can improperly report capabilties, we check to see if the host adapter
- * in combination with the device (usually a disk) properly detect
- * and acknowledge each end of the ribbon.
- */
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
-{
-	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;
-		}
-#ifndef CONFIG_IDEDMA_IVB
-		if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-		if (((drive->id->hw_config & 0x2000) == 0) ||
-		    ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
- */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
-{
-	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))
-		return 1;
-
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *  All hosts that use the 80c ribbon mus use!
- */
-byte eighty_ninty_three (ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (HWIF(drive)->pci_devid.vid==0x105a)
-	    return(HWIF(drive)->udma_four);
-#endif
-	/* PDC202XX: that's because some HDD will return wrong info */
-	return ((byte) ((HWIF(drive)->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-			(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-			(drive->id->hw_config & 0x6000)) ? 1 : 0);
-}
-#endif // CONFIG_BLK_DEV_IDEDMA
-
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int	i, error = 1;
-	byte stat;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	byte unit = (drive->select.b.unit & 0x01);
-	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	udelay(1);
-	/*
-	 * Wait for drive to become non-BUSY
-	 */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		unsigned long flags, timeout;
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only -- for jiffies */
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout))
-				break;
-		}
-		__restore_flags(flags); /* local CPU only */
-	}
-
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-			error = 0;
-			break;
-		}
-	}
-
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	enable_irq(hwif->irq);
-
-	if (error) {
-		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
-		return error;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	if (speed > XFER_PIO_4) {
-		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-	} else {
-		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-	return error;
-}
-
-EXPORT_SYMBOL(ide_auto_reduce_xfer);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_ata66_check);
-EXPORT_SYMBOL(set_transfer);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(eighty_ninty_three);
-#endif // CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(ide_config_drive_speed);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-floppy.c linux-2.4.21-rc3/drivers/ide/ide-floppy.c
--- linux-2.4.20/drivers/ide/ide-floppy.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-floppy.c	2003-05-22 22:06:38.000000000 +0000
@@ -153,10 +153,10 @@
 	char *b_data;				/* Pointer which runs on the buffers */
 	int b_count;				/* Missing/Available data on the current buffer */
 	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idefloppy_pc_t;
 
@@ -272,29 +272,41 @@
 typedef struct {
 	ide_drive_t *drive;
 
-	idefloppy_pc_t *pc;			/* Current packet command */
-	idefloppy_pc_t *failed_pc; 		/* Last failed packet command */
-	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idefloppy_pc_t *pc;
+	/* Last failed packet command */
+	idefloppy_pc_t *failed_pc;
+	/* Packet command stack */
+	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDEFLOPPY_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
-	byte ticks;		/* delay this long before sending packet command */
+	u8 sense_key, asc, ascq;
+	/* delay this long before sending packet command */
+	u8 ticks;
 	int progress_indication;
 
 	/*
 	 *	Device information
 	 */
-	int blocks, block_size, bs_factor;			/* Current format */
-	idefloppy_capacity_descriptor_t capacity;		/* Last format capacity */
-	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
-	int wp;							/* Write protect */
-	int srfp;			/* Supports format progress report */
-	unsigned long flags;			/* Status/Action flags */
+	/* Current format */
+	int blocks, block_size, bs_factor;
+	/* Last format capacity */
+	idefloppy_capacity_descriptor_t capacity;
+	/* Copy of the flexible disk page */
+	idefloppy_flexible_disk_page_t flexible_disk_page;
+	/* Write protect */
+	int wp;
+	/* Supports format progress report */
+	int srfp;
+	/* Status/Action flags */
+	unsigned long flags;
 } idefloppy_floppy_t;
 
 #define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
@@ -349,20 +361,20 @@
 /*
  *	Special requests for our block device strategy routine.
  */
-#define	IDEFLOPPY_FIRST_RQ		90
+#define	IDEFLOPPY_FIRST_RQ	90
 
 /*
  * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
  */
-#define	IDEFLOPPY_PC_RQ			90
+#define	IDEFLOPPY_PC_RQ		90
 
-#define IDEFLOPPY_LAST_RQ		90
+#define IDEFLOPPY_LAST_RQ	90
 
 /*
  *	A macro which can be used to check if a given request command
  *	originated in the driver or in the buffer cache layer.
  */
-#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
 
 /*
  *	Error codes which are returned in rq->errors to the higher part
@@ -371,170 +383,6 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bsy		:1;	/* The device has access to the command block */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned check		:1;	/* Error occurred */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned ili		:1;	/* Illegal Length Indication */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA or PIO */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	:6;	/* Reserved */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_ireason_reg_t;
-
-/*
- *	ATAPI floppy Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned sam_lun	:3;	/* Logical unit number */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned one7		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned sam_lun	:3;	/* Logical unit number */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved4567	:4;	/* Reserved */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned zero0		:1;	/* Should be set to zero */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_control_reg_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -668,32 +516,61 @@
 static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 #if IDEFLOPPY_DEBUG_BUGS
 static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
+
+static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
 /*
- *	idefloppy_end_request is used to finish servicing a request.
+ *	idefloppy_do_end_request is used to finish servicing a request.
  *
  *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_end_request\n");
+	printk(KERN_INFO "Reached idefloppy_end_request\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -705,13 +582,16 @@
 		floppy->failed_pc = NULL;
 	/* Why does this happen? */
 	if (!rq)
-		return;
-	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		return 0;
+	if (!IDEFLOPPY_RQ_CMD(rq->cmd)) {
+		/* our real local end request function */
+		idefloppy_end_request(drive, uptodate);
+		return 0;
 	}
 	rq->errors = error;
-	ide_end_drive_cmd (drive, 0, 0);
+	/* fixme: need to move this local also */
+	ide_end_drive_cmd(drive, 0, 0);
+	return 0;
 }
 
 static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
@@ -724,18 +604,21 @@
 		if (pc->b_count == bh->b_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL)
 				pc->b_count = 0;
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
-			idefloppy_discard_data (drive, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_input_buffers, bcount == %d\n",
+				drive->name, bcount);
+			idefloppy_discard_data(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (bh->b_size - pc->b_count, bcount);
-		atapi_input_bytes (drive, bh->b_data + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDEFLOPPY_MIN(bh->b_size - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 	}
 }
 
@@ -749,20 +632,24 @@
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL) {
 				pc->b_data = bh->b_data;
 				pc->b_count = bh->b_size;
 			}
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_output_buffers, bcount == %d\n",
+				drive->name, bcount);
 			idefloppy_write_zeros (drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		count = IDEFLOPPY_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 	}
 }
 
@@ -773,7 +660,7 @@
 	struct buffer_head *bh = rq->bh;
 
 	while ((bh = rq->bh) != NULL)
-		idefloppy_end_request (1, HWGROUP(drive));
+		idefloppy_do_end_request(drive, 1);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -784,17 +671,17 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
+	ide_init_drive_cmd(rq);
+	rq->buffer = (char *)pc;
 	rq->cmd = IDEFLOPPY_PC_RQ;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->pc_stack_index==IDEFLOPPY_PC_STACK)
+	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
 		floppy->pc_stack_index=0;
 	return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
@@ -803,8 +690,8 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->rq_stack_index==IDEFLOPPY_PC_STACK)
-		floppy->rq_stack_index=0;
+	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
+		floppy->rq_stack_index = 0;
 	return (&floppy->rq_stack[floppy->rq_stack_index++]);
 }
 
@@ -816,14 +703,20 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv[0] & 0x80 ?
-		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+	floppy->sense_key = result->sense_key;
+	floppy->asc = result->asc;
+	floppy->ascq = result->ascq;
+	floppy->progress_indication = result->sksv[0] & 0x80 ?
+		(u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
-		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
+			result->sense_key, result->asc, result->ascq);
 	else
-		printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
+			"ascq = %x\n", result->sense_key,
+			result->asc, result->ascq);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
@@ -832,14 +725,14 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
+	printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_end_request (1,HWGROUP (drive));
+		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request (0,HWGROUP (drive));
+		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idefloppy_do_end_request(drive, 0);
 	}
 }
 
@@ -851,10 +744,10 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
+	printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
 }
 
 /*
@@ -862,7 +755,7 @@
  */
 static void idefloppy_init_pc (idefloppy_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -874,7 +767,7 @@
 
 static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);	
+	idefloppy_init_pc(pc);	
 	pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
 	pc->c[4] = 255;
 	pc->request_transfer = 18;
@@ -890,13 +783,13 @@
 {
 	idefloppy_pc_t *pc;
 	struct request *rq;
-	idefloppy_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
-	pc = idefloppy_next_pc_storage (drive);
-	rq = idefloppy_next_rq_storage (drive);
-	idefloppy_create_request_sense_cmd (pc);
-	idefloppy_queue_pc_head (drive, pc, rq);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	pc = idefloppy_next_pc_storage(drive);
+	rq = idefloppy_next_rq_storage(drive);
+	idefloppy_create_request_sense_cmd(pc);
+	idefloppy_queue_pc_head(drive, pc, rq);
 }
 
 /*
@@ -906,24 +799,25 @@
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_status_reg_t status;
-	idefloppy_bcount_reg_t bcount;
-	idefloppy_ireason_reg_t ireason;
-	idefloppy_pc_t *pc=floppy->pc;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
+	idefloppy_pc_t *pc = floppy->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+		__FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */	
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
-			set_bit (PC_DMA_ERROR, &pc->flags);
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
+			set_bit(PC_DMA_ERROR, &pc->flags);
 		} else {
-			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers (drive, pc);
+			pc->actually_transferred = pc->request_transfer;
+			idefloppy_update_buffers(drive, pc);
 		}
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
@@ -931,83 +825,116 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 #if IDEFLOPPY_DEBUG_LOG
-		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+		printk(KERN_INFO "Packet command completed, %d bytes "
+			"transferred\n", pc->actually_transferred);
 #endif /* IDEFLOPPY_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
+			printk(KERN_INFO "ide-floppy: %s: I/O error\n",
+				drive->name);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-floppy: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
-			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ide_stopped; /* queued, but not started */
+			/* Retry operation */
+			idefloppy_retry_pc(drive);
+			/* queued, but not started */
+			return ide_stopped;
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
-			floppy->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
+			floppy->failed_pc = NULL;
+		/* Command finished - Call the callback function */
+		pc->callback(drive);
 		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-floppy: The floppy wants to issue "
+			"more interrupts in DMA mode\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "but the floppy wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
-				idefloppy_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-floppy: The floppy wants "
+					"to send us more data than expected "
+					"- discarding data\n");
+				idefloppy_discard_data(drive,bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idefloppy_pc_intr,
+						IDEFLOPPY_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-floppy: The floppy wants to "
+				"send us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_output_buffers (drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_input_buffers (drive, pc, bcount.all);
+			idefloppy_input_buffers(drive, pc, bcount.all);
 	}
-	pc->actually_transferred+=bcount.all;				/* Update the current position */
-	pc->current_position+=bcount.all;
-
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -1020,19 +947,25 @@
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_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");
+	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);
+	ireason.all = HWIF(drive)->INB(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);
-	}
-	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
 	return ide_started;
 }
 
@@ -1053,35 +986,42 @@
 {
 	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 */
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+	/* Timeout for the packet command */
+	return IDEFLOPPY_WAIT_CMD;
 }
 
 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;
+	atapi_ireason_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");
+	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);
+	ireason.all = HWIF(drive)->INB(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);
+		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.
+	 * 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, 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, 
 	  &idefloppy_pc_intr, 		/* service routine for packet command */
-	  floppy->ticks,			/* wait this long before "failing" */
+	  floppy->ticks,		/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 	return ide_started;
 }
@@ -1092,81 +1032,106 @@
 static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	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) {
-		printk (KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
+	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
-	if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-		floppy->failed_pc=pc;
-	floppy->pc=pc;							/* Set the current packet command */
+	if (floppy->failed_pc == NULL &&
+	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+		floppy->failed_pc = pc;
+	/* Set the current packet command */
+	floppy->pc = pc;
 
-	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received.
 		 */
-		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
-				;
-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+		if (!test_bit(PC_ABORT, &pc->flags)) {
+			if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
+				printk(KERN_ERR "ide-floppy: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						drive->name, pc->c[0],
+						floppy->sense_key,
+						floppy->asc, floppy->ascq);
 			}
-			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDEFLOPPY_ERROR_GENERAL;
 		}
-		floppy->failed_pc=NULL;
+		floppy->failed_pc = NULL;
 		pc->callback(drive);
 		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Retry number - %d\n",pc->retries);
+	printk (KERN_INFO "Retry number - %d\n", pc->retries);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	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_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	feature.all = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(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);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(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));
+	if (feature.b.dma) {	/* Begin DMA, if necessary */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 #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 */
+	if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		/* wait */
+		pkt_xfer_routine = &idefloppy_transfer_pc1;
 	} else {
-		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+		/* immediate */
+		pkt_xfer_routine = &idefloppy_transfer_pc;
 	}
 	
-	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+	if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+		/* Issue the packet command */
+		ide_execute_command(drive, WIN_PACKETCMD, 
+				pkt_xfer_routine,
+				IDEFLOPPY_WAIT_CMD,
+				NULL);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*pkt_xfer_routine) (drive);
 	}
 }
@@ -1177,24 +1142,25 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, 1);
 	return;
 }
 
 static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
 {
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent);
+	printk(KERN_INFO "ide-floppy: creating prevent removal command, "
+		"prevent = %d\n", prevent);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
 	pc->c[4] = prevent;
 }
 
 static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
@@ -1204,13 +1170,13 @@
 static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
 					      int flags)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
 	pc->c[1] = 0x17;
 
 	memset(pc->buffer, 0, 12);
 	pc->buffer[1] = 0xA2;
-	/* Default format list header, byte 1: FOV/DCRT/IMM bits set */
+	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
 
 	if (flags & 1)				/* Verify bit on... */
 		pc->buffer[1] ^= 0x20;		/* ... turn off DCRT bit */
@@ -1225,11 +1191,11 @@
 /*
  *	A mode sense command is used to "sense" floppy parameters.
  */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, byte page_code, byte type)
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
 {
-	unsigned short length = sizeof (idefloppy_mode_parameter_header_t);
+	u16 length = sizeof(idefloppy_mode_parameter_header_t);
 	
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
 	pc->c[1] = 0;
 	pc->c[2] = page_code + (type << 6);
@@ -1242,15 +1208,16 @@
 			length += 32;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported page code in create_mode_sense_cmd\n");
+			printk(KERN_ERR "ide-floppy: unsupported page code "
+				"in create_mode_sense_cmd\n");
 	}
-	put_unaligned (htons (length), (unsigned short *) &pc->c[7]);
+	put_unaligned(htons(length), (u16 *) &pc->c[7]);
 	pc->request_transfer = length;
 }
 
 static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_START_STOP_CMD;
 	pc->c[4] = start;
 }
@@ -1267,28 +1234,29 @@
 	int blocks = rq->nr_sectors / floppy->bs_factor;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
-		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
+	printk("create_rw1%d_cmd: block == %d, blocks == %d\n",
+		2 * test_bit(IDEFLOPPY_USE_READ12, &floppy->flags),
+		block, blocks);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
-	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
+	idefloppy_init_pc(pc);
+	if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
-		put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]);
+		put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
 	} else {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
+		put_unaligned(htons(blocks), (u16 *) &pc->c[7]);
 	}
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[2]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
 	pc->callback = &idefloppy_rw_callback;
 	pc->rq = rq;
 	pc->b_data = rq->buffer;
 	pc->b_count = rq->cmd == READ ? 0 : rq->bh->b_size;
 	if (rq->cmd == WRITE)
-		set_bit (PC_WRITING, &pc->flags);
+		set_bit(PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-	set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+	set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
@@ -1300,40 +1268,49 @@
 	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+			"current_nr_sectors: %ld\n", rq->sector,
+			rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc != NULL)
-			printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+			printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+					" key = %2x, asc = %2x, ascq = %2x\n",
+				drive->name, floppy->failed_pc->c[0],
+				floppy->sense_key, floppy->asc, floppy->ascq);
 		else
-			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-		idefloppy_end_request (0, HWGROUP(drive));
+			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+				drive->name);
+		idefloppy_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
 		case WRITE:
-			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-				printk ("%s: unsupported r/w request size\n", drive->name);
-				idefloppy_end_request (0, HWGROUP(drive));
+			if (rq->sector % floppy->bs_factor ||
+			    rq->nr_sectors % floppy->bs_factor) {
+				printk("%s: unsupported r/w request size\n",
+					drive->name);
+				idefloppy_do_end_request(drive, 0);
 				return ide_stopped;
 			}
-			pc = idefloppy_next_pc_storage (drive);
-			idefloppy_create_rw_cmd (floppy, pc, rq, block);
+			pc = idefloppy_next_pc_storage(drive);
+			idefloppy_create_rw_cmd(floppy, pc, rq, block);
 			break;
 		case IDEFLOPPY_PC_RQ:
 			pc = (idefloppy_pc_t *) rq->buffer;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
-			idefloppy_end_request (0,HWGROUP (drive));
+			printk(KERN_ERR "ide-floppy: unsupported command %x"
+				" in request queue\n", rq->cmd);
+			idefloppy_do_end_request(drive, 0);
 			return ide_stopped;
 	}
 	pc->rq = rq;
-	return idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
@@ -1344,10 +1321,10 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDEFLOPPY_PC_RQ;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
@@ -1362,23 +1339,26 @@
 	idefloppy_flexible_disk_page_t *page;
 	int capacity, lba_capacity;
 
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get flexible disk page parameters\n");
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get flexible disk "
+			"page parameters\n");
 		return 1;
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
-	page->transfer_rate = ntohs (page->transfer_rate);
-	page->sector_size = ntohs (page->sector_size);
-	page->cyls = ntohs (page->cyls);
-	page->rpm = ntohs (page->rpm);
+	page->transfer_rate = ntohs(page->transfer_rate);
+	page->sector_size = ntohs(page->sector_size);
+	page->cyls = ntohs(page->cyls);
+	page->rpm = ntohs(page->rpm);
 	capacity = page->cyls * page->heads * page->sectors * page->sector_size;
 	if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
-		printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
-			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
+		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+				"%d sector size, %d rpm\n",
+			drive->name, capacity / 1024, page->cyls,
+			page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 
 	floppy->flexible_disk_page = *page;
@@ -1387,8 +1367,8 @@
 	drive->bios_sect = page->sectors;
 	lba_capacity = floppy->blocks * floppy->block_size;
 	if (capacity < lba_capacity) {
-		printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
-			"but the drive only handles %d\n",
+		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
 	}
@@ -1402,18 +1382,18 @@
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_capabilities_page_t *page;
 
-	floppy->srfp=0;
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+	floppy->srfp = 0;
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
 						 MODE_SENSE_CURRENT);
 
 	set_bit(PC_SUPPRESS_ERROR, &pc.flags);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
 		return 1;
 	}
 
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	page= (idefloppy_capabilities_page_t *)(header+1);
-	floppy->srfp=page->srfp;
+	floppy->srfp = page->srfp;
 	return (0);
 }
 
@@ -1434,58 +1414,76 @@
 	floppy->blocks = floppy->bs_factor = 0;
 	drive->part[0].nr_sects = 0;
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 		return 1;
 	}
 	header = (idefloppy_capacity_header_t *) pc.buffer;
-	descriptors = header->length / sizeof (idefloppy_capacity_descriptor_t);
+	descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
 	for (i = 0; i < descriptors; i++, descriptor++) {
-                blocks = descriptor->blocks = ntohl (descriptor->blocks);
-                length = descriptor->length = ntohs (descriptor->length);
+		blocks = descriptor->blocks = ntohl(descriptor->blocks);
+		length = descriptor->length = ntohs(descriptor->length);
 
 		if (!i) 
 		{
-          	switch (descriptor->dc) {
-                case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */
-                        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-                                break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */
-                case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */
-                        if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
-                                printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
-                        floppy->capacity = *descriptor;
-                        if (!length || length % 512)
-                                printk (KERN_NOTICE "%s: %d bytes block size not supported\n", drive->name, length);
-                        else {
+		switch (descriptor->dc) {
+		/* Clik! drive returns this instead of CAPACITY_CURRENT */
+		case CAPACITY_UNFORMATTED:
+			if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+                                /*
+				 * If it is not a clik drive, break out
+				 * (maintains previous driver behaviour)
+				 */
+				break;
+		case CAPACITY_CURRENT:
+			/* Normal Zip/LS-120 disks */
+			if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+				printk(KERN_INFO "%s: %dkB, %d blocks, %d "
+					"sector size\n", drive->name,
+					blocks * length / 1024, blocks, length);
+			floppy->capacity = *descriptor;
+			if (!length || length % 512) {
+				printk(KERN_NOTICE "%s: %d bytes block size "
+					"not supported\n", drive->name, length);
+			} else {
                                 floppy->blocks = blocks;
                                 floppy->block_size = length;
                                 if ((floppy->bs_factor = length / 512) != 1)
-                                        printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name);
+                                        printk(KERN_NOTICE "%s: warning: non "
+						"512 bytes block size not "
+						"fully supported\n",
+						drive->name);
                                 rc = 0;
-                        }
-                        break;
-                case CAPACITY_NO_CARTRIDGE:
-                        /* This is a KERN_ERR so it appears on screen for the user to see */
-                        printk (KERN_ERR "%s: No disk in drive\n", drive->name);
-                                        break;
-                case CAPACITY_INVALID:
-                        printk (KERN_ERR "%s: Invalid capacity for disk in drive\n", drive->name);
-                                        break;
+			}
+			break;
+		case CAPACITY_NO_CARTRIDGE:
+			/*
+			 * This is a KERN_ERR so it appears on screen
+			 * for the user to see
+			 */
+			printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+			break;
+		case CAPACITY_INVALID:
+			printk(KERN_ERR "%s: Invalid capacity for disk "
+				"in drive\n", drive->name);
+			break;
 		}
 		}
 		if (!i) {
-		IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", descriptor->dc);
+			IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n",
+				descriptor->dc);
 		}
-		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length);
+		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d "
+			"sector size\n", i, blocks * length / 1024, blocks,
+			length);
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-	{
-		(void) idefloppy_get_flexible_disk_page (drive);
+        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
 	drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor;
@@ -1532,18 +1530,18 @@
 	if (u_array_size <= 0)
 		return (-EINVAL);
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                 return (-EIO);
         }
         header = (idefloppy_capacity_header_t *) pc.buffer;
         descriptors = header->length /
-		sizeof (idefloppy_capacity_descriptor_t);
+		sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
-	u_index=0;
-	argp=arg+1;
+	u_index = 0;
+	argp = arg + 1;
 
 	/*
 	** We always skip the first capacity descriptor.  That's the
@@ -1551,18 +1549,17 @@
 	** the formattable capacities.
 	*/
 
-	for (i=0; i<descriptors; i++, descriptor++)
-	{
+	for (i=0; i<descriptors; i++, descriptor++) {
 		if (u_index >= u_array_size)
 			break;	/* User-supplied buffer too small */
 		if (i == 0)
 			continue;	/* Skip the first descriptor */
 
-		blocks = ntohl (descriptor->blocks);
-		length = ntohs (descriptor->length);
+		blocks = ntohl(descriptor->blocks);
+		length = ntohs(descriptor->length);
 
 		if (put_user(blocks, argp))
-			return (-EFAULT);
+			return(-EFAULT);
 		++argp;
 
 		if (put_user(length, argp))
@@ -1603,19 +1600,19 @@
 	int flags;
 	idefloppy_pc_t pc;
 
-	if (get_user(blocks, arg)
-	    || get_user(length, arg+1)
-	    || get_user(flags, arg+2))
-	{
+	if (get_user(blocks, arg) ||
+	    get_user(length, arg+1) ||
+	    get_user(flags, arg+2)) {
 		return (-EFAULT);
 	}
 
-	(void) idefloppy_get_capability_page (drive);	/* Get the SFRP bit */
+	/* Get the SFRP bit */
+	(void) idefloppy_get_capability_page(drive);
 	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-	if (idefloppy_queue_pc_tail (drive, &pc))
-	{
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
                 return (-EIO);
-        }
+	}
+
 	return (0);
 }
 
@@ -1636,35 +1633,30 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t pc;
-	int progress_indication=0x10000;
+	int progress_indication = 0x10000;
 
-	if (floppy->srfp)
-	{
+	if (floppy->srfp) {
 		idefloppy_create_request_sense_cmd(&pc);
-		if (idefloppy_queue_pc_tail (drive, &pc))
-		{
+		if (idefloppy_queue_pc_tail(drive, &pc)) {
 			return (-EIO);
 		}
 
-		if (floppy->sense_key == 2 && floppy->asc == 4 &&
-		    floppy->ascq == 4)
-		{
-			progress_indication=floppy->progress_indication;
+		if (floppy->sense_key == 2 &&
+		    floppy->asc == 4 &&
+		    floppy->ascq == 4) {
+			progress_indication = floppy->progress_indication;
 		}
 		/* Else assume format_unit has finished, and we're
 		** at 0x10000 */
-	}
-	else
-	{
-		idefloppy_status_reg_t status;
+	} else {
+		atapi_status_t status;
 		unsigned long flags;
 
-		__save_flags(flags);
-		__cli();
-		status.all=GET_STAT();
-		__restore_flags(flags);
+		local_irq_save(flags);
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
 
-		progress_indication= !status.b.dsc ? 0:0x10000;
+		progress_indication = !status.b.dsc ? 0 : 0x10000;
 	}
 	if (put_user(progress_indication, arg))
 		return (-EFAULT);
@@ -1694,12 +1686,12 @@
 
 		/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, prevent);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, prevent);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		if (cmd == CDROMEJECT) {
-			idefloppy_create_start_stop_cmd (&pc, 2);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 2);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		return 0;
 	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
@@ -1715,16 +1707,13 @@
 		{
 			idefloppy_floppy_t *floppy = drive->driver_data;
 
-			if (drive->usage > 1)
-			{
+			if (drive->usage > 1) {
 				/* Don't format if someone is using the disk */
 
 				clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
 					  &floppy->flags);
 				return -EBUSY;
-			}
-			else
-			{
+			} else {
 				int rc;
 
 				set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
@@ -1763,7 +1752,7 @@
 	idefloppy_pc_t pc;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_open\n");
+	printk(KERN_INFO "Reached idefloppy_open\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	MOD_INC_USE_COUNT;
@@ -1773,8 +1762,8 @@
 
 		idefloppy_create_test_unit_ready_cmd(&pc);
 		if (idefloppy_queue_pc_tail(drive, &pc)) {
-			idefloppy_create_start_stop_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		if (idefloppy_get_capacity (drive)
@@ -1795,16 +1784,14 @@
 			MOD_DEC_USE_COUNT;
 			return -EROFS;
 		}		
-		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		check_disk_change(inode->i_rdev);
-	}
-	else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags))
-	{
+	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1823,12 +1810,12 @@
 	if (!drive->usage) {
 		idefloppy_floppy_t *floppy = drive->driver_data;
 
-		invalidate_bdev (inode->i_bdev, 0);
+		invalidate_bdev(inode->i_bdev, 0);
 
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 0);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 0);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
@@ -1843,7 +1830,7 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
-	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+	return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
@@ -1875,109 +1862,114 @@
 {
 	struct idefloppy_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
-	unsigned short mask,i;
+	u16 mask,i;
 	char buffer[80];
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
-	*((unsigned short *) &gcw) = id->config;
+	*((u16 *) &gcw) = id->config;
 
 #ifdef CONFIG_PPC
 	/* kludge for Apple PowerBook internal zip */
-	if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
-	    && strstr(id->model, "ZIP"))
+	if ((gcw.device_type == 5) &&
+	    !strstr(id->model, "CD-ROM") &&
+	    strstr(id->model, "ZIP"))
 		gcw.device_type = 0;			
 #endif
 
 #if IDEFLOPPY_DEBUG_INFO
-	printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
+	printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
 	switch (gcw.protocol) {
-		case 0: case 1: sprintf (buffer, "ATA");break;
-		case 2:	sprintf (buffer, "ATAPI");break;
-		case 3: sprintf (buffer, "Reserved (Unknown to ide-floppy)");break;
+		case 0: case 1: sprintf(buffer, "ATA");break;
+		case 2:	sprintf(buffer, "ATAPI");break;
+		case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
 	}
-	printk (KERN_INFO "Protocol Type: %s\n", buffer);
+	printk(KERN_INFO "Protocol Type: %s\n", buffer);
 	switch (gcw.device_type) {
-		case 0: sprintf (buffer, "Direct-access Device");break;
-		case 1: sprintf (buffer, "Streaming Tape Device");break;
+		case 0: sprintf(buffer, "Direct-access Device");break;
+		case 1: sprintf(buffer, "Streaming Tape Device");break;
 		case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
-		case 5: sprintf (buffer, "CD-ROM Device");break;
-		case 6: sprintf (buffer, "Reserved");
-		case 7: sprintf (buffer, "Optical memory Device");break;
-		case 0x1f: sprintf (buffer, "Unknown or no Device type");break;
-		default: sprintf (buffer, "Reserved");
+		case 5: sprintf(buffer, "CD-ROM Device");break;
+		case 6: sprintf(buffer, "Reserved");
+		case 7: sprintf(buffer, "Optical memory Device");break;
+		case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
+		default: sprintf(buffer, "Reserved");
 	}
-	printk (KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
-	printk (KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
+	printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
+	printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
 	switch (gcw.drq_type) {
-		case 0: sprintf (buffer, "Microprocessor DRQ");break;
-		case 1: sprintf (buffer, "Interrupt DRQ");break;
-		case 2: sprintf (buffer, "Accelerated DRQ");break;
-		case 3: sprintf (buffer, "Reserved");break;
+		case 0: sprintf(buffer, "Microprocessor DRQ");break;
+		case 1: sprintf(buffer, "Interrupt DRQ");break;
+		case 2: sprintf(buffer, "Accelerated DRQ");break;
+		case 3: sprintf(buffer, "Reserved");break;
 	}
-	printk (KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
+	printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
 	switch (gcw.packet_size) {
-		case 0: sprintf (buffer, "12 bytes");break;
-		case 1: sprintf (buffer, "16 bytes");break;
-		default: sprintf (buffer, "Reserved");break;
-	}
-	printk (KERN_INFO "Command Packet Size: %s\n", buffer);
-	printk (KERN_INFO "Model: %.40s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "Single Word DMA supported modes:\n");
+		case 0: sprintf(buffer, "12 bytes");break;
+		case 1: sprintf(buffer, "16 bytes");break;
+		default: sprintf(buffer, "Reserved");break;
+	}
+	printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+	printk(KERN_INFO "Model: %.40s\n",id->model);
+	printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "Single Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_1word & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_1word & (mask << 8)) ? " (active)" : "");
 	}
-	printk (KERN_INFO "Multi Word DMA supported modes:\n");
+	printk(KERN_INFO "Multi Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_mword & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_mword & (mask << 8)) ? " (active)" : "");
 	}
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		if (id->eide_dma_min == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_min);
-		printk (KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_min);
+		printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
 		if (id->eide_dma_time == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_time);
-		printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_time);
+		printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
 		if (id->eide_pio == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio);
-		printk (KERN_INFO "Minimum PIO cycle without IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio);
+		printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+			buffer);
 		if (id->eide_pio_iordy == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio_iordy);
-		printk (KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio_iordy);
+		printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
 	} else
-		printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
 	if (gcw.protocol != 2)
-		printk (KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 0)
-		printk (KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+		printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-floppy: The removable flag is not set\n");
+		printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
 	else if (gcw.drq_type == 3) {
-		printk (KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+		printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
 	} else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
 	} else
 		return 1;
 	return 0;
@@ -1999,7 +1991,6 @@
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
 	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
-
 }
 
 /*
@@ -2011,14 +2002,14 @@
 	int major = HWIF(drive)->major, i;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	*((unsigned short *) &gcw) = drive->id->config;
+	*((u16 *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
 	drive->ready_stat = 0;
-	memset (floppy, 0, sizeof (idefloppy_floppy_t));
+	memset(floppy, 0, sizeof(idefloppy_floppy_t));
 	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
-		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
 	/*
 	 *	We used to check revisions here. At this point however
 	 *	I'm giving up. Just assume they are all broken, its easier.
@@ -2030,8 +2021,7 @@
 	 *	we'll leave the limitation below for the 2.2.x tree.
 	 */
 
-	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
-	{
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) {
 		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
 		/* This value will be visible in the /proc/ide/hdx/settings */
 		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
@@ -2044,15 +2034,14 @@
 	*      above fix.  It makes nasty clicking noises without
 	*      it, so please don't remove this.
 	*/
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
-	{
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
 
-	(void) idefloppy_get_capacity (drive);
+	(void) idefloppy_get_capacity(drive);
 	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		ide_hwif_t *hwif = HWIF(drive);
@@ -2069,10 +2058,11 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
+
 	drive->driver_data = NULL;
-	kfree (floppy);
+	kfree(floppy);
 	return 0;
 }
 
@@ -2089,7 +2079,8 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-int idefloppy_reinit(ide_drive_t *drive);
+int idefloppy_init (void);
+int idefloppy_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2103,9 +2094,13 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
-	end_request:		idefloppy_end_request,
+	end_request:		idefloppy_do_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idefloppy_ioctl,
 	open:			idefloppy_open,
 	release:		idefloppy_release,
@@ -2115,12 +2110,12 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	reinit:			idefloppy_reinit,
+	init:			idefloppy_init,
+	attach:			idefloppy_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idefloppy_init (void);
 static ide_module_t idefloppy_module = {
 	IDE_DRIVER_MODULE,
 	idefloppy_init,
@@ -2128,38 +2123,45 @@
 	NULL
 };
 
-int idefloppy_reinit (ide_drive_t *drive)
+int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	int failed = 0;
+	int ret = 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);
+	if (!idefloppy_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-floppy: %s: not supported by this "
+			"version of ide-floppy\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		printk("ide-floppy: passing drive %s to ide-scsi "
+			"emulation.\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	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);
+		ret = 1;
+		goto bye_game_over;
+	}
+	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);
+		ret = 1;
+		goto bye_game_over;
+	}
+	DRIVER(drive)->busy++;
+	idefloppy_setup(drive, floppy);
+	DRIVER(drive)->busy--;
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
@@ -2169,9 +2171,11 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
-		if (idefloppy_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_floppy, idefloppy_driver.name,
+			&idefloppy_driver, failed)) != NULL) {
+		if (idefloppy_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
 		/* We must remove proc entries defined in this module.
@@ -2184,40 +2188,47 @@
 	ide_unregister_module(&idefloppy_module);
 }
 
-/*
- *	idefloppy_init will register the driver for each floppy.
- */
 int idefloppy_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idefloppy_floppy_t *floppy;
 	int failed = 0;
 
-	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+	printk(KERN_INFO "ide-floppy driver " IDEFLOPPY_VERSION "\n");
+#endif /* CLASSIC_BUILTINS_METHOD */
 	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);
+#ifdef CLASSIC_BUILTINS_METHOD
+	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);
+			printk("ide-floppy: passing drive %s to ide-scsi "
+				"emulation.\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);
+		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);
+		idefloppy_setup(drive, floppy);
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idefloppy_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-geometry.c linux-2.4.21-rc3/drivers/ide/ide-geometry.c
--- linux-2.4.20/drivers/ide/ide-geometry.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-geometry.c	2003-05-22 22:06:25.000000000 +0000
@@ -6,8 +6,6 @@
 #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
@@ -25,13 +23,11 @@
  * If a drive is not actually on the primary interface, then these parameters
  * will be ignored.  This results in the user having to supply the logical
  * drive geometry as a boot parameter for each drive not on the primary i/f.
- */
-/*
+ *
  * The only "perfect" way to handle this would be to modify the setup.[cS] code
  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-/*
+ *
  * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
@@ -51,14 +47,13 @@
 {
 #ifdef __i386__
 	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	u8 cmos_disks, *BIOS = (u8 *) &drive_info;
 	int unit;
 	unsigned long flags;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
 	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
 		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+
 	spin_lock_irqsave(&rtc_lock, flags);
 	cmos_disks = CMOS_READ(0x12);
 	spin_unlock_irqrestore(&rtc_lock, flags);
@@ -68,7 +63,7 @@
 
 		if ((cmos_disks & (0xf0 >> (unit*4)))
 		   && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
+			u16 cyl = *(u16 *)BIOS;
 			unsigned char head = *(BIOS+2);
 			unsigned char sect = *(BIOS+14);
 			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
@@ -86,10 +81,7 @@
 	}
 #endif
 }
-#endif /* 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 *);
@@ -98,10 +90,11 @@
  * If heads is nonzero: find a translation with this many heads and S=63.
  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  */
-static void
-ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
-	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const byte *headp = dm_head_vals;
+
+static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) 
+{
+	static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const u8 *headp = dm_head_vals;
 	unsigned long total;
 
 	/*
@@ -153,6 +146,7 @@
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
 {
 	ide_drive_t *drive;
@@ -221,4 +215,3 @@
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-io.c linux-2.4.21-rc3/drivers/ide/ide-io.c
--- linux-2.4.20/drivers/ide/ide-io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-io.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,1362 @@
+/*
+ *	IDE I/O functions
+ *
+ *	Basic PIO and command management functionality.
+ *
+ * This code was split off from ide.c. See ide.c for history and original
+ * copyrights.
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+ 
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/seq_file.h>
+#include <linux/kmod.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ide_modes.h"
+
+#if (DISK_RECOVERY_TIME > 0)
+
+Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43
+Does anyone ever use this anyway ??
+
+/*
+ * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * we can enforce a minimum delay time between successive operations.
+ */
+static unsigned long read_timer (ide_hwif_t *hwif)
+{
+	unsigned long t, flags;
+	int i;
+	
+	/* FIXME this is completely unsafe! */
+	local_irq_save(flags);
+	t = jiffies * 11932;
+	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb_p(0x40) << 8;
+	local_irq_restore(flags);
+	return (t - i);
+}
+#endif /* DISK_RECOVERY_TIME */
+
+static inline void set_recovery_timer (ide_hwif_t *hwif)
+{
+#if (DISK_RECOVERY_TIME > 0)
+	hwif->last_time = read_timer(hwif);
+#endif /* DISK_RECOVERY_TIME */
+}
+
+/*
+ *	ide_end_request		-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate: 
+ *
+ *	This is our end_request wrapper function. We complete the I/O
+ *	update random number input and dequeue the request.
+ */
+ 
+int ide_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+EXPORT_SYMBOL(ide_end_request);
+
+/**
+ *	ide_end_drive_cmd	-	end an explicit drive command
+ *	@drive: command 
+ *	@stat: status bits
+ *	@err: error bits
+ *
+ *	Clean up after success/failure of an explicit drive command.
+ *	These get thrown onto the queue so they are synchronized with
+ *	real I/O operations on the drive.
+ *
+ *	In LBA48 mode we have to read the register set twice to get
+ *	all the extra information out.
+ */
+ 
+void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	struct request *rq;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	switch(rq->cmd) {
+		case IDE_DRIVE_CMD:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASK:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+				args[3] = hwif->INB(IDE_SECTOR_REG);
+				args[4] = hwif->INB(IDE_LCYL_REG);
+				args[5] = hwif->INB(IDE_HCYL_REG);
+				args[6] = hwif->INB(IDE_SELECT_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASKFILE:
+		{
+			ide_task_t *args = (ide_task_t *) rq->special;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+				
+			if (args) {
+				if (args->tf_in_flags.b.data) {
+					u16 data			= hwif->INW(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] = hwif->INB(IDE_NSECTOR_REG);
+				args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+				args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+				args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+				args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
+				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+
+				if (drive->addressing == 1) {
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
+				}
+			}
+			break;
+		}
+		default:
+			break;
+	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
+/**
+ *	try_to_flush_leftover_data	-	flush junk
+ *	@drive: drive to flush
+ *
+ *	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 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];
+		u32 wcount = (i > 16) ? 16 : i;
+
+		i -= wcount;
+		HWIF(drive)->ata_input_data(drive, buffer, wcount);
+	}
+}
+
+EXPORT_SYMBOL(try_to_flush_leftover_data);
+
+/*
+ * FIXME Add an ATAPI error
+ */
+
+/**
+ *	ide_error	-	handle an error on the IDE
+ *	@drive: drive the error occurred on
+ *	@msg: message to report
+ *	@stat: status bits
+ *
+ *	ide_error() takes action based on the error returned by the drive.
+ *	For normal I/O that may well include retries. We deal with
+ *	both new-style (taskfile) and old style command handling here.
+ *	In the case of taskfile command handling there is work left to
+ *	do
+ */
+ 
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+
+	err = ide_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+//		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)
+			goto media_out;
+
+		if (stat & ERR_STAT) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				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;
+			}
+		}
+media_out:
+		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+			try_to_flush_leftover_data(drive);
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} 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;
+}
+
+EXPORT_SYMBOL(ide_error);
+
+/**
+ *	ide_abort	-	abort pending IDE operatins
+ *	@drive: drive the error occurred on
+ *	@msg: message to report
+ *
+ *	ide_abort kills and cleans up when we are about to do a 
+ *	host initiated reset on active commands. Longer term we
+ *	want handlers to have sensible abort handling themselves
+ *
+ *	This differs fundamentally from ide_error because in 
+ *	this case the command is doing just fine when we
+ *	blow it away.
+ */
+ 
+ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, BUSY_STAT, 0);
+		return ide_stopped;
+	}
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, BUSY_STAT, 0);
+//		ide_end_taskfile(drive, BUSY_STAT, 0);
+		return ide_stopped;
+	}
+
+	rq->errors |= ERROR_RESET;
+	DRIVER(drive)->end_request(drive, 0);
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(ide_abort);
+
+/**
+ *	ide_cmd		-	issue a simple drive command
+ *	@drive: drive the command is for
+ *	@cmd: command byte
+ *	@nsect: sector byte
+ *	@handler: handler for the command completion
+ *
+ *	Issue a simple drive command with interrupts.
+ *	The drive must be selected beforehand.
+ */
+
+void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive,0);
+	hwif->OUTB(nsect,IDE_NSECTOR_REG);
+	ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
+}
+
+EXPORT_SYMBOL(ide_cmd);
+
+/**
+ *	drive_cmd_intr		- 	drive command completion interrupt
+ *	@drive: drive the completion interrupt occurred on
+ *
+ *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ *	We do any neccessary daya reading and then wait for the drive to
+ *	go non busy. At that point we may read the error data and complete
+ *	the request
+ */
+ 
+ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 *args = (u8 *) rq->buffer;
+	u8 stat = hwif->INB(IDE_STATUS_REG);
+	int retries = 10;
+
+	local_irq_enable();
+	if ((stat & DRQ_STAT) && args && args[3]) {
+		u8 io_32bit = drive->io_32bit;
+		drive->io_32bit = 0;
+		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		drive->io_32bit = io_32bit;
+		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+			udelay(100);
+	}
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "drive_cmd", stat);
+		/* calls ide_end_drive_cmd */
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(drive_cmd_intr);
+
+/**
+ *	do_special		-	issue some special commands
+ *	@drive: drive the command is for
+ *
+ *	do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ *	commands to a drive.  It used to do much more, but has been scaled
+ *	back.
+ */
+
+ide_startstop_t do_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+#ifdef DEBUG
+	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+#endif
+	if (s->b.set_tune) {
+		s->b.set_tune = 0;
+		if (HWIF(drive)->tuneproc != NULL)
+			HWIF(drive)->tuneproc(drive, drive->tune_req);
+		return ide_stopped;
+	}
+	else
+		return DRIVER(drive)->special(drive);
+}
+
+EXPORT_SYMBOL(do_special);
+
+/**
+ *	execute_drive_command	-	issue special drive command
+ *	@drive: the drive to issue th command on
+ *	@rq: the request structure holding the command
+ *
+ *	execute_drive_cmd() issues a special drive command,  usually 
+ *	initiated by ioctl() from the external hdparm program. The
+ *	command can be a drive command, drive task or taskfile 
+ *	operation. Weirdly you can call it with NULL to wait for
+ *	all commands to finish. Don't do this as that is due to change
+ */
+
+ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 	switch(rq->cmd) {
+ 		case IDE_DRIVE_TASKFILE:
+ 		{
+ 			ide_task_t *args = rq->special;
+ 
+ 			if (!(args)) break;
+ 
+			if (args->tf_out_flags.all != 0) 
+				return flagged_taskfile(drive, args);
+			return do_rw_taskfile(drive, args);
+ 		}
+ 		case IDE_DRIVE_TASK:
+ 		{
+ 			u8 *args = rq->buffer;
+ 			u8 sel;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			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
+ 			hwif->OUTB(args[1], IDE_FEATURE_REG);
+ 			hwif->OUTB(args[3], IDE_SECTOR_REG);
+ 			hwif->OUTB(args[4], IDE_LCYL_REG);
+ 			hwif->OUTB(args[5], IDE_HCYL_REG);
+ 			sel = (args[6] & ~0x10);
+ 			if (drive->select.b.unit)
+ 				sel |= 0x10;
+ 			hwif->OUTB(sel, IDE_SELECT_REG);
+ 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		case IDE_DRIVE_CMD:
+ 		{
+ 			u8 *args = rq->buffer;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			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) {
+ 				hwif->OUTB(0x4f, IDE_LCYL_REG);
+ 				hwif->OUTB(0xc2, IDE_HCYL_REG);
+ 				hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 				hwif->OUTB(args[1],IDE_SECTOR_REG);
+ 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ 				return ide_started;
+ 			}
+ 			hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		default:
+ 			break;
+ 	}
+ 	/*
+ 	 * 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);
+#endif
+ 	ide_end_drive_cmd(drive,
+			hwif->INB(IDE_STATUS_REG),
+			hwif->INB(IDE_ERROR_REG));
+ 	return ide_stopped;
+}
+
+EXPORT_SYMBOL(execute_drive_cmd);
+
+/**
+ *	start_request	-	start of I/O and command issuing for IDE
+ *
+ *	start_request() initiates handling of a new I/O request. It
+ *	accepts commands and I/O (read/write) requests. It also does
+ *	the final remapping for weird stuff like EZDrive. Once 
+ *	device mapper can work sector level the EZDrive stuff can go away
+ *
+ *	FIXME: this function needs a rename
+ */
+ 
+ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+{
+	ide_startstop_t startstop;
+	unsigned long block, blockend;
+	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+	ide_hwif_t *hwif = HWIF(drive);
+
+#ifdef DEBUG
+	printk("%s: start_request: current=0x%08lx\n",
+		hwif->name, (unsigned long) rq);
+#endif
+
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		goto kill_rq;
+	}
+
+	/*
+	 * bail early if we've sent a device to sleep, however how to wake
+	 * this needs to be a masked flag.  FIXME for proper operations.
+	 */
+	if (drive->suspend_reset) {
+		goto kill_rq;
+	}
+
+	if (unit >= MAX_DRIVES) {
+		printk(KERN_ERR "%s: bad device number: %s\n",
+			hwif->name, kdevname(rq->rq_dev));
+		goto kill_rq;
+	}
+#ifdef DEBUG
+	if (rq->bh && !buffer_locked(rq->bh)) {
+		printk(KERN_ERR "%s: block not locked\n", drive->name);
+		goto kill_rq;
+	}
+#endif
+	block    = rq->sector;
+	blockend = block + rq->nr_sectors;
+
+	if (blk_fs_request(rq) &&
+	    (drive->media == ide_disk || drive->media == ide_floppy)) {
+		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
+			printk(KERN_ERR "%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
+			goto kill_rq;
+		}
+		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+	}
+	/* Yecch - this will shift the entire interval,
+	   possibly killing some innocent following sector */
+	if (block == 0 && drive->remap_0_to_1 == 1)
+		block = 1;  /* redirect MBR access to EZ-Drive partn table */
+
+#if (DISK_RECOVERY_TIME > 0)
+	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
+#endif
+
+	SELECT_DRIVE(drive);
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+		return startstop;
+	}
+	if (!drive->special.all) {
+		switch(rq->cmd) {
+			case IDE_DRIVE_CMD:
+			case IDE_DRIVE_TASK:
+				return execute_drive_cmd(drive, rq);
+			case IDE_DRIVE_TASKFILE:
+				return execute_drive_cmd(drive, rq);
+			default:
+				break;
+		}
+		return (DRIVER(drive)->do_request(drive, rq, block));
+	}
+	return do_special(drive);
+kill_rq:
+	DRIVER(drive)->end_request(drive, 0);
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(start_request);
+
+int restart_request (ide_drive_t *drive, struct request *rq)
+{
+	(void) start_request(drive, rq);
+	return 0;
+}
+
+EXPORT_SYMBOL(restart_request);
+
+/**
+ *	ide_stall_queue		-	pause an IDE device
+ *	@drive: drive to stall
+ *	@timeout: time to stall for (jiffies)
+ *
+ *	ide_stall_queue() can be used by a drive to give excess bandwidth back
+ *	to the hwgroup by sleeping for timeout jiffies.
+ */
+ 
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+	if (timeout > WAIT_WORSTCASE)
+		timeout = WAIT_WORSTCASE;
+	drive->sleep = timeout + jiffies;
+}
+
+EXPORT_SYMBOL(ide_stall_queue);
+
+#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
+
+/**
+ *	choose_drive		-	select a drive to service
+ *	@hwgroup: hardware group to select on
+ *
+ *	choose_drive() selects the next drive which will be serviced.
+ *	This is neccessary because the IDE layer can't issue commands
+ *	to both drives on the same cable, unlike SCSI.
+ */
+ 
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+	ide_drive_t *drive, *best;
+
+repeat:	
+	best = NULL;
+	drive = hwgroup->drive;
+	do {
+		if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
+			if (!best
+			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
+			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+			{
+				if (!blk_queue_plugged(&drive->queue))
+					best = drive;
+			}
+		}
+	} while ((drive = drive->next) != hwgroup->drive);
+	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+		long t = (signed long)(WAKEUP(best) - jiffies);
+		if (t >= WAIT_MIN_SLEEP) {
+		/*
+		 * We *may* have some time to spare, but first let's see if
+		 * someone can potentially benefit from our nice mood today..
+		 */
+			drive = best->next;
+			do {
+				if (!drive->sleep
+				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
+				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
+				{
+					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+					goto repeat;
+				}
+			} while ((drive = drive->next) != best);
+		}
+	}
+	return best;
+}
+
+/*
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
+ */
+/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
+ *         into life on wakeup from machine sleep.
+ */ 
+void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+{
+	ide_drive_t	*drive;
+	ide_hwif_t	*hwif;
+	struct request	*rq;
+	ide_startstop_t	startstop;
+
+	/* for atari only: POSSIBLY BROKEN HERE(?) */
+	ide_get_lock(ide_intr, hwgroup);
+
+	/* necessary paranoia: ensure IRQs are masked on local CPU */
+	local_irq_disable();
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
+		drive = choose_drive(hwgroup);
+		if (drive == NULL) {
+			unsigned long sleep = 0;
+			hwgroup->rq = NULL;
+			drive = hwgroup->drive;
+			do {
+				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
+					sleep = drive->sleep;
+			} while ((drive = drive->next) != hwgroup->drive);
+			if (sleep) {
+		/*
+		 * Take a short snooze, and then wake up this hwgroup again.
+		 * This gives other hwgroups on the same a chance to
+		 * play fairly with us, just in case there are big differences
+		 * in relative throughputs.. don't want to hog the cpu too much.
+		 */
+				if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+					sleep = jiffies + WAIT_MIN_SLEEP;
+#if 1
+				if (timer_pending(&hwgroup->timer))
+					printk(KERN_ERR "ide_set_handler: timer already active\n");
+#endif
+				/* so that ide_timer_expiry knows what to do */
+				hwgroup->sleeping = 1;
+				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1
+				 * while sleeping */
+			} else {
+				/* Ugly, but how can we sleep for the lock
+				 * otherwise? perhaps from tq_disk?
+				 */
+
+				/* for atari only */
+				ide_release_lock();
+				hwgroup->busy = 0;
+			}
+			/* no more work for this hwgroup (for now) */
+			return;
+		}
+		hwif = HWIF(drive);
+		if (hwgroup->hwif->sharing_irq &&
+		    hwif != hwgroup->hwif &&
+		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
+			/* set nIEN for previous hwif */
+			SELECT_INTERRUPT(drive);
+		}
+		hwgroup->hwif = hwif;
+		hwgroup->drive = drive;
+		drive->sleep = 0;
+		drive->service_start = jiffies;
+
+		/* paranoia */
+		if (blk_queue_plugged(&drive->queue))
+			printk(KERN_ERR "%s: Huh? nuking plugged queue\n", drive->name);
+
+		rq = blkdev_entry_next_request(&drive->queue.queue_head);
+		hwgroup->rq = rq;
+		/*
+		 * Some systems have trouble with IDE IRQs arriving while
+		 * the driver is still setting things up.  So, here we disable
+		 * the IRQ used by this interface while the request is being started.
+		 * This may look bad at first, but pretty much the same thing
+		 * happens anyway when any interrupt comes in, IDE or otherwise
+		 *  -- the kernel masks the IRQ while it is being handled.
+		 */
+		if (hwif->irq != masked_irq)
+			disable_irq_nosync(hwif->irq);
+		spin_unlock(&io_request_lock);
+		local_irq_enable();
+			/* allow other IRQs while we start this request */
+		startstop = start_request(drive, rq);
+		spin_lock_irq(&io_request_lock);
+		if (hwif->irq != masked_irq)
+			enable_irq(hwif->irq);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
+	}
+}
+
+EXPORT_SYMBOL(ide_do_request);
+
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+EXPORT_SYMBOL(ide_get_queue);
+
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(request_queue_t *q)
+{
+	ide_do_request(q->queuedata, IDE_NO_IRQ);
+}
+
+/*
+ * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+void ide_dma_timeout_retry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct request *rq;
+
+	/*
+	 * end current dma transaction
+	 */
+	(void) hwif->ide_dma_end(drive);
+
+	/*
+	 * complain a little, later we might remove some of this verbosity
+	 */
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	(void) hwif->ide_dma_timeout(drive);
+
+	/*
+	 * disable dma for now, but remember that we did so because of
+	 * a timeout -- we'll reenable after we finish this next request
+	 * (or rather the first chunk of it) in pio.
+	 */
+	drive->retry_pio++;
+	drive->state = DMA_PIO_RETRY;
+	(void) hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * un-busy drive etc (hwgroup->busy is cleared on return) and
+	 * make sure request is sane
+	 */
+	rq = HWGROUP(drive)->rq;
+	HWGROUP(drive)->rq = NULL;
+
+	rq->errors = 0;
+	rq->sector = rq->bh->b_rsector;
+	rq->current_nr_sectors = rq->bh->b_size >> 9;
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+	rq->buffer = rq->bh->b_data;
+}
+
+EXPORT_SYMBOL(ide_dma_timeout_retry);
+
+/**
+ *	ide_timer_expiry	-	handle lack of an IDE interrupt
+ *	@data: timer callback magic (hwgroup)
+ *
+ *	An IDE command has timed out before the expected drive return
+ *	occurred. At this point we attempt to clean up the current
+ *	mess. If the current handler includes an expiry handler then
+ *	we invoke the expiry handler, and providing it is happy the
+ *	work is done. If that fails we apply generic recovery rules
+ *	invoking the handler and checking the drive DMA status. We
+ *	have an excessively incestuous relationship with the DMA
+ *	logic that wants cleaning up.
+ */
+ 
+void ide_timer_expiry (unsigned long data)
+{
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	ide_expiry_t	*expiry;
+ 	unsigned long	flags;
+	unsigned long	wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	del_timer(&hwgroup->timer);
+
+	if ((handler = hwgroup->handler) == NULL) {
+		/*
+		 * Either a marginal timeout occurred
+		 * (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.
+		 * Either way, we don't really want to complain about anything.
+		 */
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+		}
+	} else {
+		ide_drive_t *drive = hwgroup->drive;
+		if (!drive) {
+			printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
+			hwgroup->handler = NULL;
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop = ide_stopped;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			if ((expiry = hwgroup->expiry) != NULL) {
+				/* continue */
+				if ((wait = expiry(drive)) != 0) {
+					/* reset timer */
+					hwgroup->timer.expires  = jiffies + wait;
+					add_timer(&hwgroup->timer);
+					spin_unlock_irqrestore(&io_request_lock, flags);
+					return;
+				}
+			}
+			hwgroup->handler = NULL;
+			/*
+			 * We need to simulate a real interrupt when invoking
+			 * the handler() function, which means we need to
+			 * globally mask the specific IRQ:
+			 */
+			spin_unlock(&io_request_lock);
+			hwif  = HWIF(drive);
+#if DISABLE_IRQ_NOSYNC
+			disable_irq_nosync(hwif->irq);
+#else
+			/* disable_irq_nosync ?? */
+			disable_irq(hwif->irq);
+#endif /* DISABLE_IRQ_NOSYNC */
+
+			/* local CPU only,
+			 * as if we were handling an interrupt */
+			local_irq_disable();
+			if (hwgroup->poll_timeout != 0) {
+				startstop = handler(drive);
+			} else if (drive_is_ready(drive)) {
+				if (drive->waiting_for_dma)
+					(void) hwgroup->hwif->ide_dma_lostirq(drive);
+				(void)ide_ack_intr(hwif);
+				printk(KERN_ERR "%s: lost interrupt\n", drive->name);
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+					startstop = ide_stopped;
+					ide_dma_timeout_retry(drive);
+				} else {
+					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+				}
+			}
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&io_request_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
+		}
+	}
+	ide_do_request(hwgroup, IDE_NO_IRQ);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_timer_expiry);
+
+/**
+ *	unexpected_intr		-	handle an unexpected IDE interrupt
+ *	@irq: interrupt line
+ *	@hwgroup: hwgroup being processed
+ *
+ *	There's nothing really useful we can do with an unexpected interrupt,
+ *	other than reading the status register (to clear it), and logging it.
+ *	There should be no way that an irq can happen before we're ready for it,
+ *	so we needn't worry much about losing an "important" interrupt here.
+ *
+ *	On laptops (and "green" PCs), an unexpected interrupt occurs whenever
+ *	the drive enters "idle", "standby", or "sleep" mode, so if the status
+ *	looks "good", we just ignore the interrupt completely.
+ *
+ *	This routine assumes __cli() is in effect when called.
+ *
+ *	If an unexpected interrupt happens on irq15 while we are handling irq14
+ *	and if the two interfaces are "serialized" (CMD640), then it looks like
+ *	we could screw up by interfering with a new request being set up for 
+ *	irq15.
+ *
+ *	In reality, this is a non-issue.  The new command is not sent unless 
+ *	the drive is ready to accept one, in which case we know the drive is
+ *	not trying to interrupt us.  And ide_set_handler() is always invoked
+ *	before completing the issuance of any new drive command, so we will not
+ *	be accidentally invoked as a result of any valid command completion
+ *	interrupt.
+ *
+ *	Note that we must walk the entire hwgroup here. We know which hwif
+ *	is doing the current command, but we don't know which hwif burped
+ *	mysteriously.
+ */
+ 
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+{
+	u8 stat;
+	ide_hwif_t *hwif = hwgroup->hwif;
+
+	/*
+	 * handle the unexpected interrupt
+	 */
+	do {
+		if (hwif->irq == irq) {
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+				/* Try to not flood the console with msgs */
+				static unsigned long last_msgtime, count;
+				++count;
+				if (time_after(jiffies, last_msgtime + HZ)) {
+					last_msgtime = jiffies;
+					printk(KERN_ERR "%s%s: unexpected interrupt, "
+						"status=0x%02x, count=%ld\n",
+						hwif->name,
+						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
+				}
+			}
+		}
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+}
+
+/**
+ *	ide_intr	-	default IDE interrupt handler
+ *	@irq: interrupt number
+ *	@dev_id: hwif group
+ *	@regs: unused weirdness from the kernel irq layer
+ *
+ *	This is the default IRQ handler for the IDE layer. You should
+ *	not need to override it. If you do be aware it is subtle in
+ *	places
+ *
+ *	hwgroup->hwif is the interface in the group currently performing
+ *	a command. hwgroup->drive is the drive and hwgroup->handler is
+ *	the IRQ handler to call. As we issue a command the handlers
+ *	step through multiple states, reassigning the handler to the
+ *	next step in the process. Unlike a smart SCSI controller IDE
+ *	expects the main processor to sequence the various transfer
+ *	stages. We also manage a poll timer to catch up with most
+ *	timeout situations. There are still a few where the handlers
+ *	don't ever decide to give up.
+ *
+ *	The handler eventually returns ide_stopped to indicate the
+ *	request completed. At this point we issue the next request
+ *	on the hwgroup and the process begins again.
+ */
+ 
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	ide_handler_t *handler;
+	ide_startstop_t startstop;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	hwif = hwgroup->hwif;
+
+	if (!ide_ack_intr(hwif)) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+
+	if ((handler = hwgroup->handler) == NULL ||
+	    hwgroup->poll_timeout != 0) {
+		/*
+		 * Not expecting an interrupt from this drive.
+		 * That means this could be:
+		 *	(1) an interrupt from another PCI device
+		 *	sharing the same PCI INT# as us.
+		 * or	(2) a drive just entered sleep or standby mode,
+		 *	and is interrupting to let us know.
+		 * or	(3) a spurious interrupt of unknown origin.
+		 *
+		 * For PCI, we cannot tell the difference,
+		 * so in that case we just ignore it and hope it goes away.
+		 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		if (hwif->pci_dev && !hwif->pci_dev->vendor)
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		{
+			/*
+			 * Probably not a shared PCI interrupt,
+			 * so we can safely try to do something about it:
+			 */
+			unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		} else {
+			/*
+			 * Whack the status register, just in case
+			 * we have a leftover pending IRQ.
+			 */
+			(void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	drive = hwgroup->drive;
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much
+		 * we could do about it here.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with
+		 * another device.  Unfortunately, it can also happen
+		 * with some buggy drives that trigger the IRQ before
+		 * their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
+	hwgroup->handler = NULL;
+	del_timer(&hwgroup->timer);
+	spin_unlock(&io_request_lock);
+
+	if (drive->unmask)
+		local_irq_enable();
+
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);
+	spin_lock_irq(&io_request_lock);
+
+	/*
+	 * Note that handler() may have set things up for another
+	 * interrupt to occur soon, but it cannot happen until
+	 * we exit from this routine, because it will be the
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
+	 */
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup, hwif->irq);
+		} else {
+			printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
+				"on exit\n", drive->name);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_intr);
+
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
+{
+	int		major = MAJOR(i_rdev);
+	unsigned int	h;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t  *hwif = &ide_hwifs[h];
+		if (hwif->present && major == hwif->major) {
+			unsigned unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (drive->present)
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(get_info_ptr);
+
+/**
+ *	ide_init_drive_cmd	-	initialize a drive command request
+ *	@rq: request object
+ *
+ *	Initialize a request before we fill it in and send it down to
+ *	ide_do_drive_cmd. Commands must be set up by this function. Right
+ *	now it doesn't do a lot, but if that changes abusers will have a
+ *	nasty suprise.
+ */
+
+void ide_init_drive_cmd (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_CMD;
+}
+
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
+/**
+ *	ide_do_drive_cmd	-	issue IDE special command
+ *	@drive: device to issue command
+ *	@rq: request to issue
+ *	@action: action for processing
+ *
+ *	This function issues a special IDE device request
+ *	onto the request queue.
+ *
+ *	If action is ide_wait, then the rq is queued at the end of the
+ *	request queue, and the function sleeps until it has been processed.
+ *	This is for use when invoked from an ioctl handler.
+ *
+ *	If action is ide_preempt, then the rq is queued at the head of
+ *	the request queue, displacing the currently-being-processed
+ *	request and this function returns immediately without waiting
+ *	for the new rq to be completed.  This is VERY DANGEROUS, and is
+ *	intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_next, then the rq is queued immediately after
+ *	the currently-being-processed-request (if any), and the function
+ *	returns without waiting for the new rq to be completed.  As above,
+ *	This is VERY DANGEROUS, and is intended for careful use by the
+ *	ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_end, then the rq is queued at the end of the
+ *	request queue, and the function returns immediately without waiting
+ *	for the new rq to be completed. This is again intended for careful
+ *	use by the ATAPI tape/cdrom driver code.
+ */
+ 
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	request_queue_t *q = &drive->queue;
+	struct list_head *queue_head = &q->queue_head;
+	DECLARE_COMPLETION(wait);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+		return -ENOSYS;  /* special drive cmds not supported */
+#endif
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	if (action == ide_wait)
+		rq->waiting = &wait;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (blk_queue_empty(q) || action == ide_preempt) {
+		if (action == ide_preempt)
+			hwgroup->rq = NULL;
+	} else {
+		if (action == ide_wait || action == ide_end) {
+			queue_head = queue_head->prev;
+		} else
+			queue_head = queue_head->next;
+	}
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, IDE_NO_IRQ);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	if (action == ide_wait) {
+		/* wait for it to be serviced */
+		wait_for_completion(&wait);
+		/* return -EIO if errors */
+		return rq->errors ? -EIO : 0;
+	}
+	return 0;
+
+}
+
+EXPORT_SYMBOL(ide_do_drive_cmd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-iops.c linux-2.4.21-rc3/drivers/ide/ide-iops.c
--- linux-2.4.20/drivers/ide/ide-iops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-iops.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,1339 @@
+/*
+ * linux/drivers/ide/ide-iops.c	Version 0.37	Mar 05, 2003
+ *
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003		Red Hat <alan@redhat.com>
+ *
+ *
+ */
+
+#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>
+
+/*
+ *	IDE operator we assign to an unplugged device so that
+ *	we don't trash new hardware assigned the same resources
+ */
+ 
+static u8 ide_unplugged_inb (unsigned long port)
+{
+	return 0xFF;
+}
+
+static u16 ide_unplugged_inw (unsigned long port)
+{
+	return 0xFFFF;
+}
+
+static void ide_unplugged_insw (unsigned long port, void *addr, u32 count)
+{
+}
+
+static u32 ide_unplugged_inl (unsigned long port)
+{
+	return 0xFFFFFFFF;
+}
+
+static void ide_unplugged_insl (unsigned long port, void *addr, u32 count)
+{
+}
+
+static void ide_unplugged_outb (u8 addr, unsigned long port)
+{
+}
+
+static void ide_unplugged_outbsync (ide_drive_t *drive, u8 addr, unsigned long port)
+{
+}
+
+static void ide_unplugged_outw (u16 addr, unsigned long port)
+{
+}
+
+static void ide_unplugged_outsw (unsigned long port, void *addr, u32 count)
+{
+}
+
+static void ide_unplugged_outl (u32 addr, unsigned long port)
+{
+}
+
+static void ide_unplugged_outsl (unsigned long port, void *addr, u32 count)
+{
+}
+
+void unplugged_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_unplugged_outb;
+	hwif->OUTBSYNC	= ide_unplugged_outbsync;
+	hwif->OUTW	= ide_unplugged_outw;
+	hwif->OUTL	= ide_unplugged_outl;
+	hwif->OUTSW	= ide_unplugged_outsw;
+	hwif->OUTSL	= ide_unplugged_outsl;
+	hwif->INB	= ide_unplugged_inb;
+	hwif->INW	= ide_unplugged_inw;
+	hwif->INL	= ide_unplugged_inl;
+	hwif->INSW	= ide_unplugged_insw;
+	hwif->INSL	= ide_unplugged_insl;
+}
+
+EXPORT_SYMBOL(unplugged_hwif_iops);
+
+/*
+ *	Conventional PIO operations for ATA devices
+ */
+
+static u8 ide_inb (unsigned long port)
+{
+	return (u8) inb(port);
+}
+
+static u16 ide_inw (unsigned long port)
+{
+	return (u16) inw(port);
+}
+
+static void ide_insw (unsigned long port, void *addr, u32 count)
+{
+	return insw(port, addr, count);
+}
+
+static u32 ide_inl (unsigned long port)
+{
+	return (u32) inl(port);
+}
+
+static void ide_insl (unsigned long port, void *addr, u32 count)
+{
+	insl(port, addr, count);
+}
+
+static void ide_outb (u8 addr, unsigned long port)
+{
+	outb(addr, port);
+}
+
+static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port)
+{
+	outb(addr, port);
+}
+
+static void ide_outw (u16 addr, unsigned long port)
+{
+	outw(addr, port);
+}
+
+static void ide_outsw (unsigned long port, void *addr, u32 count)
+{
+	outsw(port, addr, count);
+}
+
+static void ide_outl (u32 addr, unsigned long port)
+{
+	outl(addr, port);
+}
+
+static void ide_outsl (unsigned long port, void *addr, u32 count)
+{
+	outsl(port, addr, count);
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_outb;
+	hwif->OUTBSYNC	= ide_outbsync;
+	hwif->OUTW	= ide_outw;
+	hwif->OUTL	= ide_outl;
+	hwif->OUTSW	= ide_outsw;
+	hwif->OUTSL	= ide_outsl;
+	hwif->INB	= ide_inb;
+	hwif->INW	= ide_inw;
+	hwif->INL	= ide_inl;
+	hwif->INSW	= ide_insw;
+	hwif->INSL	= ide_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+/*
+ *	MMIO operations, typically used for SATA controllers
+ */
+
+static u8 ide_mm_inb (unsigned long port)
+{
+	return (u8) readb(port);
+}
+
+static u16 ide_mm_inw (unsigned long port)
+{
+	return (u16) readw(port);
+}
+
+static void ide_mm_insw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insw(port, addr, count);
+}
+
+static u32 ide_mm_inl (unsigned long port)
+{
+	return (u32) readl(port);
+}
+
+static void ide_mm_insl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insl(port, addr, count);
+}
+
+static void ide_mm_outb (u8 value, unsigned long port)
+{
+	writeb(value, port);
+}
+
+static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
+{
+	writeb(value, port);	
+}
+
+static void ide_mm_outw (u16 value, unsigned long port)
+{
+	writew(value, port);
+}
+
+static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsw(port, addr, count);
+}
+
+static void ide_mm_outl (u32 value, unsigned long port)
+{
+	writel(value, port);
+}
+
+static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsl(port, addr, count);
+}
+
+void default_hwif_mmiops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_mm_outb;
+	/* Most systems will need to override OUTBSYNC, alas however
+	   this one is controller specific! */
+	hwif->OUTBSYNC	= ide_mm_outbsync;
+	hwif->OUTW	= ide_mm_outw;
+	hwif->OUTL	= ide_mm_outl;
+	hwif->OUTSW	= ide_mm_outsw;
+	hwif->OUTSL	= ide_mm_outsl;
+	hwif->INB	= ide_mm_inb;
+	hwif->INW	= ide_mm_inw;
+	hwif->INL	= ide_mm_inl;
+	hwif->INSW	= ide_mm_insw;
+	hwif->INSL	= ide_mm_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_mmiops);
+
+void default_hwif_transport (ide_hwif_t *hwif)
+{
+	hwif->ata_input_data		= ata_input_data;
+	hwif->ata_output_data		= ata_output_data;
+	hwif->atapi_input_bytes		= atapi_input_bytes;
+	hwif->atapi_output_bytes	= atapi_output_bytes;
+}
+
+EXPORT_SYMBOL(default_hwif_transport);
+
+u32 read_24 (ide_drive_t *drive)
+{
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+}
+
+EXPORT_SYMBOL(read_24);
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+	if (HWIF(drive)->selectproc)
+		HWIF(drive)->selectproc(drive);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+}
+
+EXPORT_SYMBOL(SELECT_DRIVE);
+
+void SELECT_INTERRUPT (ide_drive_t *drive)
+{
+	if (HWIF(drive)->intrproc)
+		HWIF(drive)->intrproc(drive);
+	else
+		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+EXPORT_SYMBOL(SELECT_INTERRUPT);
+
+void SELECT_MASK (ide_drive_t *drive, int mask)
+{
+	if (HWIF(drive)->maskproc)
+		HWIF(drive)->maskproc(drive, mask);
+}
+
+EXPORT_SYMBOL(SELECT_MASK);
+
+void QUIRK_LIST (ide_drive_t *drive)
+{
+	if (HWIF(drive)->quirkproc)
+		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+}
+
+EXPORT_SYMBOL(QUIRK_LIST);
+
+/*
+ * 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.
+ */
+void ata_vlb_sync (ide_drive_t *drive, ide_ioreg_t port)
+{
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+}
+
+EXPORT_SYMBOL(ata_vlb_sync);
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_output_data);
+
+/*
+ * 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, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++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 || CONFIG_Q40 */
+	hwif->ata_input_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_input_bytes);
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++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 || CONFIG_Q40 */
+	hwif->ata_output_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_output_bytes);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+void ide_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+	u16 *stringcast;
+
+#ifdef __mc68000__
+	if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
+		return;
+
+#ifdef M68K_IDE_SWAPW
+	if (M68K_IDE_SWAPW) {	/* fix bus byteorder first */
+		u_char *p = (u_char *)id;
+		u_char t;
+		for (i = 0; i < 512; i += 2) {
+			t = p[i];
+			p[i] = p[i+1];
+			p[i+1] = t;
+		}
+	}
+#endif
+#endif /* __mc68000__ */
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (u16 *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (u16 *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (u16 *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; ++i)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; ++i)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth    = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; ++i)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->mprc           = __le16_to_cpu(id->mprc);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
+	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);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[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);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+EXPORT_SYMBOL(ide_fix_driveid);
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+	u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+	if (byteswap) {
+		/* convert from big-endian to host byte order */
+		for (p = end ; p != s;) {
+			unsigned short *pp = (unsigned short *) (p -= 2);
+			*pp = ntohs(*pp);
+		}
+	}
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
+	}
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
+}
+
+EXPORT_SYMBOL(ide_fixstring);
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	if (drive->waiting_for_dma)
+		return hwif->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 = hwif->INB(IDE_ALTSTATUS_REG);
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		/* Note: this may clear a pending IRQ!! */
+		stat = hwif->INB(IDE_STATUS_REG);
+
+	if (stat & BUSY_STAT)
+		/* drive busy:  definitely not interrupting */
+		return 0;
+
+	/* drive ready: *might* be interrupting */
+	return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * Global for All, and taken from ide-pmac.c. Can be called
+ * with spinlock held & IRQs disabled, so don't schedule !
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	while(--timeout) {
+		stat = hwif->INB(IDE_STATUS_REG);
+		if (!(stat & BUSY_STAT)) {
+			if (drive->ready_stat == 0)
+				break;
+			else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
+				break;
+		}
+		mdelay(1);
+	}
+	if ((stat & ERR_STAT) || timeout <= 0) {
+		if (stat & ERR_STAT) {
+			printk(KERN_ERR "%s: wait_for_ready, "
+				"error status: %x\n", drive->name, stat);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(wait_for_ready);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error() -- caller should just return.
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until timeout is achieved, before timing out.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+	int i;
+	unsigned long flags;
+ 
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		*startstop = ide_stopped;
+		return 1;
+	}
+
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		local_irq_set(flags);
+		timeout += jiffies;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout)) {
+				local_irq_restore(flags);
+				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
+				return 1;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+			return 0;
+	}
+	*startstop = DRIVER(drive)->error(drive, "status error", stat);
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/*
+ *  All hosts that use the 80c ribbon must use!
+ *  The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+u8 eighty_ninty_three (ide_drive_t *drive)
+{
+#if 0
+	if (!HWIF(drive)->udma_four)
+		return 0;
+
+	if (drive->id->major_rev_num) {
+		int hssbd = 0;
+		int i;
+		/*
+		 * Determime highest Supported SPEC
+		 */
+		for (i=1; i<=15; i++)
+			if (drive->id->major_rev_num & (1<<i))
+				hssbd++;
+
+		switch (hssbd) {
+			case 7:
+			case 6:
+			case 5:
+		/* ATA-4 and older do not support above Ultra 33 */
+			default:
+				return 0;
+		}
+	}
+
+	return ((u8) (
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+	return ((u8) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+			(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+			(drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+		if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+		if (((drive->id->hw_config & 0x2000) == 0) ||
+		    ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n", drive->name);
+			return 1;
+		}
+		if (!HWIF(drive)->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n",
+				HWIF(drive)->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_ata66_check);
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+	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))
+		return 1;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(set_transfer);
+
+u8 ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+	if (!drive->crc_count)
+		return drive->current_speed;
+	drive->crc_count = 0;
+
+	switch(drive->current_speed) {
+		case XFER_UDMA_7:	return XFER_UDMA_6;
+		case XFER_UDMA_6:	return XFER_UDMA_5;
+		case XFER_UDMA_5:	return XFER_UDMA_4;
+		case XFER_UDMA_4:	return XFER_UDMA_3;
+		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:
+		default:		return XFER_PIO_4;
+	}
+}
+
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
+
+/*
+ * Update the 
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id;
+#if 0
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id)
+		return 0;
+
+	taskfile_lib_get_identify(drive, (char *)&id);
+
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+	return 1;
+#else
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	unsigned long timeout, flags;
+
+	SELECT_MASK(drive, 1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			SELECT_MASK(drive, 0);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+		SELECT_MASK(drive, 0);
+		printk("%s: CHECK for good STATUS\n", drive->name);
+		return 0;
+	}
+	local_irq_save(flags);
+	SELECT_MASK(drive, 0);
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id) {
+		local_irq_restore(flags);
+		return 0;
+	}
+	ata_input_data(drive, id, SECTOR_WORDS);
+	(void) hwif->INB(IDE_STATUS_REG);	/* clear drive IRQ */
+	local_irq_enable();
+	local_irq_restore(flags);
+	ide_fix_driveid(id);
+
+	drive->id->dma_ultra = id->dma_ultra;
+	drive->id->dma_mword = id->dma_mword;
+	drive->id->dma_1word = id->dma_1word;
+	/* anything more ? */
+	kfree(id);
+
+	return 1;
+#endif
+}
+
+EXPORT_SYMBOL(ide_driveid_update);
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	int	i, error	= 1;
+	u8 stat;
+
+//	while (HWGROUP(drive)->busy)
+//		ide_delay_50ms();
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	hwif->ide_dma_host_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq_nosync(hwif->irq);
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(speed, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		local_irq_set(flags);
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (speed >= XFER_SW_DMA_0)
+		hwif->ide_dma_host_on(drive);
+	else
+		hwif->ide_dma_off_quietly(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+	return error;
+}
+
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+
+/*
+ * This should get invoked any time we exit the driver to
+ * wait for an interrupt response from a drive.  handler() points
+ * at the appropriate code to handle the next interrupt, and a
+ * timer is started to prevent us from waiting forever in case
+ * something goes wrong (see the ide_timer_expiry() handler later on).
+ *
+ * See also ide_execute_command
+ */
+void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	if (hwgroup->handler != NULL) {
+		printk(KERN_CRIT "%s: ide_set_handler: handler not null; "
+			"old=%p, new=%p\n",
+			drive->name, hwgroup->handler, handler);
+		BUG();
+	}
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+}
+
+EXPORT_SYMBOL(__ide_set_handler);
+
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&io_request_lock, flags);
+	__ide_set_handler(drive, handler, timeout, expiry);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_set_handler);
+
+/**
+ *	ide_execute_command	-	execute an IDE command
+ *	@drive: IDE drive to issue the command against
+ *	@command: command byte to write
+ *	@handler: handler for next phase
+ *	@timeout: timeout for command
+ *	@expiry:  handler to run on timeout
+ *
+ *	Helper function to issue an IDE command. This handles the
+ *	atomicity requirements, command timing and ensures that the 
+ *	handler and IRQ setup do not race. All IDE command kick off
+ *	should go via this function or do equivalent locking.
+ */
+ 
+void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	ide_hwif_t *hwif = HWIF(drive);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	if(hwgroup->handler)
+		BUG();
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);
+	/* Drive takes 400nS to respond, we must avoid the IRQ being
+	   serviced before that. 
+	   
+	   FIXME: we could skip this delay with care on non shared
+	   devices 
+	   
+	   For DMA transfers highpoint have a neat trick we could
+	   use. When they take an IRQ they check STS but also that
+	   the DMA count is not zero (see hpt's own driver)
+	*/
+	ndelay(400);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_execute_command);
+
+/* needed below */
+static ide_startstop_t do_reset1 (ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
+
+	SELECT_DRIVE(drive);
+	udelay (10);
+
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		printk("%s: ATAPI reset complete\n", drive->name);
+	} else {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		/* end of polling */
+		hwgroup->poll_timeout = 0;
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n",
+				drive->name, stat);
+		/* do it the old fashioned way */
+		return do_reset1(drive, 1);
+	}
+	/* done polling */
+	hwgroup->poll_timeout = 0;
+	return ide_stopped;
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 tmp;
+
+	if (hwif->reset_poll != NULL) {
+		if (hwif->reset_poll(drive)) {
+			printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+				hwif->name, drive->name);
+			return ide_stopped;
+		}
+	}
+
+	if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+		drive->failures++;
+	} else  {
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+			printk("success\n");
+			drive->failures = 0;
+		} else {
+			drive->failures++;
+#if FANCY_STATUS_DUMPS
+			printk("master: ");
+			switch (tmp & 0x7f) {
+				case 1: printk("passed");
+					break;
+				case 2: printk("formatter device error");
+					break;
+				case 3: printk("sector buffer error");
+					break;
+				case 4: printk("ECC circuitry error");
+					break;
+				case 5: printk("controlling MPU error");
+					break;
+				default:printk("error (0x%02x?)", tmp);
+			}
+			if (tmp & 0x80)
+				printk("; slave: failed");
+			printk("\n");
+#else
+			printk("failed\n");
+#endif /* FANCY_STATUS_DUMPS */
+		}
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
+}
+
+void check_dma_crc (ide_drive_t *drive)
+{
+	if (drive->crc_count) {
+		(void) HWIF(drive)->ide_dma_off_quietly(drive);
+		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
+		if (drive->current_speed >= XFER_SW_DMA_0)
+			(void) HWIF(drive)->ide_dma_on(drive);
+	} else {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+}
+
+void pre_reset (ide_drive_t *drive)
+{
+	DRIVER(drive)->pre_reset(drive);
+
+	if (!drive->keep_settings) {
+		if (drive->using_dma) {
+			check_dma_crc(drive);
+		} else {
+			drive->unmask = 0;
+			drive->io_32bit = 0;
+		}
+		return;
+	}
+	if (drive->using_dma)
+		check_dma_crc(drive);
+
+	if (HWIF(drive)->pre_reset != NULL)
+		HWIF(drive)->pre_reset(drive);
+
+}
+
+/*
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+{
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif;
+	ide_hwgroup_t *hwgroup;
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	hwgroup = HWGROUP(drive);
+	hwif = HWIF(drive);
+	
+	/* We must not reset with running handlers */
+	if(hwgroup->handler != NULL)
+		BUG();
+
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media != ide_disk && !do_not_try_atapi) {
+		pre_reset(drive);
+		SELECT_DRIVE(drive);
+		udelay (20);
+		hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return ide_started;
+	}
+
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		pre_reset(&hwif->drives[unit]);
+
+#if OK_TO_RESET_CONTROLLER
+	if (!IDE_CONTROL_REG) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return ide_stopped;
+	}
+
+	/*
+	 * Note that we also set nIEN while resetting the device,
+	 * to mask unwanted interrupts from the interface during the reset.
+	 * However, due to the design of PC hardware, this will cause an
+	 * immediate interrupt due to the edge transition it produces.
+	 * This single interrupt gives us a "fast poll" for drives that
+	 * recover from reset very quickly, saving us the first 50ms wait time.
+	 */
+	/* set SRST and nIEN */
+	hwif->OUTBSYNC(drive, drive->ctl|6,IDE_CONTROL_REG);
+	/* more than enough time */
+	udelay(10);
+	if (drive->quirk_list == 2) {
+		/* clear SRST and nIEN */
+		hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG);
+	} else {
+		/* clear SRST, leave nIEN */
+		hwif->OUTBSYNC(drive, drive->ctl|2, IDE_CONTROL_REG);
+	}
+	/* more than enough time */
+	udelay(10);
+	
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	__ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL) {
+		hwif->resetproc(drive);
+	}
+
+#endif	/* OK_TO_RESET_CONTROLLER */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ide_started;
+}
+
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ *
+ * Caller must not hold the io_request lock.
+ */
+ 
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	return do_reset1(drive, 0);
+}
+
+EXPORT_SYMBOL(ide_do_reset);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-lib.c linux-2.4.21-rc3/drivers/ide/ide-lib.c
--- linux-2.4.20/drivers/ide/ide-lib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-lib.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,439 @@
+#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>
+
+#include "ide_modes.h"
+
+/*
+ *	IDE library routines. These are plug in code that most 
+ *	drivers can use but occasionally may be weird enough
+ *	to want to do their own thing with
+ *
+ *	Add common non I/O op stuff here. Make sure it has proper
+ *	kernel-doc function headers or your patch will be rejected
+ */
+ 
+
+/**
+ *	ide_xfer_verbose	-	return IDE mode names
+ *	@xfer_rate: rate to name
+ *
+ *	Returns a constant string giving the name of the mode
+ *	requested.
+ */
+
+char *ide_xfer_verbose (u8 xfer_rate)
+{
+        switch(xfer_rate) {
+                case XFER_UDMA_7:	return("UDMA 7");
+                case XFER_UDMA_6:	return("UDMA 6");
+                case XFER_UDMA_5:	return("UDMA 5");
+                case XFER_UDMA_4:	return("UDMA 4");
+                case XFER_UDMA_3:	return("UDMA 3");
+                case XFER_UDMA_2:	return("UDMA 2");
+                case XFER_UDMA_1:	return("UDMA 1");
+                case XFER_UDMA_0:	return("UDMA 0");
+                case XFER_MW_DMA_2:	return("MW DMA 2");
+                case XFER_MW_DMA_1:	return("MW DMA 1");
+                case XFER_MW_DMA_0:	return("MW DMA 0");
+                case XFER_SW_DMA_2:	return("SW DMA 2");
+                case XFER_SW_DMA_1:	return("SW DMA 1");
+                case XFER_SW_DMA_0:	return("SW DMA 0");
+                case XFER_PIO_4:	return("PIO 4");
+                case XFER_PIO_3:	return("PIO 3");
+                case XFER_PIO_2:	return("PIO 2");
+                case XFER_PIO_1:	return("PIO 1");
+                case XFER_PIO_0:	return("PIO 0");
+                case XFER_PIO_SLOW:	return("PIO SLOW");
+                default:		return("XFER ERROR");
+        }
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ *	ide_dma_speed	-	compute DMA speed
+ *	@drive: drive
+ *	@mode; intended mode
+ *
+ *	Checks the drive capabilities and returns the speed to use
+ *	for the transfer. Returns -1 if the requested mode is unknown
+ *	(eg PIO)
+ */
+ 
+u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+{
+	struct hd_driveid *id   = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 speed = 0;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return 0;
+
+	switch(mode) {
+		case 0x04:
+			if ((id->dma_ultra & 0x0040) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if ((id->dma_ultra & 0x0020) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if ((id->dma_ultra & 0x0010) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_4; break; }
+			if ((id->dma_ultra & 0x0008) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if ((id->dma_ultra & 0x0004) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_2; break; }
+			if ((id->dma_ultra & 0x0002) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_1; break; }
+			if ((id->dma_ultra & 0x0001) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if ((id->dma_mword & 0x0004) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_2; break; }
+			if ((id->dma_mword & 0x0002) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_1; break; }
+			if ((id->dma_mword & 0x0001) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_0; break; }
+			if ((id->dma_1word & 0x0004) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_2; break; }
+			if ((id->dma_1word & 0x0002) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_1; break; }
+			if ((id->dma_1word & 0x0001) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_0; break; }
+	}
+
+//	printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+//		__FUNCTION__, drive->name, mode, speed);
+
+	return speed;
+}
+
+EXPORT_SYMBOL(ide_dma_speed);
+
+
+/**
+ *	ide_rate_filter		-	return best speed for mode
+ *	@mode: modes available
+ *	@speed: desired speed
+ *
+ *	Given the available DMA/UDMA mode this function returns
+ *	the best available speed at or below the speed requested.
+ */
+
+u8 ide_rate_filter (u8 mode, u8 speed) 
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	static u8 speed_max[] = {
+		XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
+		XFER_UDMA_5, XFER_UDMA_6
+	};
+
+//	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+
+	/* So that we remember to update this if new modes appear */
+	if (mode > 4)
+		BUG();
+	return min(speed, speed_max[mode]);
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	return min(speed, XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+EXPORT_SYMBOL(ide_rate_filter);
+
+int ide_dma_enable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	return ((int)	((((id->dma_ultra >> 8) & hwif->ultra_mask) ||
+			  ((id->dma_mword >> 8) & hwif->mwdma_mask) ||
+			  ((id->dma_1word >> 8) & hwif->swdma_mask)) ? 1 : 0));
+}
+
+EXPORT_SYMBOL(ide_dma_enable);
+
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+EXPORT_SYMBOL_GPL(ide_pio_timings);
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/**
+ *	ide_scan_pio_blacklist 	-	check for a blacklisted drive
+ *	@model: Drive model string
+ *
+ *	This routine searches the ide_pio_blacklist for an entry
+ *	matching the start/whole of the supplied model name.
+ *
+ *	Returns -1 if no match found.
+ *	Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+
+static int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/**
+ *	ide_get_best_pio_mode	-	get PIO mode from drive
+ *	@driver: drive to consider
+ *	@mode_wanted: preferred mode
+ *	@max_mode: highest allowed
+ *	@d: pio data
+ *
+ *	This routine returns the recommended PIO settings for a given drive,
+ *	based on the drive->id information and the ide_pio_blacklist[].
+ *	This is used by most chipset support modules when "auto-tuning".
+ *
+ *	Drive PIO mode auto selection
+ */
+
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+/**
+ *	ide_toggle_bounce	-	handle bounce buffering
+ *	@drive: drive to update
+ *	@on: on/off boolean
+ *
+ *	Enable or disable bounce buffering for the device. Drives move
+ *	between PIO and DMA and that changes the rules we need.
+ */
+ 
+void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+EXPORT_SYMBOL(ide_toggle_bounce);
+
+
+/**
+ *	ide_set_xfer_rate	-	set transfer rate
+ *	@drive: drive to set
+ *	@speed: speed to attempt to set
+ *	
+ *	General helper for setting the speed of an IDE device. This
+ *	function knows about user enforced limits from the configuration
+ *	which speedproc() does not.  High level drivers should never
+ *	invoke speedproc() directly.
+ */
+ 
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+#ifndef CONFIG_BLK_DEV_IDEDMA
+	rate = min(rate, (u8) XFER_PIO_4);
+#endif
+	if(HWIF(drive)->speedproc)
+		return HWIF(drive)->speedproc(drive, rate);
+	else
+		return -1;
+}
+
+EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-m8xx.c linux-2.4.21-rc3/drivers/ide/ide-m8xx.c
--- linux-2.4.20/drivers/ide/ide-m8xx.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-m8xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,857 +0,0 @@
-/*
- *  linux/drivers/ide/ide-m8xx.c
- *
- *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
- *  Modified for direct IDE interface
- *	by Thomas Lange, thomas@corelatus.com
- *  Modified for direct IDE interface on 8xx without using the PCMCIA
- *  controller
- *	by Steven.Scholz@imc-berlin.de
- *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
- *	by Mathew Locke <mattl@mvista.com>
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/bootmem.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-#include <asm/8xx_immap.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-static int identify  (volatile unsigned char *p);
-static void print_fixed (volatile unsigned char *p);
-static void print_funcid (int func);
-static int check_ide_device (unsigned long base);
-
-static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio);
-
-typedef	struct ide_ioport_desc {
-	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
-	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
-	int		irq;			/* IRQ				*/
-} ide_ioport_desc_t;
-
-ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
-#ifdef IDE0_BASE_OFFSET
-	{ IDE0_BASE_OFFSET,
-	    {
-		IDE0_DATA_REG_OFFSET,
-		IDE0_ERROR_REG_OFFSET,
-		IDE0_NSECTOR_REG_OFFSET,
-		IDE0_SECTOR_REG_OFFSET,
-		IDE0_LCYL_REG_OFFSET,
-		IDE0_HCYL_REG_OFFSET,
-		IDE0_SELECT_REG_OFFSET,
-		IDE0_STATUS_REG_OFFSET,
-		IDE0_CONTROL_REG_OFFSET,
-		IDE0_IRQ_REG_OFFSET,
-	    },
-	    IDE0_INTERRUPT,
-	},
-#ifdef IDE1_BASE_OFFSET
-	{ IDE1_BASE_OFFSET,
-	    {
-		IDE1_DATA_REG_OFFSET,
-		IDE1_ERROR_REG_OFFSET,
-		IDE1_NSECTOR_REG_OFFSET,
-		IDE1_SECTOR_REG_OFFSET,
-		IDE1_LCYL_REG_OFFSET,
-		IDE1_HCYL_REG_OFFSET,
-		IDE1_SELECT_REG_OFFSET,
-		IDE1_STATUS_REG_OFFSET,
-		IDE1_CONTROL_REG_OFFSET,
-		IDE1_IRQ_REG_OFFSET,
-	    },
-	    IDE1_INTERRUPT,
-	},
-#endif /* IDE1_BASE_OFFSET */
-#endif	/* IDE0_BASE_OFFSET */
-};
-
-ide_pio_timings_t ide_pio_clocks[6];
-int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
-
-/*
- * Warning: only 1 (ONE) PCMCIA slot supported here,
- * which must be correctly initialized by the firmware (PPCBoot).
- */
-static int _slot_ = -1;			/* will be read from PCMCIA registers   */
-
-/* Make clock cycles and always round up */
-#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
-
-
-
-/*
- * IDE stuff.
- */
-static int
-m8xx_ide_default_irq(ide_ioreg_t base)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	if (base >= MAX_HWIFS)
-		return 0;
-
-	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
-	
-	return (ioport_dsc[base].irq);
-#else
-        return 9;
-#endif
-}
-
-static ide_ioreg_t
-m8xx_ide_default_io_base(int index)
-{
-        return index;
-}
-
-#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
-
-/*
- * The TQM850L hardware has two pins swapped! Grrrrgh!
- */
-#ifdef	CONFIG_TQM850L
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
-#else
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
-#endif
-
-#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
-#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
-#endif
-
-/*
- * See include/linux/ide.h for definition of hw_regs_t (p, base)
- */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
- */
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-static void
-m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	typedef struct {
-		ulong br;
-		ulong or;
-	} pcmcia_win_t;
-	volatile pcmcia_win_t *win;
-	volatile pcmconf8xx_t *pcmp;
-
-	uint *pgcrx;
-	u32 pcmcia_phy_base;
-	u32 pcmcia_phy_end;
-	static unsigned long pcmcia_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	if (!pcmcia_base) {
-                /*
-                 * Read out PCMCIA registers. Since the reset values
-                 * are undefined, we sure hope that they have been
-                 * set up by firmware
-		 */
-
-		/* Scan all registers for valid settings */
-		pcmcia_phy_base = 0xFFFFFFFF;
-		pcmcia_phy_end = 0;
-		/* br0 is start of brX and orX regs */
-		win = (pcmcia_win_t *) \
-			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
-		for (i = 0; i < 8; i++) {
-			if (win->or & 1) {	/* This bank is marked as valid */
-				if (win->br < pcmcia_phy_base) {
-					pcmcia_phy_base = win->br;
-				}
-				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
-					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
-				}
-				/* Check which slot that has been defined */
-				_slot_ = (win->or >> 2) & 1;
-
-			}					/* Valid bank */
-			win++;
-		}						/* for */
-
-		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
-			'A' + _slot_,
-			pcmcia_phy_base, pcmcia_phy_end,
-			pcmcia_phy_end - pcmcia_phy_base);
-
-		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
-						   pcmcia_phy_end-pcmcia_phy_base);
-
-#ifdef DEBUG
-		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
-#endif
-		/* Compute clock cycles for PIO timings */
-		for (i=0; i<6; ++i) {
-			bd_t	*binfo = (bd_t *)__res;
-
-			hold_time[i]   =
-				PCMCIA_MK_CLKS (hold_time[i],
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].setup_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].active_time =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].cycle_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
-						binfo->bi_busfreq);
-#if 0
-			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
-				i,
-				ide_pio_clocks[i].setup_time,
-				ide_pio_clocks[i].active_time,
-				ide_pio_clocks[i].hold_time,
-				ide_pio_clocks[i].cycle_time,
-				ide_pio_timings[i].setup_time,
-				ide_pio_timings[i].active_time,
-				ide_pio_timings[i].hold_time,
-				ide_pio_timings[i].cycle_time);
-#endif
-		}
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	if (_slot_ == -1) {
-		printk ("PCMCIA slot has not been defined! Using A as default\n");
-		_slot_ = 0;
-	}
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-
-#ifdef DEBUG
-	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
-		pcmp->pcmc_pipr,
-		'A' + _slot_,
-		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
-#endif /* DEBUG */
-
-	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
-		printk ("No card in slot %c: PIPR=%08x\n",
-			'A' + _slot_, (u32) pcmp->pcmc_pipr);
-		return;		/* No card in slot */
-	}
-
-	check_ide_device (pcmcia_base);
-
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-
-	base = pcmcia_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-			pcmcia_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-#ifdef CONFIG_IDE_8xx_PCCARD
-		unsigned int reg;
-
-		*irq = ioport_dsc[data_port].irq;
-		if (_slot_)
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
-		else
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
-
-		reg = *pgcrx;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
-		*pgcrx = reg;
-#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
-		*irq = ioport_dsc[data_port].irq;
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
-					(0x80000000 >> ioport_dsc[data_port].irq);
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-	/* Make sure we dont get garbage irq */
-	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
-
-	/* Enable falling edge irq */
-	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
-#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
- * MPC8xx's internal PCMCIA interface
- */
-#if defined(CONFIG_IDE_EXT_DIRECT)
-void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	u32 ide_phy_base;
-	u32 ide_phy_end;
-	static unsigned long ide_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	if (!ide_base) {
-
-		/* TODO:
-		 * - add code to read ORx, BRx
-		 */
-		ide_phy_base = CFG_ATA_BASE_ADDR;
-		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
-
-		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
-			ide_phy_base, ide_phy_end,
-			ide_phy_end - ide_phy_base);
-		
-		ide_base=(unsigned long)ioremap(ide_phy_base,
-						ide_phy_end-ide_phy_base);
-
-#ifdef DEBUG
-		printk ("IDE virt base: %08lx\n", ide_base);
-#endif
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	base = ide_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-		ide_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-		/* direct connected IDE drive, i.e. external IRQ */
-		*irq = ioport_dsc[data_port].irq;
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
-			(0x80000000 >> ioport_dsc[data_port].irq);
-}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
-
-#endif	/* CONFIG_IDE_8xx_DIRECT */
-
-
-/* -------------------------------------------------------------------- */
-
-
-/* PCMCIA Timing */
-#ifndef	PCMCIA_SHT
-#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
-#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
-#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
-#endif
-
-
-/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	volatile pcmconf8xx_t	*pcmp;
-	ulong timing, mask, reg;
-#endif
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-
-#if 1
-	printk("%s[%d] %s: best PIO mode: %d\n",
-		__FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
-
-	timing  = PCMCIA_SHT(hold_time[pio]  )
-		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
-		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
-		;
-
-#if 1
-	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
-#endif
-	if ((reg = pcmp->pcmc_por0 & mask) != 0)
-		pcmp->pcmc_por0 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por1 & mask) != 0)
-		pcmp->pcmc_por1 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por2 & mask) != 0)
-		pcmp->pcmc_por2 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por3 & mask) != 0)
-		pcmp->pcmc_por3 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por4 & mask) != 0)
-		pcmp->pcmc_por4 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por5 & mask) != 0)
-		pcmp->pcmc_por5 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por6 & mask) != 0)
-		pcmp->pcmc_por6 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por7 & mask) != 0)
-		pcmp->pcmc_por7 = reg | timing;
-
-#elif defined(CONFIG_IDE_EXT_DIRECT)
-
-	printk("%s[%d] %s: not implemented yet!\n",
-		__FILE__,__LINE__,__FUNCTION__);
-#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
-}
-
-static void
-ide_interrupt_ack (void *dev)
-{
-#ifdef CONFIG_IDE_8xx_PCCARD
-	u_int pscr, pipr;
-
-#if (PCMCIA_SOCKETS_NO == 2)
-	u_int _slot_;
-#endif
-
-	/* get interrupt sources */
-
-	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
-	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
-
-	/*
-	 * report only if both card detect signals are the same
-	 * not too nice done,
-	 * we depend on that CD2 is the bit to the left of CD1...
-	 */
-
-	if(_slot_==-1){
-	  printk("PCMCIA slot has not been defined! Using A as default\n");
-	  _slot_=0;
-	}
-
-	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
-	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
-	  printk ("card detect interrupt\n");
-	}
-	/* clear the interrupt sources */
-	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
-
-#else /* ! CONFIG_IDE_8xx_PCCARD */
-	/*
-	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
-	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
-	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
-	 * The interrupt is handled somewhere else.	-- Steven
-	 */
-#endif /* CONFIG_IDE_8xx_PCCARD */
-}
-
-
-
-/*
- * CIS Tupel codes
- */
-#define CISTPL_NULL		0x00
-#define CISTPL_DEVICE		0x01
-#define CISTPL_LONGLINK_CB	0x02
-#define CISTPL_INDIRECT		0x03
-#define CISTPL_CONFIG_CB	0x04
-#define CISTPL_CFTABLE_ENTRY_CB 0x05
-#define CISTPL_LONGLINK_MFC	0x06
-#define CISTPL_BAR		0x07
-#define CISTPL_PWR_MGMNT	0x08
-#define CISTPL_EXTDEVICE	0x09
-#define CISTPL_CHECKSUM		0x10
-#define CISTPL_LONGLINK_A	0x11
-#define CISTPL_LONGLINK_C	0x12
-#define CISTPL_LINKTARGET	0x13
-#define CISTPL_NO_LINK		0x14
-#define CISTPL_VERS_1		0x15
-#define CISTPL_ALTSTR		0x16
-#define CISTPL_DEVICE_A		0x17
-#define CISTPL_JEDEC_C		0x18
-#define CISTPL_JEDEC_A		0x19
-#define CISTPL_CONFIG		0x1a
-#define CISTPL_CFTABLE_ENTRY	0x1b
-#define CISTPL_DEVICE_OC	0x1c
-#define CISTPL_DEVICE_OA	0x1d
-#define CISTPL_DEVICE_GEO	0x1e
-#define CISTPL_DEVICE_GEO_A	0x1f
-#define CISTPL_MANFID		0x20
-#define CISTPL_FUNCID		0x21
-#define CISTPL_FUNCE		0x22
-#define CISTPL_SWIL		0x23
-#define CISTPL_END		0xff
-
-/*
- * CIS Function ID codes
- */
-#define CISTPL_FUNCID_MULTI	0x00
-#define CISTPL_FUNCID_MEMORY	0x01
-#define CISTPL_FUNCID_SERIAL	0x02
-#define CISTPL_FUNCID_PARALLEL	0x03
-#define CISTPL_FUNCID_FIXED	0x04
-#define CISTPL_FUNCID_VIDEO	0x05
-#define CISTPL_FUNCID_NETWORK	0x06
-#define CISTPL_FUNCID_AIMS	0x07
-#define CISTPL_FUNCID_SCSI	0x08
-
-/*
- * Fixed Disk FUNCE codes
- */
-#define CISTPL_IDE_INTERFACE	0x01
-
-#define CISTPL_FUNCE_IDE_IFACE	0x01
-#define CISTPL_FUNCE_IDE_MASTER	0x02
-#define CISTPL_FUNCE_IDE_SLAVE	0x03
-
-/* First feature byte */
-#define CISTPL_IDE_SILICON	0x04
-#define CISTPL_IDE_UNIQUE	0x08
-#define CISTPL_IDE_DUAL		0x10
-
-/* Second feature byte */
-#define CISTPL_IDE_HAS_SLEEP	0x01
-#define CISTPL_IDE_HAS_STANDBY	0x02
-#define CISTPL_IDE_HAS_IDLE	0x04
-#define CISTPL_IDE_LOW_POWER	0x08
-#define CISTPL_IDE_REG_INHIBIT	0x10
-#define CISTPL_IDE_HAS_INDEX	0x20
-#define CISTPL_IDE_IOIS16	0x40
-
-
-/* -------------------------------------------------------------------- */
-
-
-#define	MAX_TUPEL_SZ	512
-#define MAX_FEATURES	4
-
-static int check_ide_device (unsigned long base)
-{
-	volatile unsigned char *ident = NULL;
-	volatile unsigned char *feature_p[MAX_FEATURES];
-	volatile unsigned char *p, *start;
-	int n_features = 0;
-	unsigned char func_id = ~0;
-	unsigned char code, len;
-	unsigned short config_base = 0;
-	int found = 0;
-	int i;
-
-#ifdef DEBUG
-	printk ("PCMCIA MEM: %08lX\n", base);
-#endif
-	start = p = (volatile unsigned char *) base;
-
-	while ((p - start) < MAX_TUPEL_SZ) {
-
-		code = *p; p += 2;
-
-		if (code == 0xFF) { /* End of chain */
-			break;
-		}
-
-		len = *p; p += 2;
-#ifdef	DEBUG_PCMCIA
-		{ volatile unsigned char *q = p;
-			printk ("\nTuple code %02x  length %d\n\tData:",
-				code, len);
-
-			for (i = 0; i < len; ++i) {
-				printk (" %02x", *q);
-				q+= 2;
-			}
-		}
-#endif	/* DEBUG_PCMCIA */
-		switch (code) {
-		case CISTPL_VERS_1:
-			ident = p + 4;
-			break;
-		case CISTPL_FUNCID:
-			func_id = *p;
-			break;
-		case CISTPL_FUNCE:
-			if (n_features < MAX_FEATURES)
-				feature_p[n_features++] = p;
-			break;
-		case CISTPL_CONFIG:
-			config_base = (*(p+6) << 8) + (*(p+4));
-		default:
-			break;
-		}
-		p += 2 * len;
-	}
-
-	found = identify (ident);
-
-	if (func_id != ((unsigned char)~0)) {
-		print_funcid (func_id);
-
-		if (func_id == CISTPL_FUNCID_FIXED)
-			found = 1;
-		else
-			return (1);	/* no disk drive */
-	}
-
-	for (i=0; i<n_features; ++i) {
-		print_fixed (feature_p[i]);
-	}
-
-	if (!found) {
-		printk ("unknown card type\n");
-		return (1);
-	}
-
-	/* set level mode irq and I/O mapped device in config reg*/
-	*((unsigned char *)(base + config_base)) = 0x41;
-
-	return (0);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_funcid (int func)
-{
-	switch (func) {
-	case CISTPL_FUNCID_MULTI:
-		printk (" Multi-Function");
-		break;
-	case CISTPL_FUNCID_MEMORY:
-		printk (" Memory");
-		break;
-	case CISTPL_FUNCID_SERIAL:
-		printk (" Serial Port");
-		break;
-	case CISTPL_FUNCID_PARALLEL:
-		printk (" Parallel Port");
-		break;
-	case CISTPL_FUNCID_FIXED:
-		printk (" Fixed Disk");
-		break;
-	case CISTPL_FUNCID_VIDEO:
-		printk (" Video Adapter");
-		break;
-	case CISTPL_FUNCID_NETWORK:
-		printk (" Network Adapter");
-		break;
-	case CISTPL_FUNCID_AIMS:
-		printk (" AIMS Card");
-		break;
-	case CISTPL_FUNCID_SCSI:
-		printk (" SCSI Adapter");
-		break;
-	default:
-		printk (" Unknown");
-		break;
-	}
-	printk (" Card\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_fixed (volatile unsigned char *p)
-{
-	if (p == NULL)
-		return;
-
-	switch (*p) {
-	case CISTPL_FUNCE_IDE_IFACE:
-	    {   unsigned char iface = *(p+2);
-
-		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
-		printk (" interface ");
-		break;
-	    }
-	case CISTPL_FUNCE_IDE_MASTER:
-	case CISTPL_FUNCE_IDE_SLAVE:
-	    {   unsigned char f1 = *(p+2);
-		unsigned char f2 = *(p+4);
-
-		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
-
-		if (f1 & CISTPL_IDE_UNIQUE)
-			printk (" [unique]");
-
-		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
-
-		if (f2 & CISTPL_IDE_HAS_SLEEP)
-			printk (" [sleep]");
-
-		if (f2 & CISTPL_IDE_HAS_STANDBY)
-			printk (" [standby]");
-
-		if (f2 & CISTPL_IDE_HAS_IDLE)
-			printk (" [idle]");
-
-		if (f2 & CISTPL_IDE_LOW_POWER)
-			printk (" [low power]");
-
-		if (f2 & CISTPL_IDE_REG_INHIBIT)
-			printk (" [reg inhibit]");
-
-		if (f2 & CISTPL_IDE_HAS_INDEX)
-			printk (" [index]");
-
-		if (f2 & CISTPL_IDE_IOIS16)
-			printk (" [IOis16]");
-
-		break;
-	    }
-	}
-	printk ("\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-#define MAX_IDENT_CHARS		64
-#define	MAX_IDENT_FIELDS	4
-
-static unsigned char *known_cards[] = {
-	"ARGOSY PnPIDE D5",
-	NULL
-};
-
-static int identify  (volatile unsigned char *p)
-{
-	unsigned char id_str[MAX_IDENT_CHARS];
-	unsigned char data;
-	unsigned char *t;
-	unsigned char **card;
-	int i, done;
-
-	if (p == NULL)
-		return (0);	/* Don't know */
-
-	t = id_str;
-	done =0;
-
-	for (i=0; i<=4 && !done; ++i, p+=2) {
-		while ((data = *p) != '\0') {
-			if (data == 0xFF) {
-				done = 1;
-				break;
-			}
-			*t++ = data;
-			if (t == &id_str[MAX_IDENT_CHARS-1]) {
-				done = 1;
-				break;
-			}
-			p += 2;
-		}
-		if (!done)
-			*t++ = ' ';
-	}
-	*t = '\0';
-	while (--t > id_str) {
-		if (*t == ' ')
-			*t = '\0';
-		else
-			break;
-	}
-	printk ("Card ID: %s\n", id_str);
-
-	for (card=known_cards; *card; ++card) {
-		if (strcmp(*card, id_str) == 0) {	/* found! */
-			return (1);
-		}
-	}
-
-	return (0);	/* don't know */
-}
-
-void m8xx_ide_init(void)
-{
-	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
-	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
-	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pci.c linux-2.4.21-rc3/drivers/ide/ide-pci.c
--- linux-2.4.20/drivers/ide/ide-pci.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1016 +0,0 @@
-/*
- *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
- *
- *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- *  This module provides support for automatic detection and
- *  configuration of all PCI IDE interfaces present in a system.  
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
-#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
-#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
-#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
-#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
-#define DEVID_ICH0	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
-#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
-#define DEVID_ICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
-#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
-#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_ICH2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_ICH2M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_ICH3M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_ICH3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
-#define DEVID_ICH4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
-#define DEVID_CICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
-#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
-#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
-#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
-#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
-#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
-#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
-#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_PDC20270  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270})
-#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_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
-#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})
-#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
-#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
-#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})
-#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
-#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
-#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
-#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
-#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
-#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
-#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
-#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
-#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
-#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
-#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
-#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
-#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
-#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
-#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
-#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
-#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
-#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
-#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
-#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
-#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
-#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
-#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
-#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
-#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 *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
-#define PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#define PCI_AEC62XX	NULL
-#define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	IDE_NO_DRIVER
-#define DMA_AEC62XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
-#define PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#define PCI_ALI15X3	NULL
-#define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	IDE_NO_DRIVER
-#define DMA_ALI15X3	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
-#define PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#define PCI_AMD74XX	NULL
-#define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	IDE_NO_DRIVER
-#define DMA_AMD74XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
-#define PCI_CMD64X	&pci_init_cmd64x
-#define ATA66_CMD64X	&ata66_cmd64x
-#define INIT_CMD64X	&ide_init_cmd64x
-#else
-#define PCI_CMD64X	NULL
-#define ATA66_CMD64X	NULL
-#ifdef __sparc_v9__
-#define INIT_CMD64X	IDE_IGNORE
-#else
-#define INIT_CMD64X	IDE_NO_DRIVER
-#endif
-#endif
-
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
-extern void ide_init_cy82c693(ide_hwif_t *);
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#define PCI_CY82C693	NULL
-#define INIT_CY82C693	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
-extern void ide_init_cs5530(ide_hwif_t *);
-#define PCI_CS5530	&pci_init_cs5530
-#define INIT_CS5530	&ide_init_cs5530
-#else
-#define PCI_CS5530	NULL
-#define INIT_CS5530	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
-extern void ide_init_hpt34x(ide_hwif_t *);
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt363_shared_irq;
-extern byte hpt363_shared_pin;
-extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
-#define PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
-#else
-static byte hpt363_shared_irq;
-static byte hpt363_shared_pin;
-#define PCI_HPT366	NULL
-#define ATA66_HPT366	NULL
-#define INIT_HPT366	IDE_NO_DRIVER
-#define DMA_HPT366	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define INIT_OPTI621	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
-#define PCI_PDCADMA	&pci_init_pdcadma
-#define ATA66_PDCADMA	&ata66_pdcadma
-#define INIT_PDCADMA	&ide_init_pdcadma
-#define DMA_PDCADMA	&ide_dmacapable_pdcadma
-#else
-#define PCI_PDCADMA	IDE_IGNORE
-#define ATA66_PDCADMA	IDE_IGNORE
-#define INIT_PDCADMA	IDE_IGNORE
-#define DMA_PDCADMA	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern unsigned int pci_init_piix(struct pci_dev *, const char *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-#define PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
-extern void ide_init_it8172(ide_hwif_t *);
-#define PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
-#endif
-
-#define INIT_SAMURAI	NULL
-
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#else
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
-#define PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#define PCI_SIS5513	NULL
-#define ATA66_SIS5513	NULL
-#define INIT_SIS5513	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
-extern unsigned int ata66_slc90e66(ide_hwif_t *);
-extern void ide_init_slc90e66(ide_hwif_t *);
-#define PCI_SLC90E66	&pci_init_slc90e66
-#define ATA66_SLC90E66	&ata66_slc90e66
-#define INIT_SLC90E66	&ide_init_slc90e66
-#else
-#define PCI_SLC90E66	NULL
-#define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define PCI_W82C105	&pci_init_sl82c105
-#define DMA_W82C105	&dma_init_sl82c105
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define PCI_W82C105	NULL
-#define DMA_W82C105	NULL
-#define INIT_W82C105	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
-#else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	IDE_NO_DRIVER
-#define DMA_VIA82CXXX	NULL
-#endif
-
-typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
-	char			*name;
-	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
-	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void 			(*init_hwif)(ide_hwif_t *hwif);
-	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
-	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
-	unsigned int		extra;
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_ICH0,	"ICH0", 	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH,	"ICH",  	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2,	"ICH2", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2M,	"ICH2M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3M,	"ICH3M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3,	"ICH3", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH4,	"ICH4", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_CICH,	"C-ICH",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifndef 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_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 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{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,	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_PDC20270,"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_PDC20276,"PDC20276",	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 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{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 },
-#ifndef CONFIG_BLK_DEV_CMD680
-	{DEVID_CMD680,	"CMD680",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#else /* CONFIG_BLK_DEV_CMD680 */
-	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#endif /* !CONFIG_BLK_DEV_CMD680 */
-	{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 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	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_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 },
-	{DEVID_CSB5,	"ServerWorks CSB5",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	PCI_IT8172,	NULL,	INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
-
-/*
- * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
- * settings of split-mirror pci-config space, place chipset into init-mode,
- * and/or preserve an interrupt if the card is not native ide support.
- */
-static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT366:
-		case PCI_DEVICE_ID_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return dev->irq;
-		default:
-			break;
-	}
-	return 0;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
-{
-	int h;
-	ide_hwif_t *hwif;
-
-	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name);
-			return NULL;	/* already claimed */
-		}
-	}
-	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
-	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
-	 *
-	 * Unless there is a bootable card that does not use the standard
-	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
-	 */
-	if (bootable) {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			hwif = &ide_hwifs[h];
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	} else {
-		for (h = 2; h < MAX_HWIFS; ++h) {
-			hwif = ide_hwifs + h;
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	}
-	for (h = 0; h < 2; ++h) {
-		hwif = ide_hwifs + h;
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
-	}
-	printk("%s: too many IDE interfaces, no room in table\n", name);
-	return NULL;
-}
-
-static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
-{
-	byte reg, progif = 0;
-
-	/*
-	 * Place both IDE interfaces into PCI "native" mode:
-	 */
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-		if ((progif & 0xa) != 0xa) {
-			printk("%s: device not capable of full native PCI mode\n", name);
-			return 1;
-		}
-		printk("%s: placing both ports into native PCI mode\n", name);
-		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
-			return 1;
-		}
-	}
-	/*
-	 * Setup base registers for IDE command/control spaces for each interface:
-	 */
-	for (reg = 0; reg < 4; reg++) {
-		struct resource *res = dev->resource + reg;
-		if ((res->flags & IORESOURCE_IO) == 0)
-			continue;
-		if (!res->start) {
-			printk("%s: Missing I/O address #%d\n", name, reg);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
-	unsigned short pcicmd = 0, tried_config = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
-	unsigned int class_rev;
-	static int secondpdc = 0;
-
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		autodma = 1;
-#endif
-
-	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)) {
-		if(pci_enable_device_bars(dev, 1<<4))
-		{
-			printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
-			return;
-		}
-		printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name);
-	}
-
-check_if_enabled:
-	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", d->name);
-		return;
-	}
-	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
-		/*
-		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
-		 *  (or possibly the device is using a "legacy header" for IRQs).
-		 * Maybe the user deliberately *disabled* the device,
-		 * but we'll eventually ignore it again if no drives respond.
-		 */
-		if (tried_config++
-		 || ide_setup_pci_baseregs(dev, d->name)
-		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", d->name);
-			return;
-		}
-		autodma = 0;	/* default DMA off if we had to configure it here */
-		goto check_if_enabled;
-	}
-	if (tried_config)
-		printk("%s: device enabled (Linux)\n", d->name);
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
-		/* see comments in hpt34x.c on why..... */
-		char *chipset_names[] = {"HPT343", "HPT345"};
-		strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
-		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	}
-
-	printk("%s: chipset revision %d\n", d->name, class_rev);
-
-	/*
-	 * Can we trust the reported IRQ?
-	 */
-	pciirq = dev->irq;
-	
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
-	{
-	    /*  By rights we want to ignore these, but the Promise Fastrak
-		 *	people have some strange ideas about proprietary so we have
-		 *	to act otherwise on those. The supertrak however we need
-		 *	to skip 
-		 */
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
-		{
-			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
-			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
-			   dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
-			{
-				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
-				return;
-			}
-		}
-		/* Its attached to something else, just a random bridge.
-		   Suspect a fastrak and fall through */
-	}
-
-	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
-		/*
-		 * This allows offboard ide-pci cards the enable a BIOS,
-		 * verify interrupt settings of split-mirror pci-config
-		 * space, place chipset into init-mode, and/or preserve
-		 * an interrupt if the card is not native ide support.
-		 */
-		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
-	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", d->name);
-		pciirq = 0;
-	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
-		pciirq = 0;
-	} else {
-		if (d->init_chipset)
-			(void) d->init_chipset(dev, d->name);
-#ifdef __sparc__
-		printk("%s: 100%% native mode on irq %s\n",
-		       d->name, __irq_itoa(pciirq));
-#else
-		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
-#endif
-	}
-
-	/*
-	 * Set up the IDE ports
-	 */
-	for (port = 0; port <= 1; ++port) {
-		unsigned long base = 0, ctl = 0;
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller, the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-			
-		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
-			continue;	/* port not enabled */
-controller_ok:			
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03))
-			return;
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->resource[(2*port)+1].start;
-			base = dev->resource[2*port].start;
-			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
-			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-				printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@linux-ide.org>.\n", d->name);
-#if 0
-				/* FIXME! This really should check that it really gets the IO/MEM part right! */
-				continue;
-#endif
-			}
-		}
-		if ((ctl && !base) || (base && !ctl)) {
-			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
-			continue;
-		}
-		if (!ctl)
-			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		if (!base)
-			base = port ? 0x170 : 0x1f0;	/* use default value */
-		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
-			continue;	/* no room in ide_hwifs[] */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_dev = dev;
-		hwif->pci_devid = d->devid;
-		hwif->channel = port;
-		if (!hwif->irq)
-			hwif->irq = pciirq;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
-				hwif->serialized = 1;
-				mate->serialized = 1;
-			}
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
-			hwif->irq = hwif->channel ? 15 : 14;
-			goto bypass_umc_dma;
-		}
-		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 {
-			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
-			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_PDC20270) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
-		    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);
-			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
-				/*
- 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
- 	 			 */
-		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
-					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
-				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
-				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
-					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
-					dma_base = 0;
-				}
-			}
-			if (dma_base) {
-				if (d->dma_init) {
-					d->dma_init(hwif, dma_base);
-				} else {
-					ide_setup_dma(hwif, dma_base, 8);
-				}
-			} else {
-				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
-			}
-		}
-#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 */
-			d->init_hwif(hwif);
-		mate = hwif;
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		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;
-	ide_pci_device_t *d2;
-	unsigned char pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"};
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	if (class_rev > 5)
-		class_rev = 5;
-	
-	strcpy(d->name, chipset_names[class_rev]);
-
-	switch(class_rev) {
-		case 4:
-		case 3:	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-			ide_setup_pci_device(dev, d);
-			return;
-		default:	break;
-	}
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-			hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
-			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
-			if (hpt363_shared_pin && hpt363_shared_irq) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
-#if 0
-				/* I forgot why I did this once, but it fixed something. */
-				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
-				printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
-				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
-			}
-			break;
-		}
-	}
-	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);
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c.
- * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
- */
-void __init ide_scan_pcidev (struct pci_dev *dev)
-{
-	ide_pci_devid_t		devid;
-	ide_pci_device_t	*d;
-
-	devid.vid = dev->vendor;
-	devid.did = dev->device;
-	for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
-	if (d->init_hwif == IDE_IGNORE)
-		printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
-		return;
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* CY82C693 is more than only a IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* IT8172G is also more than only an IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
-		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_PDC20270))
-		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 bus %02x device %02x, VID=%04x, DID=%04x\n",
-			       d->name, dev->bus->number, dev->devfn, devid.vid, devid.did);
-		else
-			printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-		ide_setup_pci_device(dev, d);
-	}
-}
-
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev;
-
-	if (!scan_direction) {
-		pci_for_each_dev(dev) {
-			ide_scan_pcidev(dev);
-		}
-	} else {
-		pci_for_each_dev_reverse(dev) {
-			ide_scan_pcidev(dev);
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pmac.c linux-2.4.21-rc3/drivers/ide/ide-pmac.c
--- linux-2.4.20/drivers/ide/ide-pmac.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-pmac.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1794 +0,0 @@
-/*
- * linux/drivers/ide/ide-pmac.c
- *
- * Support for IDE interfaces on PowerMacs.
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/mediabay.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-#include "ide_modes.h"
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
-
-#define IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT	500
-
-struct pmac_ide_hwif {
-	ide_ioreg_t			regbase;
-	int				irq;
-	int				kind;
-	int				aapl_bus_id;
-	struct device_node*		node;
-	u32				timings[2];
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* Those fields are duplicating what is in hwif. We currently
-	 * can't use the hwif ones because of some assumptions that are
-	 * beeing done by the generic code about the kind of dma controller
-	 * and format of the dma table. This will have to be fixed though.
-	 */
-	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table_cpu;
-	dma_addr_t			dma_table_dma;
-	struct scatterlist*		sg_table;
-	int				sg_nents;
-	int				sg_dma_direction;
-#endif
-	
-} pmac_ide[MAX_HWIFS] __pmacdata;
-
-static int pmac_ide_count;
-
-enum {
-	controller_ohare,	/* OHare based */
-	controller_heathrow,	/* Heathrow/Paddington */
-	controller_kl_ata3,	/* KeyLargo ATA-3 */
-	controller_kl_ata4,	/* KeyLargo ATA-4 */
-	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG	0x200
-#define IDE_INTERRUPT		0x300
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
-#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- * 
- * 3 Values can be programmed:
- *  - Write data setup, which appears to match the cycle time. They
- *    also call it DIOW setup.
- *  - Ready to pause time (from spec)
- *  - Address setup. That one is weird. I don't see where exactly
- *    it fits in UDMA cycles, I got it's name from an obscure piece
- *    of commented out code in Darwin. They leave it to 0, we do as
- *    well, despite a comment that would lead to think it has a
- *    min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads.
- */
-#define TR_66_UDMA_MASK			0xfff00000
-#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT	29
-#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT	25
-#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT	21
-#define TR_66_MDMA_MASK			0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT	15
-#define TR_66_MDMA_ACCESS_MASK		0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT		10
-#define TR_66_PIO_MASK			0x000003ff
-#define TR_66_PIO_RECOVERY_MASK		0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT	5
-#define TR_66_PIO_ACCESS_MASK		0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT		0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- * 
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK			0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT	16
-#define TR_33_MDMA_ACCESS_MASK		0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT		11
-#define TR_33_MDMA_HALFTICK		0x00200000
-#define TR_33_PIO_MASK			0x000007ff
-#define TR_33_PIO_E			0x00000400
-#define TR_33_PIO_RECOVERY_MASK		0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT	5
-#define TR_33_PIO_ACCESS_MASK		0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT		0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA			0x80000000
-#define IDE_INTR_DEVICE			0x40000000
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-/* Rounded Multiword DMA timings
- * 
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
-	int	accessTime;
-	int	recoveryTime;
-	int	cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  75,  75, 150 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 150, 150, 300 },
-    { 120, 120, 240 },
-    {  90, 120, 210 },
-    {  90,  90, 180 },
-    {  90,  60, 150 },
-    {  90,  30, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  90,  75, 165 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-/* Ultra DMA timings (rounded) */
-struct {
-	int	addrSetup; /* ??? */
-	int	rdy2pause;
-	int	wrDataSetup;
-} udma_timings[] __pmacdata =
-{
-    {   0, 180,  120 },	/* Mode 0 */
-    {   0, 150,  90 },	/*      1 */
-    {   0, 120,  60 },	/*      2 */
-    {   0, 90,   45 },	/*      3 */
-    {   0, 90,   30 }	/*      4 */
-};
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS		256
-
-/* Wait 2s for disk to answer on IDE bus after
- * enable operation.
- * NOTE: There is at least one case I know of a disk that needs about 10sec
- *       before anwering on the bus. I beleive we could add a kernel command
- *       line arg to override this delay for such cases.
- */
-#define IDE_WAKEUP_DELAY_MS	2000
-
-static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier idepmac_sleep_notifier = {
-	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *);
-static struct notifier_block pmac_ide_reboot_notifier = {
-	pmac_ide_notify_reboot,
-	NULL,
-	0
-};
-
-static int __pmac
-pmac_ide_find(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_ioreg_t base;
-	int i;
-	
-	for (i=0; i<pmac_ide_count; i++) {
-		base = pmac_ide[i].regbase;
-		if (base && base == hwif->io_ports[0])
-			return i;
-	}
-	return -1;
-}
-
-/*
- * N.B. this can't be an initfunc, because the media-bay task can
- * call ide_[un]register at any time.
- */
-void __pmac
-pmac_ide_init_hwif_ports(hw_regs_t *hw,
-			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
-			      int *irq)
-{
-	int i, ix;
-
-	if (data_port == 0)
-		return;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (data_port == pmac_ide[ix].regbase)
-			break;
-
-	if (ix >= MAX_HWIFS) {
-		/* Probably a PCI interface... */
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-		return;
-	}
-
-	for (i = 0; i < 8; ++i)
-		hw->io_ports[i] = data_port + i * 0x10;
-	hw->io_ports[8] = data_port + 0x160;
-
-	if (irq != NULL)
-		*irq = pmac_ide[ix].irq;
-
-	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
-	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
-	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-		if (!noautodma)
-			ide_hwifs[ix].autodma = 1;
-#endif
-	}
-}
-
-#if 0
-/* This one could be later extended to handle CMD IDE and be used by some kind
- * of /proc interface. I want to be able to get the devicetree path of a block
- * device for yaboot configuration
- */
-struct device_node*
-pmac_ide_get_devnode(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return NULL;
-	return pmac_ide[i].node;
-}
-#endif
-
-/* Setup timings for the selected drive (master/slave). I still need to verify if this
- * is enough, I beleive selectproc will be called whenever an IDE command is started,
- * but... */
-static void __pmac
-pmac_ide_selectproc(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-
-	if (drive->select.b.unit & 0x01)
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[1]);
-	else
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[0]);
-	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-}
-
-
-/* Note: We don't use the generic routine here because for some
- * yet unexplained reasons, it cause some media-bay CD-ROMs to
- * lockup the bus. Strangely, this new version of the code is
- * almost identical to the generic one and works, I've not yet
- * managed to figure out what bit is causing the lockup in the
- * generic code, possibly a timing issue...
- * 
- * --BenH
- */
-static int __pmac
-wait_for_ready(ide_drive_t *drive)
-{
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
-	byte stat;
-
-	while(--timeout) {
-		stat = GET_STAT();
-		if(!(stat & BUSY_STAT)) {
-			if (drive->ready_stat == 0)
-				break;
-			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
-				break;
-		}
-		mdelay(1);
-	}
-	if((stat & ERR_STAT) || timeout <= 0) {
-		if (stat & ERR_STAT) {
-			printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat);
-		}
-		return 1;
-	}
-	return 0;
-}
-
-static int __pmac
-pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
-{
-	int result = 1;
-	ide_hwif_t *hwif = HWIF(drive);
-	
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	(void)GET_STAT(); /* Get rid of pending error state */
-	if(wait_for_ready(drive)) {
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
-		goto out;
-	}
-	udelay(10);
-	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(command, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	udelay(1);
-	result = wait_for_ready(drive);
-	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	if (result)
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
-out:
-	SELECT_MASK(HWIF(drive), drive, 0);
-	if (result == 0) {
-		drive->id->dma_ultra &= ~0xFF00;
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		switch(command) {
-			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-			default: break;
-		}
-	}
-	enable_irq(hwif->irq);
-	return result;
-}
-
-/* Calculate PIO timings */
-static void __pmac
-pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int i;
-	u32 *timings;
-	unsigned accessTicks, recTicks;
-	unsigned accessTime, recTime;
-	
-	i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-		
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[i].timings[1];
-	else
-		timings = &pmac_ide[i].timings[0];
-
-	recTime = d.cycle_time - ide_pio_timings[pio].active_time
-			- ide_pio_timings[pio].setup_time;
-	recTime = max(recTime, 150U);
-	accessTime = ide_pio_timings[pio].active_time;
-	accessTime = max(accessTime, 150U);
-	if (pmac_ide[i].kind == controller_kl_ata4 ||
-		pmac_ide[i].kind == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_66_PIO_MASK) |
-				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell */
-		int ebit = 0;
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 4U);
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 5U) - 4;
-		if (recTicks > 9) {
-			recTicks--; /* guess, but it's only for PIO0, so... */
-			ebit = 1;
-		}
-		*timings = ((*timings) & ~TR_33_PIO_MASK) |
-				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
-		if (ebit)
-			*timings |= TR_33_PIO_E;
-	}
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
-		pio,  *timings);
-#endif	
-		
-	if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
-		pmac_ide_selectproc(drive);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int __pmac
-set_timings_udma(u32 *timings, byte speed)
-{
-	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
-	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
-	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
-	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
-
-	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
-			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
-			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
-			TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-
-	return 0;
-}
-
-static int __pmac
-set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
-{
-	int cycleTime, accessTime, recTime;
-	unsigned accessTicks, recTicks;
-	struct mdma_timings_t* tm;
-	int i;
-
-	/* Get default cycle time for mode */
-	switch(speed & 0xf) {
-		case 0: cycleTime = 480; break;
-		case 1: cycleTime = 150; break;
-		case 2: cycleTime = 120; break;
-		default:
-			return -1;
-	}
-	/* Adjust for drive */
-	if (drive_cycle_time && drive_cycle_time > cycleTime)
-		cycleTime = drive_cycle_time;
-	/* OHare limits according to some old Apple sources */	
-	if ((intf_type == controller_ohare) && (cycleTime < 150))
-		cycleTime = 150;
-	/* Get the proper timing array for this controller */
-	switch(intf_type) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			tm = mdma_timings_66;
-			break;
-		case controller_kl_ata3:
-			tm = mdma_timings_33k;
-			break;
-		default:
-			tm = mdma_timings_33;
-			break;
-	}
-	/* Lookup matching access & recovery times */
-	i = -1;
-	for (;;) {
-		if (tm[i+1].cycleTime < cycleTime)
-			break;
-		i++;
-	}
-	if (i < 0)
-		return -1;
-	cycleTime = tm[i].cycleTime;
-	accessTime = tm[i].accessTime;
-	recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
-		cycleTime, accessTime, recTime);
-#endif	
-	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 0x1U);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 0x3U);
-		/* Clear out mdma bits and disable udma */
-		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
-			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
-			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
-	} else if (intf_type == controller_kl_ata3) {
-		/* 33Mhz cell on KeyLargo */
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 1U);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell on others */
-		int halfTick = 0;
-		int origAccessTime = accessTime;
-		int origRecTime = recTime;
-		
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 2U) - 1;
-		recTicks = min(recTicks, 0x1fU);
-		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
-		if ((accessTicks > 1) &&
-		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-            		halfTick = 1;
-			accessTicks--;
-		}
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-		if (halfTick)
-			*timings |= TR_33_MDMA_HALFTICK;
-	}
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-	return 0;
-}
-#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-/* You may notice we don't use this function on normal operation,
- * our, normal mdma function is supposed to be more precise
- */
-static int __pmac
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int intf		= pmac_ide_find(drive);
-	int unit		= (drive->select.b.unit & 0x01);
-	int ret			= 0;
-	u32 *timings;
-
-	if (intf < 0)
-		return 1;
-		
-	timings = &pmac_ide[intf].timings[unit];
-	
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-			if (pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (pmac_ide[intf].kind != controller_kl_ata4 &&
-				pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-			ret = set_timings_udma(timings, speed);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
-			break;
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			return 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pmac_ide_tuneproc(drive, speed & 0x07);
-			break;
-		default:
-			ret = 1;
-	}
-	if (ret)
-		return ret;
-
-	ret = pmac_ide_do_setfeature(drive, speed);
-	if (ret)
-		return ret;
-		
-	pmac_ide_selectproc(drive);	
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-static void __pmac
-sanitize_timings(int i)
-{
-	unsigned value;
-	
-	switch(pmac_ide[i].kind) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			value = 0x0008438c;
-			break;
-		case controller_kl_ata3:
-			value = 0x00084526;
-			break;
-		case controller_heathrow:
-		case controller_ohare:
-		default:
-			value = 0x00074526;
-			break;
-	}
-	pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
-}
-
-ide_ioreg_t __pmac
-pmac_ide_get_base(int index)
-{
-	return pmac_ide[index].regbase;
-}
-
-int __pmac
-pmac_ide_check_base(ide_ioreg_t base)
-{
-	int ix;
-	
- 	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return ix;
-	return -1;
-}
-
-int __pmac
-pmac_ide_get_irq(ide_ioreg_t base)
-{
-	int ix;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return pmac_ide[ix].irq;
-	return 0;
-}
-
-static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
-
-kdev_t __init
-pmac_find_ide_boot(char *bootdevice, int n)
-{
-	int i;
-	
-	/*
-	 * Look through the list of IDE interfaces for this one.
-	 */
-	for (i = 0; i < pmac_ide_count; ++i) {
-		char *name;
-		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
-			continue;
-		name = pmac_ide[i].node->full_name;
-		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_ide_probe(void)
-{
-	struct device_node *np;
-	int i;
-	struct device_node *atas;
-	struct device_node *p, **pp, *removables, **rp;
-	unsigned long base;
-	int irq, big_delay;
-	ide_hwif_t *hwif;
-
-	if (_machine != _MACH_Pmac)
-		return;
-	pp = &atas;
-	rp = &removables;
-	p = find_devices("ATA");
-	if (p == NULL)
-		p = find_devices("IDE");
-	if (p == NULL)
-		p = find_type_devices("ide");
-	if (p == NULL)
-		p = find_type_devices("ata");
-	/* Move removable devices such as the media-bay CDROM
-	   on the PB3400 to the end of the list. */
-	for (; p != NULL; p = p->next) {
-		if (p->parent && p->parent->type
-		    && strcasecmp(p->parent->type, "media-bay") == 0) {
-			*rp = p;
-			rp = &p->next;
-		} else {
-			*pp = p;
-			pp = &p->next;
-		}
-	}
-	*rp = NULL;
-	*pp = removables;
-	big_delay = 0;
-
-	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
-		struct device_node *tp;
-		struct pmac_ide_hwif* pmhw;
-		int *bidp;
-		int in_bay = 0;
-		u8 pbus, pid;
-		struct pci_dev *pdev = NULL;
-
-		/*
-		 * If this node is not under a mac-io or dbdma node,
-		 * leave it to the generic PCI driver.
-		 */
-		for (tp = np->parent; tp != 0; tp = tp->parent)
-			if (tp->type && (strcmp(tp->type, "mac-io") == 0
-					 || strcmp(tp->type, "dbdma") == 0))
-				break;
-		if (tp == 0)
-			continue;
-
-		if (np->n_addrs == 0) {
-			printk(KERN_WARNING "ide: no address for device %s\n",
-			       np->full_name);
-			continue;
-		}
-
-		/* We need to find the pci_dev of the mac-io holding the
-		 * IDE interface
-		 */
-		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
-			pdev = pci_find_slot(pbus, pid);
-		if (pdev == NULL)
-			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
-			       np->full_name);
-
-		/*
-		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
-		 */
-		while (i < MAX_HWIFS
-		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
-			++i;
-		if (i >= MAX_HWIFS)
-			break;
-		pmhw = &pmac_ide[i];
-
-		/*
-		 * Some older OFs have bogus sizes, causing request_OF_resource
-		 * to fail. We fix them up here
-		 */
-		if (np->addrs[0].size > 0x1000)
-			np->addrs[0].size = 0x1000;
-		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
-			np->addrs[1].size = 0x100;
-
-		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
-			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
-			continue;
-		}
-
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
-
-		/* XXX This is bogus. Should be fixed in the registry by checking
-		   the kind of host interrupt controller, a bit like gatwick
-		   fixes in irq.c
-		 */
-		if (np->n_intrs == 0) {
-			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
-			       np->full_name);
-			irq = 13;
-		} else {
-			irq = np->intrs[0].line;
-		}
-		pmhw->regbase = base;
-		pmhw->irq = irq;
-		pmhw->node = np;
-		if (device_is_compatible(np, "keylargo-ata")) {
-			if (strcmp(np->name, "ata-4") == 0)
-				pmhw->kind = controller_kl_ata4;
-			else
-				pmhw->kind = controller_kl_ata3;
-		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmhw->kind = controller_heathrow;
-		else
-			pmhw->kind = controller_ohare;
-
-		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmhw->aapl_bus_id =  bidp ? *bidp : 0;
-
-		if (pmhw->kind == controller_kl_ata4) {
-			char* cable = get_property(np, "cable-type", NULL);
-			if (cable && !strncmp(cable, "80-", 3))
-				pmhw->kind = controller_kl_ata4_80;
-		}
-
-		/* Make sure we have sane timings */
-		sanitize_timings(i);
-
-		if (np->parent && np->parent->name
-		    && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
-			media_bay_set_ide_infos(np->parent,base,irq,i);
-#endif /* CONFIG_PMAC_PBOOK */
-			in_bay = 1;
-			if (!bidp)
-				pmhw->aapl_bus_id = 1;
-		} else if (pmhw->kind == controller_ohare) {
-			/* The code below is having trouble on some ohare machines
-			 * (timing related ?). Until I can put my hand on one of these
-			 * units, I keep the old way
-			 */
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-		} else {
- 			/* This is necessary to enable IDE when net-booting */
-			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmhw->aapl_bus_id);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1);
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1);
-			mdelay(10);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0);
-			big_delay = 1;
-		}
-
-		hwif = &ide_hwifs[i];
-		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
-		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->chipset = ide_pmac;
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
-		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
-		hwif->pci_dev = pdev;
-		hwif->drives[0].unmask = 1;
-		hwif->drives[1].unmask = 1;
-#ifdef CONFIG_PMAC_PBOOK
-		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
-			hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (np->n_addrs >= 2) {
-			/* has a DBDMA controller channel */
-			pmac_ide_setup_dma(np, i);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-		++i;
-	}
-	pmac_ide_count = i;
-	if (big_delay)
-		mdelay(IDE_WAKEUP_DELAY_MS);
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-	register_reboot_notifier(&pmac_ide_reboot_notifier);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-static void __init 
-pmac_ide_setup_dma(struct device_node *np, int ix)
-{
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-
-	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
-		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
-		return;
-	}
-
-	pmif->dma_regs =
-		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
-
-	/*
-	 * Allocate space for the DBDMA commands.
-	 * The +2 is +1 for the stop command and +1 to allow for
-	 * aligning the start address to a multiple of 16 bytes.
-	 */
-	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
-		ide_hwifs[ix].pci_dev,
-		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-		&pmif->dma_table_dma);
-	if (pmif->dma_table_cpu == NULL) {
-		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-		       ide_hwifs[ix].name);
-		return;
-	}
-
-	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
-				 GFP_KERNEL);
-	if (pmif->sg_table == NULL) {
-		pci_free_consistent(	ide_hwifs[ix].pci_dev,
-					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-				    	pmif->dma_table_cpu, pmif->dma_table_dma);
-		return;
-	}
-	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-	if (!noautodma)
-		ide_hwifs[ix].autodma = 1;
-#endif
-}
-
-static int
-pmac_ide_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct buffer_head *bh;
-	struct scatterlist *sg = pmif->sg_table;
-	unsigned long lastdataend = ~0UL;
-	int nents = 0;
-
-	if (hwif->sg_dma_active)
-		BUG();
-
-	if (rq->cmd == READ)
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-
-	bh = rq->bh;
-	do {
-		struct scatterlist *sge;
-		unsigned int size = bh->b_size;
-
-		/* continue segment from before? */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents-1].length += size;
-			lastdataend += size;
-			continue;
-		}
-
-		/* start new segment */
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if ((unsigned long)bh->b_data < PAGE_SIZE)
-				BUG();
-			sge->address = bh->b_data;
-		}
-		sge->length = size;
-		lastdataend = bh_phys(bh) + size;
-		nents++;
-	} while ((bh = bh->b_reqnext) != NULL);
-
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-static int
-pmac_ide_raw_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
-	int sector_count = rq->nr_sectors;
-
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
-	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
-	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++;
-   
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
-{
-	struct dbdma_cmd *table;
-	int i, count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
-	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
-	struct scatterlist *sg;
-
-	/* DMA table is already aligned */
-	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
-
-	/* Make sure DMA controller is stopped (necessary ?) */
-	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
-	while (in_le32(&dma->status) & RUN)
-		udelay(1);
-
-	/* Build sglist */
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
-	else
-		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
-	if (!i)
-		return 0;
-
-	/* Build DBDMA commands list */
-	sg = pmac_ide[ix].sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		while (cur_len) {
-			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-			if (++count >= MAX_DCMDS) {
-				printk(KERN_WARNING "%s: DMA table too small\n",
-				       drive->name);
-				return 0; /* revert to PIO for this request */
-			}
-			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
-			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, cur_addr);
-			table->cmd_dep = 0;
-			table->xfer_status = 0;
-			table->res_count = 0;
-			cur_addr += tc;
-			cur_len -= tc;
-			++table;
-		}
-		sg++;
-		i--;
-	}
-
-	/* convert the last command to an input/output last command */
-	if (count)
-		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
-	else
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
-	/* add the stop command to the end of the list */
-	memset(table, 0, sizeof(struct dbdma_cmd));
-	out_le16(&table->command, DBDMA_STOP);
-
-	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
-	return 1;
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	struct scatterlist *sg = pmac_ide[ix].sg_table;
-	int nents = pmac_ide[ix].sg_nents;
-
-	if (nents) {
-		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
-		pmac_ide[ix].sg_nents = 0;
-	}
-}
-
-static __inline__ unsigned char
-dma_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return XFER_MW_DMA_2;
-	if(bits & 0x02)
-		return XFER_MW_DMA_1;
-	if(bits & 0x01)
-		return XFER_MW_DMA_0;
-	return 0;
-}
-
-static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits, int high_speed)
-{
-	if (high_speed) {
-		if(bits & 0x10)
-			return XFER_UDMA_4;
-		if(bits & 0x08)
-			return XFER_UDMA_3;
-	}
-	if(bits & 0x04)
-		return XFER_UDMA_2;
-	if(bits & 0x02)
-		return XFER_UDMA_1;
-	if(bits & 0x01)
-		return XFER_UDMA_0;
-	return 0;
-}
-
-/* Calculate MultiWord DMA timings */
-static int __pmac
-pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
-{
-	byte bits = drive->id->dma_mword & 0x07;
-	byte feature = dma_bits_to_command(bits);
-	u32 *timings;
-	int drive_cycle_time;
-	struct hd_driveid *id = drive->id;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
-	    	return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-	
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	/* Check if drive provide explicit cycle time */
-	if ((id->field_valid & 2) && (id->eide_dma_time))
-		drive_cycle_time = id->eide_dma_time;
-	else
-		drive_cycle_time = 0;
-
-	/* Calculate controller timings */
-	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-/* Calculate Ultra DMA timings */
-static int __pmac
-pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
-{
-	byte bits = drive->id->dma_ultra & 0x1f;
-	byte feature = udma_bits_to_command(bits, high_speed);
-	u32 *timings;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-		printk(KERN_WARNING "%s: Failed !\n", drive->name);
-		return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	set_timings_udma(timings, feature);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-static int __pmac
-pmac_ide_check_dma(ide_drive_t *drive)
-{
-	int ata4, udma, idx;
-	struct hd_driveid *id = drive->id;
-	int enable = 1;
-
-	drive->using_dma = 0;
-	
-	idx = pmac_ide_find(drive);
-	if (idx < 0)
-		return 0;
-		
-	if (drive->media == ide_floppy)
-		enable = 0;
-	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
-		enable = 0;
-	if (check_drive_lists(drive, BAD_DMA_DRIVE))
-		enable = 0;
-
-	udma = 0;
-	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
-		pmac_ide[idx].kind == controller_kl_ata4_80);
-			
-	if(enable) {
-		if (ata4 && (drive->media == ide_disk) &&
-		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
-			/* UltraDMA modes. */
-			drive->using_dma = pmac_ide_udma_enable(drive, idx,
-				pmac_ide[idx].kind == controller_kl_ata4_80);
-		}
-		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
-			/* Normal MultiWord DMA modes. */
-			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
-		}
-		OUT_BYTE(0, IDE_CONTROL_REG);
-		/* Apply settings to controller */
-		pmac_ide_selectproc(drive);
-	}
-	return 0;
-}
-
-static inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
-
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
-
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
-static int __pmac
-pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	int ix, dstat;
-	volatile struct dbdma_regs *dma;
-	byte unit = (drive->select.b.unit & 0x01);
-	byte ata4;
-	int reading = 0;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return 0;		
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-	
-	switch (func) {
-	case ide_dma_off:
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	case ide_dma_off_quietly:
-		drive->using_dma = 0;
-		pmac_ide_toggle_bounce(drive, 0);
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		pmac_ide_check_dma(drive);
-		if (drive->using_dma)
-			pmac_ide_toggle_bounce(drive, 1);
-		break;
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		SELECT_READ_WRITE(HWIF(drive),drive,func);
-		if (!pmac_ide_build_dmatable(drive, ix, !reading))
-			return 1;
-		/* Apple adds 60ns to wrDataSetup on reads */
-		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-				pmac_ide[ix].timings[unit] + 
-				(reading ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-		}
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		if ((HWGROUP(drive)->rq->cmd == IDE_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);
-		}
-	case ide_dma_begin:
-		out_le32(&dma->control, (RUN << 16) | RUN);
-		/* Make sure it gets to the controller right now */
-		(void)in_le32(&dma->control);
-		break;
-	case ide_dma_end: /* returns 1 on error, 0 otherwise */
-		drive->waiting_for_dma = 0;
-		dstat = in_le32(&dma->status);
-		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-		pmac_ide_destroy_dmatable(drive, ix);
-		/* verify good dma status */
-		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-		/* We have to things to deal with here:
-		 * 
-		 * - The dbdma won't stop if the command was started
-		 * but completed with an error without transfering all
-		 * datas. This happens when bad blocks are met during
-		 * a multi-block transfer.
-		 * 
-		 * - The dbdma fifo hasn't yet finished flushing to
-		 * to system memory when the disk interrupt occurs.
-		 * 
-		 * The trick here is to increment drive->waiting_for_dma,
-		 * and return as if no interrupt occured. If the counter
-		 * reach a certain timeout value, we then return 1. If
-		 * we really got the interrupt, it will happen right away
-		 * again.
-		 * Apple's solution here may be more elegant. They issue
-		 * a DMA channel interrupt (a separate irq line) via a DBDMA
-		 * NOP command just before the STOP, and wait for both the
-		 * disk and DBDMA interrupts to have completed.
-		 */
-		 
-		/* If ACTIVE is cleared, the STOP command have passed and
-		 * transfer is complete.
-		 */
-		if (!(in_le32(&dma->status) & ACTIVE))
-			return 1;
-		if (!drive->waiting_for_dma)
-			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
-
-		/* If dbdma didn't execute the STOP command yet, the
-		 * active bit is still set */
-		drive->waiting_for_dma++;
-		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-			printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-			return 1;
-		}
-		udelay(1);
-		return 0;
-
-		/* Let's implement tose just in case someone wants them */
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-	case ide_dma_verbose:
-		return report_drive_dmaing(drive);
-	case ide_dma_retune:
-	case ide_dma_lostirq:
-	case ide_dma_timeout:
-		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-		return 1;
-	default:
-		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-		return 1;
-	}
-	return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-static void __pmac
-idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
-{
-	int j;
-	
-	/* FIXME: We only handle the master IDE disk, we shoud
-	 *        try to fix CD-ROMs here
-	 */
-	switch (drive->media) {
-	case ide_disk:
-		/* Spin down the drive */
-		outb(drive->select.all, base+0x60);
-		(void)inb(base+0x60);
-		udelay(100);
-		outb(0x0, base+0x30);
-		outb(0x0, base+0x20);
-		outb(0x0, base+0x40);
-		outb(0x0, base+0x50);
-		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);   
-		for (j = 0; j < 10; j++) {
-			int status;
-			mdelay(100);
-			status = inb(base+0x70);
-			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
-				break;
-		}
-		break;
-	case ide_cdrom:
-		// todo
-		break;
-	case ide_floppy:
-		// todo
-		break;
-	}
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-static void __pmac
-idepmac_wake_device(ide_drive_t *drive, int used_dma)
-{
-	/* We force the IDE subdriver to check for a media change
-	 * This must be done first or we may lost the condition
-	 *
-	 * Problem: This can schedule. I moved the block device
-	 * wakeup almost late by priority because of that.
-	 */
-	if (DRIVER(drive) && DRIVER(drive)->media_change)
-		DRIVER(drive)->media_change(drive);
-
-	/* We kick the VFS too (see fix in ide.c revalidate) */
-	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
-	
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* We re-enable DMA on the drive if it was active. */
-	/* This doesn't work with the CD-ROM in the media-bay, probably
-	 * because of a pending unit attention. The problem if that if I
-	 * clear the error, the filesystem dies.
-	 */
-	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		pmac_ide_check_dma(drive);
-		HWGROUP(drive)->busy = 0;
-		if (!list_empty(&drive->queue.queue_head))
-			ide_do_request(HWGROUP(drive), 0);
-		spin_unlock_irq(&io_request_lock);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-}
-
-static void __pmac
-idepmac_sleep_interface(int i, unsigned base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	/* We clear the timings */
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
-	
-	/* The media bay will handle itself just fine */
-	if (mediabay)
-		return;
-	
-	/* Disable the bus */
-	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
-}
-
-static void __pmac
-idepmac_wake_interface(int i, unsigned long base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	if (!mediabay) {
-		/* Revive IDE disk and controller */
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
-		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
-		mdelay(10);
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
-	}
-}
-
-static void
-idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
-{
-	int unlock = 0;
-
-	/* Wait for HW group to complete operations */
-	if (ide_spin_wait_hwgroup(drive)) {
-		// What can we do here ? Wake drive we had already
-		// put to sleep and return an error ?
-	} else {
-		unlock = 1;
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		/* Stop the device */
-		idepmac_sleep_device(drive, idx, base);
-	}
-	if (unlock)
-		spin_unlock_irq(&io_request_lock);
-}
-
-static void
-idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
-{
-	unsigned long flags;
-	int j;
-	
-	/* Reset timings */
-	pmac_ide_selectproc(drive);
-	mdelay(10);
-	
-	/* Wait up to 20 seconds for the drive to be ready */
-	for (j = 0; j < 200; j++) {
-		int status;
-		mdelay(100);
-		outb(drive->select.all, base + 0x60);
-		if (inb(base + 0x60) != drive->select.all)
-			continue;
-		status = inb(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
-
-	/* We resume processing on the HW group */
-	spin_lock_irqsave(&io_request_lock, flags);
-	HWGROUP(drive)->busy = 0;
-	if (!list_empty(&drive->queue.queue_head))
-		ide_do_request(HWGROUP(drive), 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);			
-}
-
-/* Note: We support only master drives for now. This will have to be
- * improved if we want to handle sleep on the iMacDV where the CD-ROM
- * is a slave.
- * 
- * Well, actually, that sorta works on the iBook2 when the CD-ROM is
- * a slave, though it will fail to spin_wait_hwgroup for the slave
- * device as it is marked busy by the master sleep code. Well, it's
- * probably not worth fixing now as we don't have sleep code for
- * ATAPI devices anyway. Future kernels will hopefully deal with
- * IDE PM in a more generic way.
- */
-static int __pmac
-idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	int i, ret;
-	unsigned long base;
-	int big_delay;
- 
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-	case PBOOK_SLEEP_NOW:
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int dn;
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				if (!hwif->drives[dn].present)
-					continue;
-				idepmac_sleep_drive(&hwif->drives[dn], i, base);
-			}
-			/* Disable irq during sleep */
-			disable_irq(pmac_ide[i].irq);
-			
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay.
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV))
-				idepmac_sleep_interface(i, base, (ret == 0));
-		}
-		break;
-	case PBOOK_WAKE:
-		big_delay = 0;
-		for (i = 0; i < pmac_ide_count; ++i) {
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			/* Make sure we have sane timings */		
-			sanitize_timings(i);
-
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV)) {
-				idepmac_wake_interface(i, base, (ret == 0));				
-				big_delay = 1;
-			}
-
-		}
-		/* Let hardware get up to speed */
-		if (big_delay)
-			mdelay(IDE_WAKEUP_DELAY_MS);
-	
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int used_dma, dn;
-			int irq_on = 0;
-			
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				ide_drive_t *drive = &hwif->drives[dn];
-				if (!drive->present)
-					continue;
-				/* We don't have re-configured DMA yet */
-				used_dma = drive->using_dma;
-				drive->using_dma = 0;
-				idepmac_wake_drive(drive, base);
-				if (!irq_on) {
-					enable_irq(pmac_ide[i].irq);
-					irq_on = 1;
-				}
-				idepmac_wake_device(drive, used_dma);
-			}
-			if (!irq_on)
-				enable_irq(pmac_ide[i].irq);
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int __pmac
-pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
-{
-	int i, gotone;
-	unsigned long base;
-
-	if (code != SYS_HALT && code != SYS_POWER_OFF)
-		return 0;
-
-	gotone = 0;
-	for (i = 0; i < pmac_ide_count; ++i) {
-		ide_hwif_t *hwif;
-		ide_drive_t *drive;
-		int unlock = 0;
-		int dn;
-
-		if ((base = pmac_ide[i].regbase) == 0)
-				continue;	
-
-		hwif = &ide_hwifs[i];
-		for (dn=0; dn<MAX_DRIVES; dn++) {
-			drive = &hwif->drives[dn];
-			if (drive->present) {
-				gotone = 1;
-				/* Wait for HW group to complete operations */
-				if (ide_spin_wait_hwgroup(drive)) {
-					// What can we do here ? Wake drive we had already
-					// put to sleep and return an error ?
-				} else {
-					unlock = 1;
-					/* Lock HW group */
-					HWGROUP(drive)->busy = 1;
-
-					/* Stop the device */
-					idepmac_sleep_device(drive, i, base);
-				}
-			}
-			if (unlock)
-				spin_unlock_irq(&io_request_lock);
-		}
-	}
-	if (gotone)
-		mdelay(1000);
-		
-	return NOTIFY_DONE;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pnp.c linux-2.4.21-rc3/drivers/ide/ide-pnp.c
--- linux-2.4.20/drivers/ide/ide-pnp.c	2001-05-01 23:06:23.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-pnp.c	2003-05-22 22:06:51.000000000 +0000
@@ -21,12 +21,6 @@
 
 #include <linux/isapnp.h>
 
-#ifndef PREPARE_FUNC
-#define PREPARE_FUNC(dev)  (dev->prepare)
-#define ACTIVATE_FUNC(dev)  (dev->activate)
-#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
-#endif
-
 #define DEV_IO(dev, index) (dev->resource[index].start)
 #define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
 
@@ -54,6 +48,7 @@
 };
 
 /* Generic initialisation function for ISA PnP IDE interface */
+
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
@@ -66,13 +61,16 @@
 		return 1;
 
 	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
-			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
-			0, NULL, DEV_IRQ(dev, 0));
+			generic_ide_offsets,
+			(ide_ioreg_t) DEV_IO(dev, 1),
+			0, NULL,
+//			generic_pnp_ide_iops,
+			DEV_IRQ(dev, 0));
 
 	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1) {
-	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+	    	printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
@@ -88,7 +86,6 @@
 	{	0 }
 };
 
-#ifdef MODULE
 #define NR_PNP_DEVICES 8
 struct pnp_dev_inst {
 	struct pci_dev *dev;
@@ -96,11 +93,11 @@
 };
 static struct pnp_dev_inst devices[NR_PNP_DEVICES];
 static int pnp_ide_dev_idx = 0;
-#endif
 
 /*
  * Probe for ISA PnP IDE interfaces.
  */
+
 void __init pnpide_init(int enable)
 {
 	struct pci_dev *dev = NULL;
@@ -109,19 +106,18 @@
 	if (!isapnp_present())
 		return;
 
-#ifdef MODULE
 	/* Module unload, deactivate all registered devices. */
 	if (!enable) {
 		int i;
 		for (i = 0; i < pnp_ide_dev_idx; i++) {
+			dev = devices[i].dev;
 			devices[i].dev_type->init_fn(dev, 0);
-
-			if (DEACTIVATE_FUNC(devices[i].dev))
-				DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+			if (dev->deactivate)
+				dev->deactivate(dev);
 		}
 		return;
 	}
-#endif
+
 	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
@@ -129,20 +125,20 @@
 			if (dev->active)
 				continue;
 
-       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s prepare failed\n", DEV_NAME(dev));
+       			if (dev->prepare && dev->prepare(dev) < 0) {
+				printk(KERN_ERR"ide-pnp: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
 
-			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s activate failed\n", DEV_NAME(dev));
+			if (dev->activate && dev->activate(dev) < 0) {
+				printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
 				continue;
 			}
 
 			/* Call device initialization function */
 			if (dev_type->init_fn(dev, 1)) {
-				if (DEACTIVATE_FUNC(dev))
-					DEACTIVATE_FUNC(dev)(dev);
+				if (dev->deactivate(dev))
+					dev->deactivate(dev);
 			} else {
 #ifdef MODULE
 				/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-probe.c linux-2.4.21-rc3/drivers/ide/ide-probe.c
--- linux-2.4.20/drivers/ide/ide-probe.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-probe.c	2003-05-22 22:06:24.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide-probe.c	Version 1.07	March 18, 2001
+ *  linux/drivers/ide/ide-probe.c	Version 1.11	Mar 05, 2003
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -27,6 +27,8 @@
  * Version 1.06		stream line request queue and prep for cascade project.
  * Version 1.07		max_sect <= 255; slower disks would get behind and
  * 			then fall over when they get to 256.	Paul G.
+ * Version 1.10		Update set for new IDE. drive->id is now always
+ *			valid after probe time even with noprobe
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -46,40 +48,106 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static inline void do_identify (ide_drive_t *drive, byte cmd)
+/**
+ *	generic_id		-	add a generic drive id
+ *	@drive:	drive to make an ID block for
+ *	
+ *	Add a fake id field to the drive we are passed. This allows
+ *	use to skip a ton of NULL checks (which people always miss) 
+ *	and make drive properties unconditional outside of this file
+ */
+ 
+static void generic_id(ide_drive_t *drive)
 {
-	int bswap = 1;
-	struct hd_driveid *id;
+	drive->id->cyls = drive->cyl;
+	drive->id->heads = drive->head;
+	drive->id->sectors = drive->sect;
+	drive->id->cur_cyls = drive->cyl;
+	drive->id->cur_heads = drive->head;
+	drive->id->cur_sectors = drive->sect;
+}
+		
+/**
+ *	drive_is_flashcard	-	check for compact flash
+ *	@drive: drive to check
+ *
+ *	CompactFlash cards and their brethern pretend to be removable
+ *	hard disks, except:
+ * 		(1) they never have a slave unit, and
+ *		(2) they don't have doorlock mechanisms.
+ *	This test catches them, and is invoked elsewhere when setting
+ *	appropriate config bits.
+ *
+ *	FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
+ *	devices, so in linux 2.3.x we should change this to just treat all
+ *	PCMCIA  drives this way, and get rid of the model-name tests below
+ *	(too big of an interface change for 2.4.x).
+ *	At that time, we might also consider parameterizing the timeouts and
+ *	retries, since these are MUCH faster than mechanical drives. -M.Lord
+ */
+ 
+static inline int drive_is_flashcard (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
-	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
-		goto err_kmalloc;
+	if (drive->removable && id != NULL) {
+		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
+		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
+		{
+			return 1;	/* yes, it is a flash memory card */
+		}
 	}
+	return 0;	/* no, it is not a flash memory card */
+}
 
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
-	ide__sti();	/* local CPU only */
-	ide_fix_driveid(id);
+/**
+ *	do_identify	-	identify a drive
+ *	@drive: drive to identify 
+ *	@cmd: command used
+ *
+ *	Called when we have issued a drive identify command to
+ *	read and parse the results. This function is run with
+ *	interrupts disabled. 
+ */
+ 
+static inline void do_identify (ide_drive_t *drive, u8 cmd)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int bswap = 1;
+	struct hd_driveid *id;
 
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
-	}
+	/* called with interrupts disabled! */
+	id = drive->id;
+	/* read 512 bytes of id info */
+	hwif->ata_input_data(drive, id, SECTOR_WORDS);
+	drive->id_read = 1;
+	local_irq_enable();
+	
+	ide_fix_driveid(id);
 
 	if (!drive->forced_lun)
 		drive->last_lun = id->last_lun & 0x7;
+
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:
 	 * Ignore them if there is a driver for them available.
 	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+	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);
 		goto err_misc;
 	}
@@ -93,27 +161,30 @@
 		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
 		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
 		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
+			/* Vertos drives may still be weird */
+			bswap ^= 1;	
 	}
-	ide_fixstring (id->model,     sizeof(id->model),     bswap);
-	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+	ide_fixstring(id->model,     sizeof(id->model),     bswap);
+	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	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"))
 		goto err_misc;
 
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	/* we depend on this a lot! */
+	id->model[sizeof(id->model)-1] = '\0';
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
+	drive->dead = 0;
 
 	/*
 	 * Check for an ATAPI device
 	 */
 	if (cmd == WIN_PIDENTIFY) {
-		byte type = (id->config >> 8) & 0x1f;
+		u8 type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
-		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
@@ -121,19 +192,24 @@
 		switch (type) {
 			case ide_floppy:
 				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+					if (!strstr(id->model, "oppy") &&
+					    !strstr(id->model, "poyp") &&
+					    !strstr(id->model, "ZIP"))
 						printk("cdrom or floppy?, assuming ");
 					if (drive->media != ide_cdrom) {
 						printk ("FLOPPY");
+						drive->removable = 1;
 						break;
 					}
 				}
-				type = ide_cdrom;	/* Early cdrom models used zero */
+				/* Early cdrom models used zero */
+				type = ide_cdrom;
 			case ide_cdrom:
 				drive->removable = 1;
 #ifdef CONFIG_PPC
 				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+				if (!strstr(id->model, "CD-ROM") &&
+				    strstr(id->model, "ZIP")) {
 					printk ("FLOPPY");
 					type = ide_floppy;
 					break;
@@ -162,128 +238,173 @@
 	 */
 	if (id->config & (1<<7))
 		drive->removable = 1;
+		
 	/*
 	 * Prevent long system lockup probing later for non-existant
-	 * slave drive if the hwif is actually a flash memory card of some variety:
+	 * slave drive if the hwif is actually a flash memory card of
+	 * some variety:
 	 */
+	drive->is_flash = 0;
 	if (drive_is_flashcard(drive)) {
-		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+#if 0
+		/* The new IDE adapter widgets don't follow this heuristic
+		   so we must nowdays just bite the bullet and take the
+		   probe hit */	
+		ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];		
 		if (!mate->ata_flash) {
 			mate->present = 0;
 			mate->noprobe = 1;
 		}
+#endif		
+		drive->is_flash = 1;
 	}
 	drive->media = ide_disk;
-	printk("ATA DISK drive\n");
-	QUIRK_LIST(HWIF(drive),drive);
+	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+	QUIRK_LIST(drive);
 	return;
 
 err_misc:
 	kfree(id);
-err_kmalloc:
 	drive->present = 0;
 	return;
 }
 
-/*
- * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
- * and waits for a response.  It also monitors irqs while this is
- * happening, in hope of automatically determining which one is
- * being used by the interface.
+/**
+ *	actual_try_to_identify	-	send ata/atapi identify
+ *	@drive: drive to identify
+ *	@cmd: comamnd to use
  *
- * Returns:	0  device was identified
- *		1  device timed-out (no response to identify request)
- *		2  device aborted the command (refused to identify itself)
+ *	try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
+ *	and waits for a response.  It also monitors irqs while this is
+ *	happening, in hope of automatically determining which one is
+ *	being used by the interface.
+ *
+ *	Returns:	0  device was identified
+ *			1  device timed-out (no response to identify request)
+ *			2  device aborted the command (refused to identify itself)
  */
-static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+
+static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int rc;
 	ide_ioreg_t hd_status;
 	unsigned long timeout;
-	byte s, a;
+	u8 s = 0, a = 0;
 
 	if (IDE_CONTROL_REG) {
 		/* take a deep breath */
 		ide_delay_50ms();
-		a = IN_BYTE(IDE_ALTSTATUS_REG);
-		s = IN_BYTE(IDE_STATUS_REG);
+		a = hwif->INB(IDE_ALTSTATUS_REG);
+		s = hwif->INB(IDE_STATUS_REG);
 		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+			printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of "
+				"ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			/* ancient Seagate drives, broken interfaces */
+			hd_status = IDE_STATUS_REG;
 		} else {
-			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+			/* use non-intrusive polling */
+			hd_status = IDE_ALTSTATUS_REG;
 		}
 	} else {
 		ide_delay_50ms();
 		hd_status = IDE_STATUS_REG;
 	}
 
-	/* set features register for atapi identify command to be sure of reply */
+	/* set features register for atapi
+	 * identify command to be sure of reply
+	 */
 	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+		/* disable dma & overlap */
+		hwif->OUTB(0, IDE_FEATURE_REG);
 
-#if CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(ide_drive_t *);
-		if (pdc4030_identify(drive)) {
+	if (hwif->identify != NULL) {
+		if (hwif->identify(drive))
 			return 1;
-		}
-	} else
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	} else {
+		/* ask drive for ID */
+		hwif->OUTB(cmd, IDE_COMMAND_REG);
+	}
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			return 1;	/* drive timed-out */
+		if (time_after(jiffies, timeout)) {
+			/* drive timed-out */
+			return 1;
 		}
-		ide_delay_50ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
+		/* give drive a breather */
+		ide_delay_50ms();
+	} while ((hwif->INB(hd_status)) & BUSY_STAT);
 
-	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+	/* wait for IRQ and DRQ_STAT */
+	ide_delay_50ms();
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
 		unsigned long flags;
-		__save_flags(flags);	/* local CPU only */
-		__cli();		/* local CPU only; some systems need this */
-		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* drive responded with ID */
-		(void) GET_STAT();	/* clear drive IRQ */
-		__restore_flags(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
+
+		/* local CPU only; some systems need this */
+		local_irq_save(flags);
+		/* drive returned ID */
+		do_identify(drive, cmd);
+		/* drive responded with ID */
+		rc = 0;
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
+	} else {
+		/* drive refused ID */
+		rc = 2;
+	}
 	return rc;
 }
 
-static int try_to_identify (ide_drive_t *drive, byte cmd)
+/**
+ *	try_to_identify	-	try to identify a drive
+ *	@drive: drive to probe
+ *	@cmd: comamnd to use
+ *
+ *	Issue the identify command and then do IRQ probing to
+ *	complete the identification when needed by finding the
+ *	IRQ the drive is attached to
+ */
+ 
+static int try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int retval;
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 
-	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+	if (IDE_CONTROL_REG && !hwif->irq) {
 		autoprobe = 1;
 		cookie = probe_irq_on();
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		/* enable device irq */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
-		(void) GET_STAT();			/* clear drive IRQ */
+		/* mask device irq */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
 		irq = probe_irq_off(cookie);
-		if (!HWIF(drive)->irq) {
+		if (!hwif->irq) {
 			if (irq > 0) {
-				HWIF(drive)->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+				hwif->irq = irq;
+			} else {
+				/* Mmmm.. multiple IRQs..
+				 * don't know which was ours
+				 */
+				printk("%s: IRQ probe failed (0x%lx)\n",
+					drive->name, cookie);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
-				if (HWIF(drive)->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+				if (hwif->chipset == ide_cmd640) {
+					printk("%s: Hmmm.. probably a driver "
+						"problem.\n", drive->name);
 					CMD640_DUMP_REGS;
 				}
 #endif /* CMD640_DUMP_REGS */
@@ -295,15 +416,19 @@
 }
 
 
-/*
- * do_probe() has the difficult job of finding a drive if it exists,
- * without getting hung up if it doesn't exist, without trampling on
- * ethernet cards, and without leaving any IRQs dangling to haunt us later.
- *
- * If a drive is "known" to exist (from CMOS or kernel parameters),
- * but does not respond right away, the probe will "hang in there"
- * for the maximum wait time (about 30 seconds), otherwise it will
- * exit much more quickly.
+/**
+ *	do_probe		-	probe an IDE device
+ *	@drive: drive to probe
+ *	@cmd: command to use
+ *
+ *	do_probe() has the difficult job of finding a drive if it exists,
+ *	without getting hung up if it doesn't exist, without trampling on
+ *	ethernet cards, and without leaving any IRQs dangling to haunt us later.
+ *
+ *	If a drive is "known" to exist (from CMOS or kernel parameters),
+ *	but does not respond right away, the probe will "hang in there"
+ *	for the maximum wait time (about 30 seconds), otherwise it will
+ *	exit much more quickly.
  *
  * Returns:	0  device was identified
  *		1  device timed-out (no response to identify request)
@@ -311,11 +436,14 @@
  *		3  bad status from device (possible for ATAPI drives)
  *		4  probe was not attempted because failure was obvious
  */
-static int do_probe (ide_drive_t *drive, byte cmd)
+
+static int do_probe (ide_drive_t *drive, u8 cmd)
 {
 	int rc;
 	ide_hwif_t *hwif = HWIF(drive);
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
+
+	if (drive->present) {
+		/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
 			return 4;
 	}
@@ -324,44 +452,66 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	SELECT_DRIVE(hwif,drive);
+
+	/* needed for some systems
+	 * (e.g. crw9624 as drive0 with disk as slave)
+	 */
 	ide_delay_50ms();
-	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+	SELECT_DRIVE(drive);
+	ide_delay_50ms();
+	if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		if (drive->select.b.unit != 0) {
-			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
+			/* exit with drive0 selected */
+			SELECT_DRIVE(&hwif->drives[0]);
+			/* allow BUSY_STAT to assert & clear */
+			ide_delay_50ms();
 		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+		/* no i/f present: mmm.. this should be a 4 -ml */
+		return 3;
 	}
 
-	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
-	 || drive->present || cmd == WIN_PIDENTIFY)
-	{
-		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
-			rc = try_to_identify(drive,cmd); /* failed: try again */
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+	    drive->present || cmd == WIN_PIDENTIFY) {
+		/* send cmd and wait */
+		if ((rc = try_to_identify(drive, cmd))) {
+			/* failed: try again */
+			rc = try_to_identify(drive,cmd);
+		}
+		if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+			return 4;
+
+		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+			((drive->autotune == IDE_TUNE_DEFAULT) ||
+			(drive->autotune == IDE_TUNE_AUTO))) {
 			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			printk("%s: no response (status = 0x%02x), "
+				"resetting drive\n", drive->name,
+				hwif->INB(IDE_STATUS_REG));
 			ide_delay_50ms();
-			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			ide_delay_50ms();
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+			       time_before(jiffies, timeout + WAIT_WORSTCASE))
 				ide_delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
-		(void) GET_STAT();		/* ensure drive irq is clear */
+			printk("%s: no response (status = 0x%02x)\n",
+				drive->name, hwif->INB(IDE_STATUS_REG));
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	} else {
-		rc = 3;				/* not present or maybe ATAPI */
+		/* not present or maybe ATAPI */
+		rc = 3;
 	}
 	if (drive->select.b.unit != 0) {
-		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		/* exit with drive0 selected */
+		SELECT_DRIVE(&hwif->drives[0]);
 		ide_delay_50ms();
-		(void) GET_STAT();		/* ensure drive irq is clear */
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	}
 	return rc;
 }
@@ -371,12 +521,13 @@
  */
 static void enable_nest (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long timeout;
 
-	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
-	SELECT_DRIVE(HWIF(drive), drive);
+	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
 		if (time_after(jiffies, timeout)) {
@@ -384,193 +535,405 @@
 			return;
 		}
 		ide_delay_50ms();
-	} while (GET_STAT() & BUSY_STAT);
+	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
 	ide_delay_50ms();
-	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
-		printk("failed (status = 0x%02x)\n", GET_STAT());
-	else
+
+	if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
+		printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
+	} else {
 		printk("success\n");
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) {	/* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+	}
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 }
 
-/*
- * probe_for_drive() tests for existence of a given drive using do_probe().
+/**
+ *	probe_for_drives	-	upper level drive probe
+ *	@drive: drive to probe for
  *
- * Returns:	0  no device was found
- *		1  device was found (note: drive->present might still be 0)
+ *	probe_for_drive() tests for existence of a given drive using do_probe()
+ *	and presents things to the user as needed.
+ *
+ *	Returns:	0  no device was found
+ *			1  device was found (note: drive->present might
+ *			   still be 0)
  */
-static inline byte probe_for_drive (ide_drive_t *drive)
+ 
+static inline u8 probe_for_drive (ide_drive_t *drive)
 {
-	if (drive->noprobe)			/* skip probing? */
-		return drive->present;
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
-	}
-	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
-		enable_nest(drive);
-	if (!drive->present)
-		return 0;			/* drive not found */
-	if (drive->id == NULL) {		/* identification failed? */
-		if (drive->media == ide_disk) {
-			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
-			 drive->name, drive->cyl, drive->head, drive->sect);
-		} else if (drive->media == ide_cdrom) {
-			printk("%s: ATAPI cdrom (?)\n", drive->name);
-		} else {
-			drive->present = 0;	/* nuke it */
+	/*
+	 *	In order to keep things simple we have an id
+	 *	block for all drives at all times. If the device
+	 *	is pre ATA or refuses ATA/ATAPI identify we
+	 *	will add faked data to this.
+	 *
+	 *	Also note that 0 everywhere means "can't do X"
+	 */
+	 
+	drive->id = kmalloc(SECTOR_WORDS *4, GFP_KERNEL);
+	drive->id_read = 0;
+	if(drive->id == NULL)
+	{
+		printk(KERN_ERR "ide: out of memory for id data.\n");
+		return 0;
+	}
+	memset(drive->id, 0, SECTOR_WORDS * 4);
+	strcpy(drive->id->model, "UNKNOWN");
+	
+	/* skip probing? */
+	if (!drive->noprobe)
+	{
+		/* if !(success||timed-out) */
+		if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+			/* look for ATAPI device */
+			(void) do_probe(drive, WIN_PIDENTIFY);
+		}
+		if (strstr(drive->id->model, "E X A B Y T E N E S T"))
+			enable_nest(drive);
+		if (!drive->present)
+			/* drive not found */
+			return 0;
+	
+		/* identification failed? */
+		if (!drive->id_read) {
+			if (drive->media == ide_disk) {
+				printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
+					drive->name, drive->cyl,
+					drive->head, drive->sect);
+			} else if (drive->media == ide_cdrom) {
+				printk(KERN_INFO "%s: ATAPI cdrom (?)\n", drive->name);
+			} else {
+				/* nuke it */
+				printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
+				drive->present = 0;
+			}
 		}
+		/* drive was found */
 	}
-	return 1;	/* drive was found */
+	if(!drive->present)
+		return 0;
+	/* The drive wasn't being helpful. Add generic info only */
+	if(!drive->id_read)
+		generic_id(drive);
+	return drive->present;
 }
 
-/*
- * Calculate the region that this interface occupies,
- * handling interfaces where the registers may not be
- * ordered sanely.  We deal with the CONTROL register
- * separately.
+#define hwif_check_region(addr, num) \
+	((hwif->mmio) ? check_mem_region((addr),(num)) : check_region((addr),(num)))
+
+/**
+ *	hwif_check_regions	-	check resources for IDE
+ *	@hwif: interface to use
+ *
+ *	Checks if all the needed resources for an interface are free
+ *	providing the interface is PIO. Right now core IDE code does
+ *	this work which is deeply wrong. MMIO leaves it to the controller
+ *	driver, PIO will migrate this way over time
  */
+ 
 static int hwif_check_regions (ide_hwif_t *hwif)
 {
-	int region_errors = 0;
-
-	hwif->straight8 = 0;
-	region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+	u32 i		= 0;
+	int addr_errs	= 0;
 
+	if (hwif->mmio == 2)
+		return 0;
+	addr_errs  = hwif_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		addr_errs += hwif_check_region(hwif->io_ports[i], 1);
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-	/*
-	 * If any errors are return, we drop the hwif interface.
-	 */
-	return(region_errors);
+	/* If any errors are return, we drop the hwif interface. */
+	hwif->straight8 = 0;
+	return(addr_errs);
 }
 
+//EXPORT_SYMBOL(hwif_check_regions);
+
+#define hwif_request_region(addr, num, name)	\
+	((hwif->mmio) ? request_mem_region((addr),(num),(name)) : request_region((addr),(num),(name)))
+
 static void hwif_register (ide_hwif_t *hwif)
 {
+	u32 i = 0;
+
+	if (hwif->mmio == 2)
+		return;
+	if (hwif->io_ports[IDE_CONTROL_OFFSET])
+		hwif_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+	if (hwif->io_ports[IDE_IRQ_OFFSET])
+		hwif_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
 	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
 	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
 		hwif->straight8 = 1;
-		goto jump_straight8;
+		return;
 	}
 
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hwif_request_region(hwif->io_ports[i], 1, hwif->name);
+}
 
-jump_straight8:
-	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+//EXPORT_SYMBOL(hwif_register);
+
+/* Enable code below on all archs later, for now, I want it on PPC
+ */
+#ifdef CONFIG_PPC
+/*
+ * This function waits for the hwif to report a non-busy status
+ * see comments in probe_hwif()
+ */
+static int wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
+{
+	u8 stat = 0;
+	
+	while(timeout--) {
+		/* Turn this into a schedule() sleep once I'm sure
+		 * about locking issues (2.5 work ?)
+		 */
+		mdelay(1);
+		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		if ((stat & BUSY_STAT) == 0)
+			break;
+		/* Assume a value of 0xff means nothing is connected to
+		 * the interface and it doesn't implement the pull-down
+		 * resistor on D7
+		 */
+		if (stat == 0xff)
+			break;
+	}
+	return ((stat & BUSY_STAT) == 0) ? 0 : -EBUSY;
+}
+
+static int wait_hwif_ready(ide_hwif_t *hwif)
+{
+	int rc;
+
+	printk(KERN_INFO "Probing IDE interface %s...\n", hwif->name);
+
+	/* Let HW settle down a bit from whatever init state we
+	 * come from */
+	mdelay(2);
+
+	/* Wait for BSY bit to go away, spec timeout is 30 seconds,
+	 * I know of at least one disk who takes 31 seconds, I use 35
+	 * here to be safe
+	 */
+	rc = wait_not_busy(hwif, 35000);
+	if (rc)
+		return rc;
+
+	/* Now make sure both master & slave are ready */
+	SELECT_DRIVE(&hwif->drives[0]);
+	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+	mdelay(2);
+	rc = wait_not_busy(hwif, 10000);
+	if (rc)
+		return rc;
+	SELECT_DRIVE(&hwif->drives[1]);
+	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+	mdelay(2);
+	rc = wait_not_busy(hwif, 10000);
+
+	/* Exit function with master reselected (let's be sane) */
+	SELECT_DRIVE(&hwif->drives[0]);
+	
+	return rc;
 }
+#endif /* CONFIG_PPC */
 
 /*
  * This routine only knows how to look for drive units 0 and 1
  * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  */
-static void probe_hwif (ide_hwif_t *hwif)
+void probe_hwif (ide_hwif_t *hwif)
 {
 	unsigned int unit;
 	unsigned long flags;
+	unsigned int irqd;
 
 	if (hwif->noprobe)
 		return;
 #ifdef CONFIG_BLK_DEV_IDE
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
 		extern void probe_cmos_for_drives(ide_hwif_t *);
-
-		probe_cmos_for_drives (hwif);
+		probe_cmos_for_drives(hwif);
 	}
 #endif
-
-	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
+	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	    (hwif_check_regions(hwif))) {
-		int msgout = 0;
+		u16 msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
 			if (drive->present) {
 				drive->present = 0;
-				printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
+				printk(KERN_ERR "%s: ERROR, PORTS ALREADY IN USE\n",
+					drive->name);
 				msgout = 1;
 			}
 		}
 		if (!msgout)
-			printk("%s: ports already in use, skipping probe\n", hwif->name);
+			printk(KERN_ERR "%s: ports already in use, skipping probe\n",
+				hwif->name);
 		return;	
 	}
 
-	__save_flags(flags);	/* local CPU only */
-	__sti();		/* local CPU only; needed for jiffies and irq probing */
+	/*
+	 * We must always disable IRQ, as probe_for_drive will assert IRQ, but
+	 * we'll install our IRQ driver much later...
+	 */
+	irqd = hwif->irq;
+	if (irqd)
+		disable_irq(hwif->irq);
+
+	local_irq_set(flags);
+
+#ifdef CONFIG_PPC
+	/* This is needed on some PPCs and a bunch of BIOS-less embedded
+	 * platforms. Typical cases are:
+	 * 
+	 *  - The firmware hard reset the disk before booting the kernel,
+	 *    the drive is still doing it's poweron-reset sequence, that
+	 *    can take up to 30 seconds
+	 *  - The firmware does nothing (or no firmware), the device is
+	 *    still in POST state (same as above actually).
+	 *  - Some CD/DVD/Writer combo drives tend to drive the bus during
+	 *    their reset sequence even when they are non-selected slave
+	 *    devices, thus preventing discovery of the main HD
+	 *    
+	 *  Doing this wait-for-busy should not harm any existing configuration
+	 *  (at least things won't be worse than what current code does, that
+	 *  is blindly go & talk to the drive) and fix some issues like the
+	 *  above.
+	 *  
+	 *  BenH.
+	 */
+	if (wait_hwif_ready(hwif))
+		printk(KERN_WARNING "%s: Wait for ready failed before probe !\n", hwif->name);
+#endif /* CONFIG_PPC */
+
 	/*
 	 * Second drive should only exist if first drive was found,
 	 * but a lot of cdrom drives are configured as single slaves.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
-		(void) probe_for_drive (drive);
+		drive->dn = ((hwif->channel ? 2 : 0) + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		(void) probe_for_drive(drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
-			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+			if (hwif->chipset != ide_4drives ||
+			    !hwif->mate || 
+			    !hwif->mate->present) {
 				hwif_register(hwif);
 			}
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		byte stat;
+		u8 stat;
 
-		printk("%s: reset\n", hwif->name);
-		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		printk(KERN_WARNING "%s: reset\n", hwif->name);
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
-		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		do {
 			ide_delay_50ms();
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
 
 	}
-	__restore_flags(flags);	/* local CPU only */
+	local_irq_restore(flags);
+	/*
+	 * Use cached IRQ number. It might be (and is...) changed by probe
+	 * code above
+	 */
+	if (irqd)
+		enable_irq(irqd);
+
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
+		int enable_dma = 1;
+
 		if (drive->present) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-			if (tuneproc != NULL && drive->autotune == 1)
-				tuneproc(drive, 255);	/* auto-tune PIO mode */
+			if (hwif->tuneproc != NULL && 
+				drive->autotune == IDE_TUNE_AUTO)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+
+#ifdef CONFIG_IDEDMA_ONLYDISK
+			if (drive->media != ide_disk)
+				enable_dma = 0;
+#endif
+			/*
+			 * MAJOR HACK BARF :-/
+			 *
+			 * FIXME: chipsets own this cruft!
+			 */
+			/*
+			 * Move here to prevent module loading clashing.
+			 */
+	//		drive->autodma = hwif->autodma;
+			if ((hwif->ide_dma_check) &&
+				((drive->autotune == IDE_TUNE_DEFAULT) ||
+				(drive->autotune == IDE_TUNE_AUTO))) {
+				/*
+				 * Force DMAing for the beginning of the check.
+				 * Some chipsets appear to do interesting
+				 * things, if not checked and cleared.
+				 *   PARANOIA!!!
+				 */
+				hwif->ide_dma_off_quietly(drive);
+				if (enable_dma)
+					hwif->ide_dma_check(drive);
+			}
+		}
+	}
+}
+
+EXPORT_SYMBOL(probe_hwif);
+
+#if 0
+int hwif_init (ide_hwif_t *hwif);
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#if 1
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				ata_attach(drive);
+			}
 		}
 	}
+#endif
+	hwif->initializing = 0;
+	return 0;
 }
 
+EXPORT_SYMBOL(probe_hwif_init);
+#endif
+
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -583,18 +946,20 @@
  *
  * This routine detects and reports such situations, but does not fix them.
  */
-static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
 {
 	ide_hwif_t *m = *match;
 
 	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
 		if (!new->hwgroup)
 			return;
-		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+		printk("%s: potential irq problem with %s and %s\n",
+			hwif->name, new->name, m->name);
 	}
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
+EXPORT_SYMBOL(save_match);
 #endif /* MAX_HWIFS > 1 */
 
 /*
@@ -606,14 +971,9 @@
 
 	q->queuedata = HWGROUP(drive);
 	blk_init_queue(q, do_ide_request);
-
-	if (drive->media == ide_disk) {
-#ifdef CONFIG_BLK_DEV_ELEVATOR_NOOP
-		elevator_init(&q->elevator, ELEVATOR_NOOP);
-#endif
-	}
 }
 
+#undef __IRQ_HELL_SPIN
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -627,20 +987,26 @@
  * but anything else has led to problems on some machines.  We re-enable
  * interrupts as much as we can safely do in most places.
  */
-static int init_irq (ide_hwif_t *hwif)
+int init_irq (ide_hwif_t *hwif)
 {
 	unsigned long flags;
 	unsigned int index;
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
-	
+#if 0
+	/* Allocate the buffer and no sleep allowed */
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_ATOMIC);
+#else
 	/* Allocate the buffer and potentially sleep first */
-	
 	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+#endif
 	
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+	save_and_cli(flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
 	hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
@@ -652,7 +1018,8 @@
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
-				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+				if (hwif->chipset != ide_pci ||
+				    h->chipset != ide_pci) {
 					save_match(hwif, h, &match);
 				}
 			}
@@ -677,7 +1044,11 @@
 	} else {
 		hwgroup = new_hwgroup;
 		if (!hwgroup) {
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
@@ -695,19 +1066,30 @@
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else /* !CONFIG_IDEPCI_SHARE_IRQ */
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+		int sa = SA_INTERRUPT;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+		sa = SA_SHIRQ;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+			sa = SA_SHIRQ;
+#ifndef CONFIG_IDEPCI_SHARE_IRQ
+			sa |= 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 */
+			/* clear nIEN */
+			hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
 
-		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
+		if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 	}
@@ -735,10 +1117,16 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
-	restore_flags(flags);	/* all CPUs; safe now that hwif->hwgroup is set up */
+
+	/* all CPUs; safe now that hwif->hwgroup is set up */
+#ifndef __IRQ_HELL_SPIN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET],
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
@@ -748,7 +1136,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
-	printk("%s at %p on irq 0x%08x", hwif->name,
+	printk("%s at 0x%08lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
 #endif /* __mc68000__ && CONFIG_APUS */
 	if (match)
@@ -758,6 +1146,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(init_irq);
+
 /*
  * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  * after probing for drives, to allocate partition tables and other data
@@ -771,34 +1161,27 @@
 	int *bs, *max_sect, *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);
+	gd        = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
-	memset (gd, 0, sizeof(struct gendisk));
-	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	memset(gd, 0, sizeof(struct gendisk));
+	
+	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);
+	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);
+	bs        = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!bs)
 		goto err_kmalloc_bs;
-	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_sect  = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_sect)
 		goto err_kmalloc_max_sect;
-	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_ra    = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_ra)
 		goto err_kmalloc_max_ra;
 
@@ -813,55 +1196,49 @@
 		/*
 		 * IDE can do up to 128K per request == 256
 		 */
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+		*max_sect++ = ((hwif->rqsize) ? hwif->rqsize : 128);
 		*max_ra++ = vm_max_readahead;
 	}
 
 	for (unit = 0; unit < units; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
 
-	gd->major	= hwif->major;		/* our major device number */
-	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
-	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
-	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
-	gd->next	= NULL;			/* linked list of major devs */
-	gd->fops        = ide_fops;             /* file operations */
-	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
-	gd->flags	= kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+	/* our major device number */
+	gd->major	= hwif->major;
+	/* treated special in genhd.c */
+	gd->major_name	= IDE_MAJOR_NAME;
+	/* num bits for partitions */
+	gd->minor_shift	= PARTN_BITS;
+	/* 1 + max partitions / drive */
+	gd->max_p	= 1<<PARTN_BITS;
+	/* current num real drives */
+	gd->nr_real	= units;
+	/* ptr to internal data */
+	gd->real_devices= hwif;
+	/* linked list of major devs */
+	gd->next	= NULL;
+	/* file operations */
+	gd->fops        = ide_fops;
+	gd->de_arr	= kmalloc(sizeof *gd->de_arr * units, GFP_KERNEL);
+	gd->flags	= kmalloc(sizeof *gd->flags * units, GFP_KERNEL);
 	if (gd->de_arr)
-		memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+		memset(gd->de_arr, 0, sizeof *gd->de_arr * units);
 	if (gd->flags)
-		memset (gd->flags, 0, sizeof *gd->flags * units);
+		memset(gd->flags, 0, sizeof *gd->flags * units);
 
 	hwif->gd = gd;
 	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);
+//		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];
-
-			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);
-			hwif->drives[unit].de =
-				devfs_mk_dir (ide_devfs_handle, name, NULL);
-		}
-#endif
 	}
 	return;
 
@@ -880,7 +1257,9 @@
 	return;
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+EXPORT_SYMBOL(init_gendisk);
+
+int hwif_init (ide_hwif_t *hwif)
 {
 	if (!hwif->present)
 		return 0;
@@ -893,15 +1272,18 @@
 	}
 #ifdef CONFIG_BLK_DEV_HD
 	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
+		printk("%s: CANNOT SHARE IRQ WITH OLD "
+			"HARDDISK DRIVER (hd.c)\n", hwif->name);
 		return (hwif->present = 0);
 	}
 #endif /* CONFIG_BLK_DEV_HD */
-	
-	hwif->present = 0; /* we set it back to 1 if all is ok below */
+
+	/* we set it back to 1 if all is ok below */	
+	hwif->present = 0;
 
 	if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
+			hwif->name, hwif->major);
 		return (hwif->present = 0);
 	}
 	
@@ -912,14 +1294,15 @@
 		 *	this port and try that.
 		 */
 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			printk("%s: Disabled unable to get IRQ %d.\n",
+				hwif->name, i);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		if (init_irq(hwif)) {
 			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 				hwif->name, i, hwif->irq);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		printk("%s: probed IRQ %d failed, using default.\n",
@@ -942,19 +1325,51 @@
 	return hwif->present;
 }
 
+EXPORT_SYMBOL(hwif_init);
+
 void export_ide_init_queue (ide_drive_t *drive)
 {
 	ide_init_queue(drive);
 }
 
-byte export_probe_for_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(export_ide_init_queue);
+
+u8 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);
 
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef DIRECT_HWIF_PROBE_ATTACH_METHOD
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present)
+				ide_attach_drive(drive);
+		}
+	}
+#    endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#  endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -975,12 +1390,20 @@
 	/*
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
 	 */
+#ifdef HWIF_PROBE_CLASSIC_METHOD
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			probe_hwif(&ide_hwifs[index]);
+
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			probe_hwif_init(&ide_hwifs[index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 	if (!ide_probe)
 		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-proc.c linux-2.4.21-rc3/drivers/ide/ide-proc.c
--- linux-2.4.20/drivers/ide/ide-proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-proc.c	2003-05-22 22:06:25.000000000 +0000
@@ -1,7 +1,8 @@
 /*
- *  linux/drivers/ide/ide-proc.c	Version 1.03	January  2, 1998
+ *  linux/drivers/ide/ide-proc.c	Version 1.05	Mar 05, 2003
  *
  *  Copyright (C) 1997-1998	Mark Lord
+ *  Copyright (C) 2003		Red Hat <alan@redhat.com>
  */
 
 /*
@@ -57,6 +58,9 @@
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -70,63 +74,15 @@
 
 #include <asm/io.h>
 
+#ifdef CONFIG_ALL_PPC
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern byte aec62xx_proc;
-int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern byte ali_proc;
-int (*ali_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern byte amd74xx_proc;
-int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern byte cmd64x_proc;
-int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-extern byte cs5530_proc;
-int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern byte hpt34x_proc;
-int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt366_proc;
-int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern byte pdc202xx_proc;
-int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-extern byte piix_proc;
-int (*piix_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern byte svwks_proc;
-int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern byte sis_proc;
-int (*sis_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern byte slc90e66_proc;
-int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern byte via_proc;
-int (*via_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -160,6 +116,17 @@
 
 static struct proc_dir_entry * proc_ide_root = NULL;
 
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#include <linux/delay.h>
+/*
+ * This is the list of registered PCI chipset driver data structures.
+ */
+static ide_pci_host_proc_t * ide_pci_host_proc_list;
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#undef __PROC_HELL
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -181,7 +148,11 @@
 	 * Do one full pass to verify all parameters,
 	 * then do another to actually write the regs.
 	 */
+#ifndef __PROC_HELL
 	save_flags(flags);	/* all CPUs */
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	do {
 		const char *p;
 		if (for_real) {
@@ -190,15 +161,32 @@
 			ide_hwgroup_t *mategroup = NULL;
 			if (hwif->mate && hwif->mate->hwgroup)
 				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
+#ifndef __PROC_HELL
 			cli();	/* all CPUs; ensure all writes are done together */
-			while (mygroup->busy || (mategroup && mategroup->busy)) {
+#else
+			spin_lock_irqsave(&io_request_lock, flags);
+#endif
+			while (mygroup->busy ||
+			       (mategroup && mategroup->busy)) {
+#ifndef __PROC_HELL
 				sti();	/* all CPUs */
-				if (0 < (signed long)(jiffies - timeout)) {
+#else
+				spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+				if (time_after(jiffies, timeout)) {
 					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
+#ifndef __PROC_HELL
 					restore_flags(flags);	/* all CPUs */
+#else
+					spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 					return -EBUSY;
 				}
+#ifndef __PROC_HELL
 				cli();	/* all CPUs */
+#else
+				spin_lock_irqsave(&io_request_lock, flags);
+#endif
 			}
 		}
 		p = buffer;
@@ -213,7 +201,7 @@
 						break;
 				case 'P':	is_pci = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+						if (hwif->pci_dev && !hwif->pci_dev->vendor)
 							break;
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 						msg = "not a PCI device";
@@ -281,7 +269,11 @@
 							break;
 					}
 					if (rc) {
+#ifndef __PROC_HELL
 						restore_flags(flags);	/* all CPUs */
+#else
+						spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
 							msg, dev->bus->number, dev->devfn, reg, val);
 						printk("proc_ide_write_config: error %d\n", rc);
@@ -311,11 +303,11 @@
  * 
  */
 					switch (digits) {
-						case 2:	outb(val, reg);
+						case 2:	hwif->OUTB(val, reg);
 							break;
-						case 4:	outw(val, reg);
+						case 4:	hwif->OUTW(val, reg);
 							break;
-						case 8:	outl(val, reg);
+						case 8:	hwif->OUTL(val, reg);
 							break;
 					}
 #endif /* !__mc68000__ && !CONFIG_APUS */
@@ -323,15 +315,23 @@
 			}
 		}
 	} while (!for_real++);
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	return count;
 parse_error:
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	printk("parse error\n");
 	return xx_xx_parse_error(start, startn, msg);
 }
 
-static int proc_ide_read_config
+int proc_ide_read_config
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -340,20 +340,26 @@
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
 	struct pci_dev	*dev = hwif->pci_dev;
-	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
+	if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) {
 		int reg = 0;
 
-		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
-			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+		out += sprintf(out, "pci bus %02x device %02x vendor %04x "
+				"device %04x channel %d\n",
+			dev->bus->number, dev->devfn,
+			hwif->pci_dev->vendor, hwif->pci_dev->device,
+			hwif->channel);
 		do {
-			byte val;
+			u8 val;
 			int rc = pci_read_config_byte(dev, reg, &val);
 			if (rc) {
-				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
+				printk("proc_ide_read_config: error %d reading"
+					" bus %02x dev %02x reg 0x%02x\n",
 					rc, dev->bus->number, dev->devfn, reg);
-				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "??%c",
+					(++reg & 0xf) ? ' ' : '\n');
 			} else
-				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "%02x%c",
+					val, (++reg & 0xf) ? ' ' : '\n');
 		} while (reg < 0x100);
 	} else
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
@@ -362,6 +368,7 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_config);
 
 static int ide_getdigit(char c)
 {
@@ -373,7 +380,7 @@
 	return digit;
 }
 
-static int proc_ide_read_drivers
+int proc_ide_read_drivers
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -384,14 +391,17 @@
 	while (p) {
 		driver = (ide_driver_t *) p->info;
 		if (driver)
-			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
+			out += sprintf(out, "%s version %s\n",
+				driver->name, driver->version);
 		p = p->next;
 	}
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_imodel
+EXPORT_SYMBOL(proc_ide_read_drivers);
+
+int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -414,14 +424,38 @@
 		case ide_cmd646:	name = "cmd646";	break;
 		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
-		case ide_pmac:		name = "mac-io";	break;
+		case ide_pmac:		name = "pmac";		break;
 		default:		name = "(unknown)";	break;
 	}
 	len = sprintf(page, "%s\n", name);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_mate
+#ifdef CONFIG_ALL_PPC
+static int proc_ide_read_devspec
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t		*hwif = (ide_hwif_t *) data;
+	int			len;
+	struct device_node	*ofnode = NULL;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	extern struct device_node* pmac_ide_get_of_node(int index);
+	if (hwif->chipset == ide_pmac)
+		ofnode = pmac_ide_get_of_node(hwif->index);
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#ifdef CONFIG_PCI
+	if (ofnode == NULL && hwif->pci_dev)
+		ofnode = pci_device_to_OF_node(hwif->pci_dev);
+#endif /* CONFIG_PCI */		
+	len = sprintf(page, "%s\n", ofnode ? ofnode->full_name : "");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif /* CONFIG_ALL_PPC */
+
+EXPORT_SYMBOL(proc_ide_read_imodel);
+
+int proc_ide_read_mate
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -434,7 +468,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_channel
+EXPORT_SYMBOL(proc_ide_read_mate);
+
+int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -446,41 +482,53 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_get_identify(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.sector_count = 0x01;
-	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
-
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
-}
+EXPORT_SYMBOL(proc_ide_read_channel);
 
-static int proc_ide_read_identify
+int proc_ide_read_identify
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *)data;
 	int		len = 0, i = 0;
+	int		err = 0;
 
-	if (drive && !proc_ide_get_identify(drive, page)) {
+	len = sprintf(page, "\n");
+	
+	if (drive)
+	{
 		unsigned short *val = (unsigned short *) page;
-		char *out = ((char *)val) + (SECTOR_WORDS * 4);
-		page = out;
-		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
-			val += 1;
-		} while (i < (SECTOR_WORDS * 2));
-		len = out - page;
+		
+		/*
+		 *	The current code can't handle a driverless
+		 *	identify query taskfile. Now the right fix is
+		 *	to add a 'default' driver but that is a bit
+		 *	more work. 
+		 *
+		 *	FIXME: this has to be fixed for hotswap devices
+		 */
+		 
+		if(DRIVER(drive))
+			err = taskfile_lib_get_identify(drive, page);
+		else	/* This relies on the ID changes */
+			val = (unsigned short *)drive->id;
+
+		if(!err)
+		{						
+			char *out = ((char *)page) + (SECTOR_WORDS * 4);
+			page = out;
+			do {
+				out += sprintf(out, "%04x%c",
+					le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+				val += 1;
+			} while (i < (SECTOR_WORDS * 2));
+			len = out - page;
+		}
 	}
-	else
-		len = sprintf(page, "\n");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_settings
+EXPORT_SYMBOL(proc_ide_read_identify);
+
+int proc_ide_read_settings
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -488,6 +536,7 @@
 	char		*out = page;
 	int		len, rc, mul_factor, div_factor;
 
+	down(&ide_setting_sem);
 	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
 	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
 	while(setting) {
@@ -507,12 +556,15 @@
 		setting = setting->next;
 	}
 	len = out - page;
+	up(&ide_setting_sem);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_settings);
+
 #define MAX_LEN	30
 
-static int proc_ide_write_settings
+int proc_ide_write_settings
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -573,12 +625,17 @@
 				--n;
 				++p;
 			}
+			
+			down(&ide_setting_sem);
 			setting = ide_find_setting_by_name(drive, name);
 			if (!setting)
+			{
+				up(&ide_setting_sem);
 				goto parse_error;
-
+			}
 			if (for_real)
 				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
+			up(&ide_setting_sem);
 		}
 	} while (!for_real++);
 	return count;
@@ -587,21 +644,21 @@
 	return -EINVAL;
 }
 
+EXPORT_SYMBOL(proc_ide_write_settings);
+
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
-	ide_driver_t    *driver = (ide_driver_t *) drive->driver;
 	int		len;
 
-	if (!driver)
-		len = sprintf(page, "(none)\n");
-        else
-		len = sprintf(page,"%llu\n",
-			      (unsigned long long) ((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);
 }
 
+EXPORT_SYMBOL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -609,38 +666,46 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+			drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+			drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_dmodel
+EXPORT_SYMBOL(proc_ide_read_geometry);
+
+int proc_ide_read_dmodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	struct hd_driveid *id = drive->id;
 	int		len;
 
-	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	len = sprintf(page, "%.40s\n",
+		(id && id->model[0]) ? (char *)id->model : "(none)");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_driver
+EXPORT_SYMBOL(proc_ide_read_dmodel);
+
+int proc_ide_read_driver
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	ide_driver_t	*driver = (ide_driver_t *) drive->driver;
 	int		len;
 
-	if (!driver)
-		len = sprintf(page, "(none)\n");
-	else
-		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+	len = sprintf(page, "%s version %s\n",
+		driver->name, driver->version);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_write_driver
+EXPORT_SYMBOL(proc_ide_read_driver);
+
+int proc_ide_write_driver
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -652,7 +717,9 @@
 	return count;
 }
 
-static int proc_ide_read_media
+EXPORT_SYMBOL(proc_ide_write_driver);
+
+int proc_ide_read_media
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -676,6 +743,8 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_media);
+
 static ide_proc_entry_t generic_drive_entries[] = {
 	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
@@ -702,6 +771,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_add_proc_entries);
+
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
 	if (!dir || !p)
@@ -712,7 +783,9 @@
 	}
 }
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+EXPORT_SYMBOL(ide_remove_proc_entries);
+
+void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
@@ -742,6 +815,8 @@
 	}
 }
 
+EXPORT_SYMBOL(create_proc_ide_drives);
+
 void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	struct proc_dir_entry *ent;
@@ -769,13 +844,14 @@
 	}
 }
 
+EXPORT_SYMBOL(recreate_proc_ide_device);
+
 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, 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);
@@ -783,24 +859,29 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_device);
+
 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);
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_drives);
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
 	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
+#ifdef CONFIG_ALL_PPC
+	{ "devspec",	S_IFREG|S_IRUGO,	proc_ide_read_devspec,	NULL },
+#endif	
 	{ NULL,	0, NULL, NULL }
 };
 
@@ -823,7 +904,9 @@
 	}
 }
 
-static void destroy_proc_ide_interfaces(void)
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+void destroy_proc_ide_interfaces(void)
 {
 	int	h;
 
@@ -844,8 +927,34 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_interfaces);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+void ide_pci_register_host_proc (ide_pci_host_proc_t *p)
+{
+	ide_pci_host_proc_t *tmp;
+
+	if (!p) return;
+	p->next = NULL;
+	p->set = 1;
+	if (ide_pci_host_proc_list) {
+		tmp = ide_pci_host_proc_list;
+		while (tmp->next) tmp = tmp->next;
+		tmp->next = p;
+	} else
+		ide_pci_host_proc_list = p;
+}
+
+EXPORT_SYMBOL(ide_pci_register_host_proc);
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 void proc_ide_create(void)
 {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 	proc_ide_root = proc_mkdir("ide", 0);
 	if (!proc_ide_root) return;
 
@@ -854,120 +963,40 @@
 	create_proc_read_entry("drivers", 0, proc_ide_root,
 				proc_ide_read_drivers, NULL);
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	while (p != NULL)
+	{
+		if (p->name != NULL && p->set == 1 && p->get_info != NULL) 
+		{
+			p->parent = proc_ide_root;
+			create_proc_info_entry(p->name, 0, p->parent, p->get_info);
+			p->set = 2;
+		}
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+EXPORT_SYMBOL(proc_ide_create);
+
 void proc_ide_destroy(void)
 {
-	/*
-	 * Mmmm.. does this free up all resources,
-	 * or do we need to do a more proper cleanup here ??
-	 */
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		remove_proc_entry("ide/aec62xx",0);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		remove_proc_entry("ide/ali",0);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		remove_proc_entry("ide/amd74xx",0);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		remove_proc_entry("ide/cmd64x",0);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		remove_proc_entry("ide/cs5530",0);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		remove_proc_entry("ide/hpt34x",0);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		remove_proc_entry("ide/hpt366",0);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		remove_proc_entry("ide/pdc202xx",0);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		remove_proc_entry("ide/piix",0);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		remove_proc_entry("ide/svwks",0);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		remove_proc_entry("ide/sis", 0);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		remove_proc_entry("ide/slc90e66",0);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+	char name[32];
 
-	remove_proc_entry("ide/drivers", 0);
+	while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) {
+		name[0] = '\0';
+		sprintf(name, "ide/%s", p->name);
+		if (p->set == 2)
+			remove_proc_entry(p->name, p->parent);
+		if (p->next == NULL) break;
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	remove_proc_entry("ide/drivers", proc_ide_root);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
+
+EXPORT_SYMBOL(proc_ide_destroy);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-sibyte.c linux-2.4.21-rc3/drivers/ide/ide-sibyte.c
--- linux-2.4.20/drivers/ide/ide-sibyte.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-sibyte.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/64bit.h>
-#include <asm/sibyte/board.h>
-
-/* Note: this should be general for any board using IDE on GenBus */
-
-extern struct ide_ops std_ide_ops;
-
-static ide_hwif_t *sb_ide_hwif = NULL;
-static unsigned long ide_base;
-
-#define SIBYTE_IDE_BASE        (KSEG1ADDR(ide_base)-mips_io_port_base)
-#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5))
-
-/*
- * We are limiting the number of PCI-IDE devices to leave room for
- * GenBus IDE (and possibly PCMCIA/CF?)
- */
-static int sibyte_ide_default_irq(ide_ioreg_t base)
-{
-	return 0;
-}
-
-static ide_ioreg_t sibyte_ide_default_io_base(int index)
-{
-	return 0;
-}
-
-static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
-				       ide_ioreg_t ctrl_port, int *irq)
-{
-	std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
-}
-
-static int sibyte_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static void sibyte_ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static inline int is_sibyte_ide(ide_ioreg_t from)
-{
-	return (sb_ide_hwif &&
-		((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET])));
-}
-
-static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	/* Figure out if it's the SiByte IDE; if so, don't do anything
-           since our I/O space is in a weird place. */
-	if (is_sibyte_ide(from))
-		return 0;
-	else
-#ifdef CONFIG_BLK_DEV_IDE
-		return std_ide_ops.ide_check_region(from, extent);
-#else
-		return 0;
-#endif
-}
-
-static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent,
-				     const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_request_region(from, extent, name);
-#endif
-}
-
-static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_release_region(from, extent);
-#endif
-}
-
-struct ide_ops sibyte_ide_ops = {
-	&sibyte_ide_default_irq,
-	&sibyte_ide_default_io_base,
-	&sibyte_ide_init_hwif_ports,
-	&sibyte_ide_request_irq,
-	&sibyte_ide_free_irq,
-	&sibyte_ide_check_region,
-	&sibyte_ide_request_region,
-	&sibyte_ide_release_region
-};
-
-/*
- * I/O operations. The FPGA for SiByte generic bus IDE deals with
- * byte-swapping for us, so we can't share the I/O macros with other
- * IDE (e.g. PCI-IDE) devices.
- */
-
-#define sibyte_outb(val,port)					\
-do {								\
-	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outw(val,port)					\
-do {								\
-	*(volatile u16 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outl(val,port)					\
-do {								\
-	*(volatile u32 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-static inline unsigned char sibyte_inb(unsigned long port)
-{
-	return (*(volatile u8 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned short sibyte_inw(unsigned long port)
-{
-	return (*(volatile u16 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned int sibyte_inl(unsigned long port)
-{
-	return (*(volatile u32 *)(mips_io_port_base + (port)));
-}
-
-
-static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outb(*(u8 *)addr, port);
-		addr++;
-	}
-}
-
-static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u8 *)addr = sibyte_inb(port);
-		addr++;
-	}
-}
-
-static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outw(*(u16 *)addr, port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u16 *)addr = sibyte_inw(port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outl(*(u32 *)addr, port);
-		addr += 4;
-	}
-}
-
-static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u32 *)addr = sibyte_inl(port);
-		addr += 4;
-	}
-}
-
-static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive,
-			   void *buffer, unsigned int count)
-{
-	/*  slow? vlb_sync? */
-	switch (action) {
-	case ideproc_ide_input_data:
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_ide_output_data:
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_atapi_input_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	case ideproc_atapi_output_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	}
-}
-
-/*
- * selectproc and intrproc aren't really necessary, since
- * byte-swapping doesn't affect byte ops; they are included for
- * consistency.
- */
-static void sibyte_selectproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->select.all, IDE_SELECT_REG);
-}
-
-static void sibyte_intrproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->ctl|2, IDE_CONTROL_REG);
-}
-
-void __init sibyte_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif;
-	/* 
-	 * Find the first untaken slot in hwifs 
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
-			break;
-		}
-	}
-	if (i == MAX_HWIFS) {
-		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Find memory base address */
-#ifdef __MIPSEL__
-	/* Pass1 workaround (bug 1624) */
-	if (sb1250_pass == K_SYS_REVISION_PASS1)
-		ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE;
-	else
-#endif
-		ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE;
-
-	/*
-	 * Set up our stuff; we're a little odd because our io_ports
-	 * aren't in the usual place, and byte-swapping isn't
-	 * necessary.
-	 */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
-	hwif->hw.irq                          = K_INT_GB_IDE;
-	hwif->irq                             = K_INT_GB_IDE;
-	hwif->noprobe                         = 0;
-	/* Use our own non-byte-swapping routines */
-	hwif->ideproc                         = sibyte_ideproc;
-	hwif->selectproc                      = sibyte_selectproc;
-	hwif->intrproc                        = sibyte_intrproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	printk("SiByte onboard IDE configured as device %i\n", i);
-	sb_ide_hwif = hwif;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-tape.c linux-2.4.21-rc3/drivers/ide/ide-tape.c
--- linux-2.4.20/drivers/ide/ide-tape.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-tape.c	2003-05-22 22:06:27.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ * linux/drivers/ide/ide-tape.c		Version 1.17b	Dec, 2002
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- Limit size of pipeline
+ * Ver 1.17b Dec 2002   Alan Stern <stern@rowland.harvard.edu>
+ *			Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ *			 it in the code!
+ *			Actually removed aborted stages in idetape_abort_pipeline
+ *			 instead of just changing the command code.
+ *			Made the transfer byte count for Request Sense equal to the
+ *			 actual length of the data transfer.
+ *			Changed handling of partial data transfers: they do not
+ *			 cause DMA errors.
+ *			Moved initiation of DMA transfers to the correct place.
+ *			Removed reference to unallocated memory.
+ *			Made __idetape_discard_read_pipeline return the number of
+ *			 sectors skipped, not the number of stages.
+ *			Replaced errant kfree() calls with __idetape_kfree_stage().
+ *			Fixed off-by-one error in testing the pipeline length.
+ *			Fixed handling of filemarks in the read pipeline.
+ *			Small code optimization for MTBSF and MTBSFM ioctls.
+ *			Don't try to unlock the door during device close if is
+ *			 already unlocked!
+ *			Cosmetic fixes to miscellaneous debugging output messages.
+ *			Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ *			 "pipeline_min", and "pipeline_max" to 1.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.17a"
+#define IDETAPE_VERSION "1.17b-ac1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -416,7 +438,6 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
@@ -429,8 +450,6 @@
 #include <asm/bitops.h>
 
 
-#define NO_LONGER_REQUIRED	(1)
-
 /*
  *	OnStream support
  */
@@ -577,9 +596,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	the optimum value or until we reach MAX.
  *
- *	Setting the following parameter to 0 will disable the pipelined mode.
+ *	Setting the following parameter to 0 is illegal: the pipelined mode
+ *	cannot be disabled (calculate_speeds() divides by tape->max_stages.)
  */
-#define IDETAPE_MIN_PIPELINE_STAGES	200
+#define IDETAPE_MIN_PIPELINE_STAGES	  1
 #define IDETAPE_MAX_PIPELINE_STAGES	400
 #define IDETAPE_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +621,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -724,22 +744,28 @@
 	struct buffer_head *bh;
 	char *b_data;
 	int b_count;
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idetape_pc_t;
 
 /*
  *	Packet command flag bits.
  */
-#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
-#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
-#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
-#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
-#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
-#define	PC_WRITING			5	/* Data direction */
+/* Set when an error is considered normal - We won't retry */
+#define	PC_ABORT			0
+/* 1 When polling for DSC on a media access command */
+#define PC_WAIT_FOR_DSC			1
+/* 1 when we prefer to use DMA if possible */
+#define PC_DMA_RECOMMENDED		2
+/* 1 while DMA in progress */
+#define	PC_DMA_IN_PROGRESS		3
+/* 1 when encountered problem during DMA */
+#define	PC_DMA_ERROR			4
+/* Data direction */
+#define	PC_WRITING			5
 
 /*
  *	Capabilities and Mechanical Status Page
@@ -814,6 +840,7 @@
  *	REQUEST SENSE packet command result - Data Format.
  */
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	error_code	:7;	/* Current of deferred errors */
 	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
 	__u8		reserved1	:8;	/* Segment Number - Reserved */
@@ -822,6 +849,18 @@
 	unsigned	ili		:1;	/* Incorrect Length Indicator */
 	unsigned	eom		:1;	/* End Of Medium */
 	unsigned	filemark 	:1;	/* Filemark */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;
+	unsigned	error_code	:7;
+	__u8		reserved1	:8;
+	unsigned	filemark	:1;
+	unsigned	eom		:1;
+	unsigned	ili		:1;
+	unsigned	reserved2_4	:1;
+	unsigned	sense_key	:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	__u32		information __attribute__ ((packed));
 	__u8		asl;			/* Additional sense length (n-7) */
 	__u32		command_specific;	/* Additional command specific information */
@@ -860,12 +899,17 @@
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	idetape_pc_t *pc;			/* Current packet command */
-	idetape_pc_t *failed_pc; 		/* Last failed packet command */
-	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idetape_pc_t *pc;
+	/* Last failed packet command */
+	idetape_pc_t *failed_pc;
+	/* Packet command stack */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDETAPE_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	DSC polling variables.
@@ -879,38 +923,48 @@
 	 *	to ide.c only one at a time.
 	 */
 	struct request *postponed_rq;
-	unsigned long dsc_polling_start;	/* The time in which we started polling for DSC */
-	struct timer_list dsc_timer;		/* Timer used to poll for dsc */
-	unsigned long best_dsc_rw_frequency;	/* Read/Write dsc polling frequency */
-	unsigned long dsc_polling_frequency;	/* The current polling frequency */
-	unsigned long dsc_timeout;		/* Maximum waiting time */
+	/* The time in which we started polling for DSC */
+	unsigned long dsc_polling_start;
+	/* Timer used to poll for dsc */
+	struct timer_list dsc_timer;
+	/* Read/Write dsc polling frequency */
+	unsigned long best_dsc_rw_frequency;
+	/* The current polling frequency */
+	unsigned long dsc_polling_frequency;
+	/* Maximum waiting time */
+	unsigned long dsc_timeout;
 
 	/*
 	 *	Read position information
 	 */
-	byte partition;
-	unsigned int first_frame_position;		/* Current block */
+	u8 partition;
+	/* Current block */
+	unsigned int first_frame_position;
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
+	u8 sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
 	 */
 	unsigned int minor;
-	char name[4];					/* device name */
-	idetape_chrdev_direction_t chrdev_direction;	/* Current character device data transfer direction */
+	/* device name */
+	char name[4];
+	/* Current character device data transfer direction */
+	idetape_chrdev_direction_t chrdev_direction;
 
 	/*
 	 *	Device information
 	 */
-	unsigned short tape_block_size;			/* Usually 512 or 1024 bytes */
+	/* Usually 512 or 1024 bytes */
+	unsigned short tape_block_size;
 	int user_bs_factor;
-	idetape_capabilities_page_t capabilities;	/* Copy of the tape's Capabilities and Mechanical Page */
+	/* Copy of the tape's Capabilities and Mechanical Page */
+	idetape_capabilities_page_t capabilities;
 
 	/*
 	 *	Active data transfer request parameters.
@@ -925,8 +979,10 @@
 	 *	The data buffer size is chosen based on the tape's
 	 *	recommendation.
 	 */
-	struct request *active_data_request;	/* Pointer to the request which is waiting in the device request queue */
-	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
+	/* Pointer to the request, waiting in the device request queue */
+	struct request *active_data_request;
+	/* Data buffer size (chosen based on the tape's recommendation */
+	int stage_size;
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
 	struct buffer_head *bh;
@@ -939,19 +995,30 @@
 	 *	To accomplish non-pipelined mode, we simply set the following
 	 *	variables to zero (or NULL, where appropriate).
 	 */
-	int nr_stages;				/* Number of currently used stages */
-	int nr_pending_stages;			/* Number of pending stages */
-	int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */
-	idetape_stage_t *first_stage;		/* The first stage which will be removed from the pipeline */
-	idetape_stage_t *active_stage;		/* The currently active stage */
-	idetape_stage_t *next_stage;		/* Will be serviced after the currently active request */
-	idetape_stage_t *last_stage;		/* New requests will be added to the pipeline here */
-	idetape_stage_t *cache_stage;		/* Optional free stage which we can use */
+	/* Number of currently used stages */
+	int nr_stages;
+	/* Number of pending stages */
+	int nr_pending_stages;
+	/* We will not allocate more than this number of stages */
+	int max_stages, min_pipeline, max_pipeline;
+	/* The first stage which will be removed from the pipeline */
+	idetape_stage_t *first_stage;
+	/* The currently active stage */
+	idetape_stage_t *active_stage;
+	/* Will be serviced after the currently active request */
+	idetape_stage_t *next_stage;
+	/* New requests will be added to the pipeline here */
+	idetape_stage_t *last_stage;
+	/* Optional free stage which we can use */
+	idetape_stage_t *cache_stage;
 	int pages_per_stage;
-	int excess_bh_size;			/* Wasted space in each stage */
+	/* Wasted space in each stage */
+	int excess_bh_size;
 
-	unsigned long flags;			/* Status/Action flags: long for set_bit */
-	spinlock_t spinlock;			/* protects the ide-tape queue */
+	/* Status/Action flags: long for set_bit */
+	unsigned long flags;
+	/* protects the ide-tape queue */
+	spinlock_t spinlock;
 
 	/*
 	 * Measures average tape speed
@@ -960,31 +1027,44 @@
 	int avg_size;
 	int avg_speed;
 
-	idetape_request_sense_result_t sense;	/* last sense information */
+	/* last sense information */
+	idetape_request_sense_result_t sense;
 
 	char vendor_id[10];
 	char product_id[18];
 	char firmware_revision[6];
 	int firmware_revision_num;
 
-	int door_locked;			/* the door is currently locked */
+	/* the door is currently locked */
+	int door_locked;
 
 	/*
 	 * OnStream flags
 	 */
-	int onstream;				/* the tape is an OnStream tape */
-	int raw;				/* OnStream raw access (32.5KB block size) */
-	int cur_frames;				/* current number of frames in internal buffer */
-	int max_frames;				/* max number of frames in internal buffer */
-	int logical_blk_num;			/* logical block number */
-	__u16 wrt_pass_cntr;			/* write pass counter */
-	__u32 update_frame_cntr;		/* update frame counter */
+	/* the tape is an OnStream tape */
+	int onstream;
+	/* OnStream raw access (32.5KB block size) */
+	int raw;
+	/* current number of frames in internal buffer */
+	int cur_frames;
+	/* max number of frames in internal buffer */
+	int max_frames;
+	/* logical block number */
+	int logical_blk_num;
+	/* write pass counter */
+	__u16 wrt_pass_cntr;
+	/* update frame counter */
+	__u32 update_frame_cntr;
 	struct completion *waiting;
-	int onstream_write_error;		/* write error recovery active */
-	int header_ok;				/* header frame verified ok */
-	int linux_media;			/* reading linux-specifc media */
+	/* write error recovery active */
+	int onstream_write_error;
+	/* header frame verified ok */
+	int header_ok;
+	/* reading linux-specifc media */
+	int linux_media;
 	int linux_media_version;
-	char application_sig[5];		/* application signature */
+	/* application signature */
+	char application_sig[5];
 	int filemark_cnt;
 	int first_mark_addr;
 	int last_mark_addr;
@@ -997,8 +1077,10 @@
 	 * Optimize the number of "buffer filling"
 	 * mode sense commands.
 	 */
-	unsigned long last_buffer_fill;		/* last time in which we issued fill cmd */
-	int req_buffer_fill;			/* buffer fill command requested */
+	/* last time in which we issued fill cmd */
+	unsigned long last_buffer_fill;
+	/* buffer fill command requested */
+	int req_buffer_fill;
 	int writes_since_buffer_fill;
 	int reads_since_buffer_fill;
 
@@ -1007,7 +1089,8 @@
 	 * be postponed, to avoid an infinite postpone
 	 * deadlock.
 	 */
-	int postpone_cnt;			/* request postpone count limit */
+	/* request postpone count limit */
+	int postpone_cnt;
 
 	/*
 	 * Measures number of frames:
@@ -1040,11 +1123,17 @@
 	 * Speed regulation negative feedback loop
 	 */
 	int speed_control;
-	int pipeline_head_speed, controlled_pipeline_head_speed, uncontrolled_pipeline_head_speed;
-	int controlled_last_pipeline_head, uncontrolled_last_pipeline_head;
-	unsigned long uncontrolled_pipeline_head_time, controlled_pipeline_head_time;
-	int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head;
-	unsigned long controlled_previous_head_time, uncontrolled_previous_head_time;
+	int pipeline_head_speed;
+	int controlled_pipeline_head_speed;
+	int uncontrolled_pipeline_head_speed;
+	int controlled_last_pipeline_head;
+	int uncontrolled_last_pipeline_head;
+	unsigned long uncontrolled_pipeline_head_time;
+	unsigned long controlled_pipeline_head_time;
+	int controlled_previous_pipeline_head;
+	int uncontrolled_previous_pipeline_head;
+	unsigned long controlled_previous_head_time;
+	unsigned long uncontrolled_previous_head_time;
 	int restart_speed_control_req;
 
         /*
@@ -1164,101 +1253,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idetape_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-	} b;
-} idetape_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-	} b;
-} idetape_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idetape_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idetape_ireason_reg_t;
-
-/*
- *	ATAPI Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-	} b;
-} idetape_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-	} b;
-} idetape_control_reg_t;
-
-/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ide_drive_t structure.
@@ -1432,41 +1426,60 @@
  * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
  */
 
-char *idetape_sense_key_verbose (byte idetape_sense_key)
+char *idetape_sense_key_verbose (u8 idetape_sense_key)
 {
 	switch (idetape_sense_key) {
 		default: {
 			char buf[22];
-			sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
+			sprintf(buf, "IDETAPE_SENSE (0x%02x)",
+				idetape_sense_key);
 			return(buf);
 		}
 
 	}
 }
 
-char *idetape_command_key_verbose (byte idetape_command_key)
+char *idetape_command_key_verbose (u8 idetape_command_key)
 {
 	switch (idetape_command_key) {
-		case IDETAPE_TEST_UNIT_READY_CMD:	return("TEST_UNIT_READY_CMD");
-		case IDETAPE_REWIND_CMD:		return("REWIND_CMD");
-		case IDETAPE_REQUEST_SENSE_CMD:		return("REQUEST_SENSE_CMD");
-		case IDETAPE_READ_CMD:			return("READ_CMD");
-		case IDETAPE_WRITE_CMD:			return("WRITE_CMD");
-		case IDETAPE_WRITE_FILEMARK_CMD:	return("WRITE_FILEMARK_CMD");
-		case IDETAPE_SPACE_CMD:			return("SPACE_CMD");
-		case IDETAPE_INQUIRY_CMD:		return("INQUIRY_CMD");
-		case IDETAPE_ERASE_CMD:			return("ERASE_CMD");
-		case IDETAPE_MODE_SENSE_CMD:		return("MODE_SENSE_CMD");
-		case IDETAPE_MODE_SELECT_CMD:		return("MODE_SELECT_CMD");
-		case IDETAPE_LOAD_UNLOAD_CMD:		return("LOAD_UNLOAD_CMD");
-		case IDETAPE_PREVENT_CMD:		return("PREVENT_CMD");
-		case IDETAPE_LOCATE_CMD:		return("LOCATE_CMD");
-		case IDETAPE_READ_POSITION_CMD:		return("READ_POSITION_CMD");
-		case IDETAPE_READ_BUFFER_CMD:		return("READ_BUFFER_CMD");
-		case IDETAPE_SET_SPEED_CMD:		return("SET_SPEED_CMD");
+		case IDETAPE_TEST_UNIT_READY_CMD:
+			return("TEST_UNIT_READY_CMD");
+		case IDETAPE_REWIND_CMD:
+			return("REWIND_CMD");
+		case IDETAPE_REQUEST_SENSE_CMD:
+			return("REQUEST_SENSE_CMD");
+		case IDETAPE_READ_CMD:
+			return("READ_CMD");
+		case IDETAPE_WRITE_CMD:
+			return("WRITE_CMD");
+		case IDETAPE_WRITE_FILEMARK_CMD:
+			return("WRITE_FILEMARK_CMD");
+		case IDETAPE_SPACE_CMD:
+			return("SPACE_CMD");
+		case IDETAPE_INQUIRY_CMD:
+			return("INQUIRY_CMD");
+		case IDETAPE_ERASE_CMD:
+			return("ERASE_CMD");
+		case IDETAPE_MODE_SENSE_CMD:
+			return("MODE_SENSE_CMD");
+		case IDETAPE_MODE_SELECT_CMD:
+			return("MODE_SELECT_CMD");
+		case IDETAPE_LOAD_UNLOAD_CMD:
+			return("LOAD_UNLOAD_CMD");
+		case IDETAPE_PREVENT_CMD:
+			return("PREVENT_CMD");
+		case IDETAPE_LOCATE_CMD:
+			return("LOCATE_CMD");
+		case IDETAPE_READ_POSITION_CMD:
+			return("READ_POSITION_CMD");
+		case IDETAPE_READ_BUFFER_CMD:
+			return("READ_BUFFER_CMD");
+		case IDETAPE_SET_SPEED_CMD:
+			return("SET_SPEED_CMD");
 		default: {
 				char buf[20];
-				sprintf(buf, "CMD (0x%02x)", idetape_command_key);
+				sprintf(buf, "CMD (0x%02x)",
+					idetape_command_key);
 				return(buf);
 			}
 	}
@@ -1482,13 +1495,13 @@
 static void idetape_write_release (struct inode *inode);
 
 /*
- *	Too bad. The drive wants to send us data which we are not ready to accept.
- *	Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
  */
 static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
@@ -1499,13 +1512,14 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
-			idetape_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
+			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(bh->b_size - atomic_read(&bh->b_count), bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
 		bcount -= count;
 		atomic_add(count, &bh->b_count);
 		if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1525,12 +1539,13 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		count = IDE_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -1550,16 +1565,17 @@
 	struct buffer_head *bh = pc->bh;
 	int count, bcount = pc->actually_transferred;
 
-	if (test_bit (PC_WRITING, &pc->flags))
+	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");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
+		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;
@@ -1581,9 +1597,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+		printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+			tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+	if (tape->pc_stack_index == IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
 	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
@@ -1607,9 +1624,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+		printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+			tape->rq_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->rq_stack_index==IDETAPE_PC_STACK)
+	if (tape->rq_stack_index == IDETAPE_PC_STACK)
 		tape->rq_stack_index=0;
 	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
@@ -1619,7 +1637,7 @@
  */
 static void idetape_init_pc (idetape_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -1649,19 +1667,23 @@
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-				pc->c[0], result->sense_key, result->asc, result->ascq);
+		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			pc->c[0], result->sense_key,
+			result->asc, result->ascq);
 #if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
-			idetape_command_key_verbose((byte) pc->c[0]),
+		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			idetape_command_key_verbose((u8) pc->c[0]),
 			result->sense_key,
 			result->asc,
 			result->ascq);
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
+	if (tape->onstream && result->sense_key == 2 &&
+	    result->asc == 0x53 && result->ascq == 2) {
 		clear_bit(PC_DMA_ERROR, &pc->flags);
 		ide_stall_queue(drive, HZ / 2);
 		return;
@@ -1671,49 +1693,33 @@
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
-		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
-		idetape_update_buffers (pc);
+	if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned (&result->information));
+		idetape_update_buffers(pc);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
 		pc->error = IDETAPE_ERROR_FILEMARK;
-		set_bit (PC_ABORT, &pc->flags);
+		set_bit(PC_ABORT, &pc->flags);
 	}
 	if (pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+		if (result->eom || (result->sense_key == 0xd &&
+		    result->asc == 0x0 && result->ascq == 0x2)) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
 	}
 	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
 		if (result->sense_key == 8) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
-		if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred))
+		if (!test_bit(PC_ABORT, &pc->flags) &&
+		    (tape->onstream || pc->actually_transferred))
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
 
-static void idetape_abort_pipeline (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage = tape->next_stage;
-
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
-		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;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1725,11 +1731,12 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to activate a "
+			"non existing stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
@@ -1755,10 +1762,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1776,21 +1783,21 @@
 		if (bh->b_data != NULL) {
 			size = (int) bh->b_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page((unsigned long) bh->b_data);
 				size -= PAGE_SIZE;
 				bh->b_data += PAGE_SIZE;
 			}
 		}
 		prev_bh = bh;
 		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		kfree(prev_bh);
 	}
-	kfree (stage);
+	kfree(stage);
 }
 
 static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 /*
@@ -1804,45 +1811,72 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (tape->first_stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
 		return;		
 	}
 	if (tape->active_stage == tape->first_stage) {
-		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to free our "
+			"active pipeline stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	stage = tape->first_stage;
 	tape->first_stage = stage->next;
-	idetape_kfree_stage (tape, stage);
+	idetape_kfree_stage(tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
 		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
-			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+			printk(KERN_ERR "ide-tape: bug: "
+				"tape->next_stage != NULL\n");
 		if (tape->nr_stages)
-			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+			printk(KERN_ERR "ide-tape: bug: nr_stages should "
+				"be 0 now\n");
 #endif /* IDETAPE_DEBUG_BUGS */
 	}
 }
 
+static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage = tape->next_stage;
+	idetape_stage_t *nstage;
+
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
+		printk(KERN_INFO "ide-tape: %s: %s called\n",
+			tape->name, __FUNCTION__);
+#endif
+	while (stage) {
+		nstage = stage->next;
+		idetape_kfree_stage(tape, stage);
+		--tape->nr_stages;
+		--tape->nr_pending_stages;
+		stage = nstage;
+	}
+	tape->last_stage = last_stage;
+	if (last_stage)
+		last_stage->next = NULL;
+	tape->next_stage = NULL;
+}
+
 /*
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idetape_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1851,7 +1885,7 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -1864,7 +1898,9 @@
 		tape->failed_pc = NULL;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+	if (tape->active_data_request == rq) {
+		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1884,34 +1920,40 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					if (tape->debug_level >= 2)
-						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
+						printk("ide-tape: %s: skipping over config partition.\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
-				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
-					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+					idetape_abort_pipeline(drive, active_stage);
+				if (tape->onstream && !tape->raw &&
+				    error == IDETAPE_ERROR_GENERAL &&
+				    tape->sense.sense_key == 3) {
+					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
 					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
-				idetape_abort_pipeline(drive);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+				idetape_abort_pipeline(drive, active_stage);
 			}
 		}
 		if (tape->next_stage != NULL && !tape->onstream_write_error) {
@@ -1920,18 +1962,19 @@
 			/*
 			 *	Insert the next request into the request queue.
 			 */
-			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
 			if (!tape->onstream)
-				idetape_increase_max_pipeline_stages (drive);
+				idetape_increase_max_pipeline_stages(drive);
 		}
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (remove_stage)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
 		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
+	return 0;
 }
 
 static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
@@ -1940,24 +1983,25 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0, HWGROUP (drive));
+		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
+			"itself - Aborting request!\n");
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
 
 static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);	
+	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -1982,10 +2026,10 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->cmd = IDETAPE_PC_RQ1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 /*
@@ -1998,14 +2042,14 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *rq;
-	idetape_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage (drive);
 	rq = idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc);
-	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	idetape_queue_pc_head (drive, pc, rq);
+	idetape_create_request_sense_cmd(pc);
+	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head(drive, pc, rq);
 	return ide_stopped;
 }
 
@@ -2037,9 +2081,9 @@
 static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
 	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
@@ -2050,14 +2094,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+				"interrupt handler\n");
 #endif /* IDETAPE_DEBUG_LOG */	
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2069,8 +2115,18 @@
 			 * actually transferred (we can't receive that
 			 * information from the DMA engine on most chipsets).
 			 */
+
+			/*
+			 * On the contrary, a DMA error is never expected;
+			 * it usually indicates a hardware error or abort.
+			 * If the tape crosses a filemark during a READ
+			 * command, it will issue an irq and position itself
+			 * after the filemark (not before). Only a partial
+			 * data transfer will occur, but no DMA error.
+			 * (AS, 19 Apr 2001)
+			 */
 			set_bit (PC_DMA_ERROR, &pc->flags);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2081,106 +2137,139 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+			printk(KERN_INFO "ide-tape: Packet command completed, "
+				"%d bytes transferred\n",
+				pc->actually_transferred);
 #endif /* IDETAPE_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
 #if SIMULATE_ERRORS
-		if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
-			printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
+		if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+		     pc->c[0] == IDETAPE_READ_CMD) &&
+		    (++error_sim_count % 100) == 0) {
+			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+				tape->name);
 			status.b.check = 1;
 		}
 #endif
 		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
 			status.b.check = 0;
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
-#if IDETAPE_DEBUG_LOG
-			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-tape: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
+				printk(KERN_INFO "ide-tape: [cmd %x]: check "
+					"condition\n", pc->c[0]);
 #endif
-			return idetape_retry_pc (drive);				/* Retry operation */
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
-		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+		if (!tape->onstream &&
+		    test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+		    !status.b.dsc) {
+			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
+			/* Allow ide.c to handle other requests */
+			idetape_postpone_request(drive);
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		return pc->callback(drive);			/* Command finished - Call the callback function */
+		/* Command finished - Call the callback function */
+		return pc->callback(drive);
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
-		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-tape: The tape wants to issue more "
+				"interrupts in DMA mode\n");
+		printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all   = IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-tape: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data (drive, bcount.all);
-				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-tape: The tape wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				idetape_discard_data(drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idetape_pc_intr,
+						IDETAPE_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+				printk(KERN_NOTICE "ide-tape: The tape wants "
+					"to send us more data than expected "
+					"- allowing transfer\n");
 #endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bh != NULL)
-			idetape_output_buffers (drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,pc->current_position,bcount.all);
 	} else {
 		if (pc->bh != NULL)
-			idetape_input_buffers (drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,pc->current_position,bcount.all);
 	}
-	pc->actually_transferred += bcount.all;					/* Update the current position */
-	pc->current_position+=bcount.all;
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] done %d\n"
+			pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 	return ide_started;
 }
 
@@ -2217,9 +2306,9 @@
  *
  *	4.	When the packet command is finished, it will be checked for errors.
  *
- *	5.	In case an error was found, we queue a request sense packet command
- *		in front of the request queue and retry the operation up to
- *		IDETAPE_MAX_PC_RETRIES times.
+ *	5.	In case an error was found, we queue a request sense packet
+ *		command in front of the request queue and retry the operation
+ *		upto IDETAPE_MAX_PC_RETRIES times.
  *
  *	6.	In case no error was found, or we decided to give up and not
  *		to retry again, the callback function will be called and then
@@ -2230,108 +2319,144 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 	int retries = 100;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-tape: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+				"a packet command, retrying\n");
 		udelay(100);
-		ireason.all = IN_BYTE(IDE_IREASON_REG);
+		ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 		if (retries == 0) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+					"issuing a packet command, ignoring\n");
 			ireason.b.cod = 1;
 			ireason.b.io = 0;
 		}
 	}
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+				"a packet command\n");
+		return ide_do_reset(drive);
 	}
 	tape->cmd_start_time = jiffies;
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	/* Begin DMA, if necessary */
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+#endif
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
 }
 
 static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 
 #if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
 		tape->failed_pc = pc;
-	tape->pc = pc;							/* Set the current packet command */
+	/* Set the current packet command */
+	tape->pc = pc;
 
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
-			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
-				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+			      tape->sense_key == 2 && tape->asc == 4 &&
+			     (tape->ascq == 1 || tape->ascq == 8))) {
+				printk(KERN_ERR "ide-tape: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						tape->name, pc->c[0],
+						tape->sense_key, tape->asc,
+						tape->ascq);
+				if (tape->onstream &&
+				    pc->c[0] == IDETAPE_READ_CMD &&
+				    tape->sense_key == 3 &&
+				    tape->asc == 0x11)
+					/* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
-			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDETAPE_ERROR_GENERAL;
 		}
 		tape->failed_pc = NULL;
 		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+		printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n",
+				pc->retries, pc->c[0]);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = pc->request_transfer;
 
 #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_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		printk(KERN_WARNING "ide-tape: DMA disabled, "
+				"reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(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);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(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));
-	}
+	if (feature.b.dma)		/* Will begin DMA later */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 #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);
+		ide_execute_command(drive, WIN_PACKETCMD,
+				&idetape_transfer_pc,
+				IDETAPE_WAIT_CMD,
+				NULL);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idetape_transfer_pc(drive);
 	}
 }
@@ -2348,22 +2473,22 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
 /*
  *	A mode sense command is used to "sense" tape parameters.
  */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
 {
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
+		pc->c[1] = 8;	/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
-	pc->c[3] = 255;				/* Don't limit the returned information */
-	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	pc->c[3] = 255;		/* Don't limit the returned information */
+	pc->c[4] = 255;		/* (We will just discard data in that case) */
 	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
 		pc->request_transfer = 12;
 	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2391,13 +2516,15 @@
 	}
 	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
 #if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
+			tape->tape_head, tape->minor);
 #endif
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
+			tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2429,7 +2556,8 @@
 	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
-	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
+	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+		/* -1 for read mode error recovery */
 		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
@@ -2465,15 +2593,24 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 	if (tape->onstream)
-		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
-	status.all = GET_STAT();
+		printk(KERN_INFO "ide-tape: bug: "
+			"onstream, media_access_finished\n");
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
 	if (status.b.dsc) {
-		if (status.b.check) {					/* Error detected */
-			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			return idetape_retry_pc (drive);			/* Retry operation */
+		if (status.b.check) {
+			/* Error detected */
+			printk(KERN_ERR "ide-tape: %s: I/O error: "
+			    "pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+			    tape->name, pc->c[0],
+			    tape->sense_key, tape->asc, tape->ascq);
+
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2510,16 +2647,16 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->first_frame_position += blocks;
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_end_request(drive, 1);
 	else
-		idetape_end_request (tape->pc->error, HWGROUP (drive));
+		idetape_end_request(drive, tape->pc->error);
 	return ide_stopped;
 }
 
@@ -2528,7 +2665,7 @@
 	struct buffer_head *p = bh;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	pc->bh = bh;
@@ -2543,11 +2680,11 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
@@ -2558,7 +2695,7 @@
 	int size = 32768;
 
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
@@ -2577,9 +2714,9 @@
 static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
 {
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	set_bit (PC_WRITING, &pc->flags);
@@ -2596,17 +2733,49 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
 }
 
 /*
+ * This is our end_request replacement function.
+ */
+static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
  *	idetape_do_request is our request handling function.	
  */
 static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -2614,35 +2783,42 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 #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: %d, errors: %d\n", rq->rq_status,
+			(unsigned int) rq->rq_dev, rq->cmd, 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: %ld\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->cmd)) {
 		/*
 		 *	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);
-		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
+		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
+			"request queue (%d)\n", drive->name, rq->cmd);
+		idetape_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
-	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		return idetape_issue_packet_command (drive, tape->failed_pc);
+	if (tape->failed_pc != NULL &&
+	    tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		return idetape_issue_packet_command(drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
-			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+					"Two DSC requests were queued\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2653,7 +2829,7 @@
 	 *	If the tape is still busy, postpone our request and service
 	 *	the other device meanwhile.
 	 */
-	status.all = GET_STAT();
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	/*
 	 * The OnStream tape drive doesn't support DSC. Assume
@@ -2662,7 +2838,7 @@
 	if (tape->onstream)
 		status.b.dsc = 1;
 	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
 	 * For the OnStream tape, check the current status of the tape
@@ -2674,7 +2850,8 @@
 	 */
 	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->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2699,7 +2876,8 @@
 			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",
+			printk(KERN_INFO "ide-tape: postponing request, "
+					"cmd %d, cur %d, max %d\n",
 				rq->cmd, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
@@ -2708,25 +2886,28 @@
 		}
 #if ONSTREAM_DEBUG
 		else if (tape->debug_level >= 4) 
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
+				tape->name, tape->postpone_cnt);
 #endif
 	}
-	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+	    !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
 			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);
+			printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+				tape->name);
 			if (rq->cmd == IDETAPE_PC_RQ2) {
-				idetape_media_access_finished (drive);
+				idetape_media_access_finished(drive);
 				return ide_stopped;
 			} else {
-				return ide_do_reset (drive);
+				return ide_do_reset(drive);
 			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request (drive);
+		idetape_postpone_request(drive);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
@@ -2743,8 +2924,8 @@
 				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2760,39 +2941,41 @@
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			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);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->cmd = IDETAPE_WRITE_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: detected "
+					"aborted read rq\n", tape->name);
 #endif
 			rq->cmd = IDETAPE_READ_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished (drive);
+			idetape_media_access_finished(drive);
 			return ide_stopped;
 		default:
-			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: bug in "
+				"IDETAPE_RQ_CMD macro\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 	}
-	return idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command(drive, pc);
 }
 
 /*
@@ -2826,11 +3009,11 @@
 	int pages = tape->pages_per_stage;
 	char *b_data;
 
-	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+	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);
+	bh = stage->bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
 	if (bh == NULL)
 		goto abort;
 	bh->b_reqnext = NULL;
@@ -2840,7 +3023,7 @@
 		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);
+	set_bit(BH_Lock, &bh->b_state);
 
 	while (--pages) {
 		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
@@ -2861,15 +3044,15 @@
 			continue;
 		}
 		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		if ((bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL)) == NULL) {
+			free_page((unsigned long) b_data);
 			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);
+		set_bit(BH_Lock, &bh->b_state);
 		prev_bh->b_reqnext = bh;
 	}
 	bh->b_size -= tape->excess_bh_size;
@@ -2879,7 +3062,7 @@
 		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
 	return stage;
 abort:
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return NULL;
 }
 
@@ -2889,7 +3072,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->nr_stages >= tape->max_stages)
@@ -2898,7 +3081,7 @@
 		tape->cache_stage = NULL;
 		return cache_stage;
 	}
-	return __idetape_kmalloc_stage (tape, 0, 0);
+	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
@@ -2909,12 +3092,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			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(bh->b_size - atomic_read(&bh->b_count), n);
+		copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
 		n -= count;
 		atomic_add(count, &bh->b_count);
 		buf += count;
@@ -2935,12 +3119,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (tape->b_count, n);
-		copy_to_user (buf, tape->b_data, count);
+		count = IDE_MIN(tape->b_count, n);
+		copy_to_user(buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2960,9 +3145,9 @@
 	struct buffer_head *bh = tape->merge_stage->bh;
 	
 	tape->bh = bh;
-	if (tape->chrdev_direction == idetape_direction_write)
+	if (tape->chrdev_direction == idetape_direction_write) {
 		atomic_set(&bh->b_count, 0);
-	else {
+	} else {
 		tape->b_data = bh->b_data;
 		tape->b_count = atomic_read(&bh->b_count);
 	}
@@ -2973,9 +3158,12 @@
 	struct buffer_head *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->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;
 	idetape_init_merge_stage (tape);
 }
 
@@ -2989,10 +3177,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	spin_lock_irqsave(&tape->spinlock, flags);
-	stage->next=NULL;
+	stage->next = NULL;
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
 	else
@@ -3058,10 +3246,13 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	} 
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
-	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
+	}
+	/* shouldn't this be htonl ?? */
+	aux->filemark_cnt = ntohl(tape->filemark_cnt);
+	/* shouldn't this be htonl ?? */
+	aux->phys_fm = ntohl(0xffffffff);
+	/* shouldn't this be htonl ?? */
+	aux->last_mark_addr = ntohl(tape->last_mark_addr);
 }
 
 /*
@@ -3078,7 +3269,8 @@
 
 #if IDETAPE_DEBUG_BUGS
 	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
-		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to sleep on "
+			"non-valid request\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3086,7 +3278,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3098,35 +3290,39 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: BOP - %s\n",
+				result->bop ? "Yes":"No");
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: EOP - %s\n",
+				result->eop ? "Yes":"No");
 #endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
-			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_INFO "ide-tape: Block location is "
+				"unknown to the tape\n");
+			clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_INFO "ide-tape: Block Location - %u\n", ntohl (result->first_block));
+				printk(KERN_INFO "ide-tape: Block Location "
+					"- %u\n", ntohl(result->first_block));
 #endif /* IDETAPE_DEBUG_LOG */
 			tape->partition = result->partition;
-			tape->first_frame_position = ntohl (result->first_block);
-			tape->last_frame_position = ntohl (result->last_block);
+			tape->first_frame_position = ntohl(result->first_block);
+			tape->last_frame_position = ntohl(result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
-			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (1, HWGROUP (drive));
+			set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 1);
 		}
 	} else {
-		idetape_end_request (0, HWGROUP (drive));
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
@@ -3143,12 +3339,12 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3165,8 +3361,8 @@
  *	ide_do_drive_cmd from ide.c
  *	cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
  *
- *	We add a special packet command request to the tail of the request queue,
- *	and wait for it to be serviced.
+ *	We add a special packet command request to the tail of the request
+ *	queue, and wait for it to be serviced.
  *
  *	This is not to be called from within the request handling part
  *	of the driver ! We allocate here data in the stack, and it is valid
@@ -3183,17 +3379,17 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDETAPE_PC_RQ1;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
 	if (tape->onstream) {
@@ -3201,7 +3397,7 @@
 		if (cmd == !IDETAPE_LU_LOAD_MASK)
 			pc->c[4] = 4;
 	}
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3219,13 +3415,14 @@
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
 			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
 		}
-		if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
+		if (!(tape->sense_key == 2 && tape->asc == 4 &&
+		    (tape->ascq == 1 || tape->ascq == 8)))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
   		schedule_timeout(HZ / 10);
@@ -3241,9 +3438,13 @@
 	rc = __idetape_queue_pc_tail(drive, pc);
 	if (rc)
 		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
-                          because retension takes approx. 8:20 with Onstream 30GB tape */
+	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
+		/* AJN-4: Changed from 5 to 10 minutes;
+		 * because retension takes approx.
+		 * 8:20 with Onstream 30GB tape
+		 */
+		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
+	}
 	return rc;
 }
 
@@ -3261,7 +3462,7 @@
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
 	pc->callback = &idetape_read_position_callback;
@@ -3275,42 +3476,27 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-#ifdef NO_LONGER_REQUIRED
-	idetape_flush_tape_buffers(drive);
-#endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc))
+	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
-#ifdef NO_LONGER_REQUIRED
-	if (tape->onstream) {
-		if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
-		    (position != tape->last_frame_position + tape->blocks_in_buffer)) {
-			if (tape->blocks_in_buffer == 0) {
-				printk("ide-tape: %s: correcting read position %d, %d, %d\n", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer);
-				position = tape->last_frame_position;
-				tape->first_frame_position = position;
-			}
-		}
-	}
-#endif
 	return position;
 }
 
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
                 /*
@@ -3319,7 +3505,7 @@
                  * data in the drive to this new position!
                  */
 		pc->c[9] = skip << 7;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3345,11 +3531,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		return 0;
+	cnt = tape->merge_stage_size / tape->tape_block_size;
+	if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+		++cnt;		/* Filemarks count as 1 sector */
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3357,13 +3547,18 @@
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
-	if (idetape_pipeline_active (tape))
+	if (idetape_pipeline_active(tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
-	cnt = tape->nr_stages - tape->nr_pending_stages;
-	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+	while (tape->first_stage != NULL) {
+		struct request *rq_ptr = &tape->first_stage->rq;
+
+		cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; 
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			++cnt;
+		idetape_remove_stage_head(drive);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3378,7 +3573,7 @@
  *	of the request queue and wait for their completion.
  *	
  */
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int retval;
@@ -3387,13 +3582,13 @@
 	if (tape->chrdev_direction == idetape_direction_read)
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return (retval);
 
-	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive, &pc));
+	idetape_create_read_position_cmd(&pc);
+	return (idetape_queue_pc_tail(drive, &pc));
 }
 
 static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
@@ -3407,11 +3602,13 @@
 		position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
+			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n",
+				position, cnt);
 #endif
 		seek = position > cnt ? position - cnt : 0;
 		if (idetape_position_tape(drive, seek, 0, 0)) {
-			printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: position_tape "
+				"failed in discard_pipeline()\n", tape->name);
 			return;
 		}
 	}
@@ -3421,7 +3618,7 @@
 {
 	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
@@ -3437,29 +3634,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+		printk(KERN_INFO "ide-tape: %s: cmd=%d\n", __FUNCTION__, cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (idetape_pipeline_active (tape)) {
-		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+		printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+			__FUNCTION__);
 		return (0);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.bh = bh;
 	rq.cmd = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
 		tape->postpone_cnt = 600;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
 		return 0;
 
 	if (tape->merge_stage)
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 	if (rq.errors == IDETAPE_ERROR_GENERAL)
 		return -EIO;
 	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
@@ -3517,7 +3715,8 @@
 	idetape_update_stats(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
+		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n",
+			tape->name, tape->cur_frames);
 #endif
 }
 
@@ -3578,12 +3777,12 @@
 
 	if (tape->next_stage == NULL)
 		return;
-	if (!idetape_pipeline_active (tape)) {
+	if (!idetape_pipeline_active(tape)) {
 		if (tape->onstream_write_error)
 			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-		idetape_active_next_stage (drive);
-		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+		idetape_active_next_stage(drive);
+		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 	}
 }
 
@@ -3599,41 +3798,41 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
-	idetape_init_pc (pc);
-	set_bit (PC_WRITING, &pc->flags);
+	idetape_init_pc(pc);
+	set_bit(PC_WRITING, &pc->flags);
 	pc->c[0] = IDETAPE_MODE_SELECT_CMD;
 	pc->c[1] = 0x10;
-	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
+	put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count,u8 cmd)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_SPACE_CMD;
-	put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3662,48 +3861,70 @@
 		return 1;
 	}
 	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"read error\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"format_id %u\n", tape->name,
+			tape->first_frame_position, ntohl(aux->format_id));
 		return 0;
 	}
 	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"incorrect application signature\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame "
+			"type %x\n", tape->name,
+			tape->first_frame_position, aux->frame_type);
 		return 0;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"partition num %d\n", tape->name,
+				tape->first_frame_position, par->partition_num);
 			return 0;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"partition version %d\n", tape->name,
+			tape->first_frame_position, par->par_desc_ver);
 		return 0;
 	}
 	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n",
+			tape->name, tape->first_frame_position,
+			ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr,
+			ntohl(aux->logical_blk_num));
 		return 0;
 	}
 	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"seq != logical\n", tape->name,
+			tape->first_frame_position);
 		return 0;
 	}
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+	if (logical_blk_num != -1 &&
+	     ntohl(aux->logical_blk_num) != logical_blk_num) {
 		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"logical_blk_num %u (expected %d)\n",
+				tape->name, tape->first_frame_position,
+				ntohl(aux->logical_blk_num), logical_blk_num);
 		return 0;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3746,7 +3967,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
      	/*
@@ -3755,31 +3976,32 @@
 	 */
 	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		if (idetape_pipeline_active (tape)) {
+		if (idetape_pipeline_active(tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
 			spin_unlock_irqrestore(&tape->spinlock, flags);
-			idetape_insert_pipeline_into_queue (drive);
-			if (idetape_pipeline_active (tape))
+			idetape_insert_pipeline_into_queue(drive);
+			if (idetape_pipeline_active(tape))
 				continue;
 			/*
 			 *	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->bh);
 		}
 	}
 	rq = &new_stage->rq;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = IDETAPE_WRITE_RQ;
-	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
+	/* Doesn't actually matter - We always assume sequential access */
+	rq->sector = tape->first_frame_position;
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
 	idetape_switch_buffers (tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive, new_stage);
+	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3813,10 +4035,11 @@
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
-	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3831,7 +4054,7 @@
 	unsigned long flags;
 
 	while (tape->next_stage || idetape_pipeline_active(tape)) {
-		idetape_insert_pipeline_into_queue (drive);
+		idetape_insert_pipeline_into_queue(drive);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active(tape))
 			idetape_wait_for_request(drive, tape->active_data_request);
@@ -3847,11 +4070,12 @@
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to empty write "
+			"pipeline, but we are not writing.\n");
 		return;
 	}
 	if (tape->merge_stage_size > tape->stage_size) {
-		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
 		tape->merge_stage_size = tape->stage_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3878,15 +4102,15 @@
 				bh = bh->b_reqnext;
 			}
 		}
-		(void) idetape_add_chrdev_write_request (drive, blocks);
+		(void) idetape_add_chrdev_write_request(drive, blocks);
 		tape->merge_stage_size = 0;
 	}
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 
 	/*
@@ -3897,10 +4121,14 @@
 	 */
 	tape->max_stages = tape->min_pipeline;
 #if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
-		printk (KERN_ERR "ide-tape: ide-tape pipeline bug, "
-		"first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n",
-		tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
+	if (tape->first_stage != NULL ||
+	    tape->next_stage != NULL ||
+	    tape->last_stage != NULL ||
+	    tape->nr_stages != 0) {
+		printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+			"first_stage %p, next_stage %p, last_stage %p, "
+			"nr_stages %d\n", tape->first_stage,
+			tape->next_stage, tape->last_stage, tape->nr_stages);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 }
@@ -3928,14 +4156,16 @@
 	int bytes_read;
 	int blocks = tape->capabilities.ctl;
 
-	if (tape->chrdev_direction != idetape_direction_read) {		/* Initialize read operation */
+	/* Initialize read operation */
+	if (tape->chrdev_direction != idetape_direction_read) {
 		if (tape->chrdev_direction == idetape_direction_write) {
-			idetape_empty_write_pipeline (drive);
-			idetape_flush_tape_buffers (drive);
+			idetape_empty_write_pipeline(drive);
+			idetape_flush_tape_buffers(drive);
 		}
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size "
+				"should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3949,9 +4179,9 @@
 		 *	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->bh);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,18 +4189,19 @@
 	}
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.cmd = 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) {
-		new_stage = idetape_kmalloc_stage (tape);
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+	    tape->nr_stages < max_stages) {
+		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
-			idetape_add_stage_tail (drive, new_stage);
+			idetape_add_stage_tail(drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage = idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage(tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3979,11 +4210,11 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
@@ -4000,7 +4231,9 @@
 	 */
 	while (1) {
 		if (cnt++ > 1000) {   /* AJN: was 100 */
-			printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: couldn't find "
+				"logical block %d, aborting\n",
+				tape->name, logical_blk_num);
 			return 0;
 		}
 		idetape_initiate_read(drive, max_stages);
@@ -4012,21 +4245,31 @@
 #endif
 				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				position = idetape_read_position(drive);
-				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
+				printk(KERN_INFO "ide-tape: %s: blank block "
+					"detected at %d\n", tape->name,
+					position);
 				if (position >= 3000 && position < 3080)
-					position += 32;  /* Why is this check and number ??? MM */
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+					/* Why is this check and number ??? MM */
+					position += 32;
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				else
 					/*
-					 * compensate for write errors that generally skip 80 frames,
-					 * expect around 20 read errors in a row...
+					 * compensate for write errors that
+					 * generally skip 80 frames, expect
+					 * around 20 read errors in a row...
 					 */
 					position += 60;
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
-				if (position == 3000)  /* seems to be needed to correctly position at block 3000 MM */
+
+				/* seems to be needed to correctly position
+				 * at block 3000 MM
+				 */
+				if (position == 3000)
 					idetape_position_tape(drive, 0, 0, 0);
 				idetape_position_tape(drive, position, 0, 0);
 				cnt += 40;
@@ -4069,10 +4312,17 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+		printk(KERN_INFO "ide-tape: Reached %s, %d blocks\n",
+			__FUNCTION__, blocks);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
+	 * If we are at a filemark, return a read length of 0
+	 */
+	if (test_bit(IDETAPE_FILEMARK, &tape->flags))
+		return 0;
+
+	/*
 	 * Wait for the next logical block to be available at the head
 	 * of the pipeline
 	 */
@@ -4083,38 +4333,35 @@
 		}
 		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->bh);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
+	if (tape->onstream && !tape->raw &&
+	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
+				tape->name);
 #endif
 		return 0;
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit (IDETAPE_FILEMARK, &tape->flags);
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
-		calculate_speeds(drive);
-	} else {
-		idetape_switch_buffers (tape, tape->first_stage);
+	else {
+		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
+				printk(KERN_INFO "ide-tape: error detected, "
+					"bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			set_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4126,9 +4373,10 @@
 		calculate_speeds(drive);
 	}
 #if IDETAPE_DEBUG_BUGS
-	if (bytes_read > blocks*tape->tape_block_size) {
-		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-		bytes_read=blocks*tape->tape_block_size;
+	if (bytes_read > blocks * tape->tape_block_size) {
+		printk(KERN_ERR "ide-tape: bug: trying to return more "
+			"bytes than requested\n");
+		bytes_read = blocks * tape->tape_block_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	return (bytes_read);
@@ -4142,16 +4390,16 @@
 	
 	while (bcount) {
 		bh = tape->merge_stage->bh;
-		count = IDE_MIN (tape->stage_size, bcount);
+		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));
+			memset(bh->b_data, 0, atomic_read(&bh->b_count));
 			count -= atomic_read(&bh->b_count);
 			bh = bh->b_reqnext;
 		}
-		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->bh);
 	}
 }
 
@@ -4162,7 +4410,7 @@
 	struct request *rq;
 	int size = 0;
 
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	stage = tape->first_stage;
 	while (stage != NULL) {
 		rq = &stage->rq;
@@ -4187,16 +4435,16 @@
 	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */	
 	
-	idetape_create_rewind_cmd (drive, &pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_rewind_cmd(drive, &pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 
-	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_read_position_cmd(&pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 	tape->logical_blk_num = 0;
@@ -4218,7 +4466,7 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	switch (cmd) {
 		case 0x0340:
@@ -4248,7 +4496,7 @@
 {
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n");
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 	return 0;
 }
@@ -4257,7 +4505,7 @@
 {
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n");
+        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 }
 
@@ -4268,7 +4516,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	if (tape != NULL)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
 /*
@@ -4291,7 +4539,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_bwd\n", tape->name);
 		return -EIO;
 	}
 	while (cnt != mt_count) {
@@ -4300,16 +4549,20 @@
 			return -EIO;
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
+			printk(KERN_INFO "ide-tape: positioning to last "
+			"mark at %d\n", last_mark_addr);
 #endif
 		idetape_position_tape(drive, last_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, last_mark_addr);
 			return -EIO;
 		}
 	}
@@ -4334,12 +4587,14 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 	while (1) {
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
@@ -4347,19 +4602,20 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (cnt == mt_count)
 			break;
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4377,7 +4633,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 
@@ -4390,22 +4647,27 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
 			if (tape->first_mark_addr == -1) {
-				printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: reverting to "
+					"slow filemark space\n", tape->name);
 				return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
 			}
 			idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
 			if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-				printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: couldn't get "
+					"logical blk num in %s\n",							__FUNCTION__, tape->name);
 				return -EIO;
 			}
 			if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr);
+				printk(KERN_INFO "ide-tape: %s: expected to "
+					"find filemark at %d\n",
+					tape->name, tape->first_mark_addr);
 				return -EIO;
 			}
 		} else {
@@ -4418,7 +4680,8 @@
 	while (cnt != mt_count) {
 		next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
 		if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
-			printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: reverting to slow "
+				"filemark space\n", tape->name);
 			return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
 #if ONSTREAM_DEBUG
 		} else if (tape->debug_level >= 2) {
@@ -4428,17 +4691,20 @@
 		idetape_position_tape(drive, next_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, next_mark_addr);
 			return -EIO;
 		}
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4478,6 +4744,14 @@
 		tape->restart_speed_control_req = 1;
 		return retval;
 	}
+ 
+	if (mt_count == 0)
+		return 0;
+	if (MTBSF == mt_op || MTBSFM == mt_op) {
+		if (!tape->capabilities.sprev)
+			return -EIO;
+		mt_count = - mt_count;
+	}
 
 	if (tape->chrdev_direction == idetape_direction_read) {
 		/*
@@ -4485,28 +4759,36 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+			++count;
 		while (tape->first_stage != NULL) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
-			idetape_remove_stage_head (drive);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage == tape->active_stage) {
+				/*
+				 *	We have reached the active stage in the read pipeline.
+				 *	There is no point in allowing the drive to continue
+				 *	reading any farther, so we stop the pipeline.
+				 *
+				 *	This section should be moved to a separate subroutine,
+				 *	because a similar function is performed in
+				 *	__idetape_discard_read_pipeline(), for example.
+				 */
+				tape->next_stage = NULL;
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+				idetape_wait_first_stage(drive);
+				tape->next_stage = tape->first_stage->next;
+			} else
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+				++count;
+			idetape_remove_stage_head(drive);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4515,27 +4797,20 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
-			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
-		case MTFSFM:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
-			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTBSF, 1));
 		case MTBSF:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
+		case MTFSFM:
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not "
+				"supported\n", mt_op);
 			return (-EIO);
 	}
 }
@@ -4562,7 +4837,7 @@
 				    size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
@@ -4571,17 +4846,21 @@
 		return -ENXIO;
 	}
 	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
+		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size "
+			"(%Zd used)\n", tape->name,
+			tape->tape_block_size, count);
 		return -EINVAL;
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+		printk (KERN_INFO "ide-tape: Reached %s, count %Zd\n",
+			__FUNCTION__, count);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction != idetape_direction_read) {
-		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
-			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+		if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size &&
+			    (count % tape->tape_block_size) == 0)
 				tape->user_bs_factor = count / tape->tape_block_size;
 	}
 	if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
@@ -4589,42 +4868,45 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = IDE_MIN (tape->merge_stage_size, count);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		actually_read = IDE_MIN(tape->merge_stage_size, count);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
 	}
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read=idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = IDE_MIN (count, bytes_read);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
+		temp = IDE_MIN(count, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
-	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
+	if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: spacing over "
+				"filemark\n", tape->name);
 #endif
 		idetape_space_over_filemarks (drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
-					tape->name, tape->logical_blk_num);
+	if (tape->onstream && !actually_read &&
+	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
+			"logical block number %d, skipping\n",
+			tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
@@ -4649,21 +4931,25 @@
 	position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+		printk(KERN_INFO "ide-tape: current position (2) %d, "
+			"lblk %d\n", position, tape->logical_blk_num);
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
+		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)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		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);
 		return;
 	}
 	aux = stage->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+		printk(KERN_INFO "ide-tape: %s: expected to find marker "
+			"at addr %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
@@ -4673,13 +4959,14 @@
 #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)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		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);
 		return;
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	idetape_flush_tape_buffers (drive);
 	idetape_position_tape(drive, position, 0, 0);
 	return;
@@ -4702,18 +4989,20 @@
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
 #endif
-	if (rc != 0) 
-		return;	/* don't write fillers if we cannot position the tape. */
+	if (rc != 0)
+		/* don't write fillers if we cannot position the tape. */
+		return;
 
 	strcpy(stage->bh->b_data, "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: "
+				"couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
@@ -4741,14 +5030,14 @@
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(stage->bh->b_data, &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->bh)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 }
 
 static void idetape_write_header (ide_drive_t *drive, int locate_eod)
@@ -4767,7 +5056,9 @@
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+			printk(KERN_INFO "ide-tape: %s: locating back to "
+				"eod frame addr %d\n", tape->name,
+				tape->eod_frame_addr);
 #endif
 		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 	}
@@ -4777,7 +5068,7 @@
 				     size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t retval, actually_written = 0;
 	int position;
@@ -4794,13 +5085,14 @@
 
 	if (tape->onstream) {
 		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
-					tape->name, tape->tape_block_size, count);
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: "
+				"use %d bytes as block size (%Zd used)\n",
+				tape->name, tape->tape_block_size, count);
 			return -EINVAL;
 		}
 		/*
-		 * Check if we reach the end of the tape. Just assume the whole pipeline
-		 * is filled with write requests!
+		 * Check if we reach the end of the tape. Just assume the whole
+		 * pipeline is filled with write requests!
 		 */
 		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
 #if ONSTREAM_DEBUG
@@ -4812,19 +5104,20 @@
 		}
 	}
 
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+	/* Initialize write operation */
+	if (tape->chrdev_direction != idetape_direction_write) {
 		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_write;
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
@@ -4860,9 +5153,9 @@
 		 *	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->bh);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -4879,35 +5172,35 @@
 	if (tape->merge_stage_size) {
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
-			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		actually_written = IDE_MIN(tape->stage_size - tape->merge_stage_size, count);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
 				return (retval);
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
 		buf += tape->stage_size;
 		count -= tape->stage_size;
-		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 		actually_written += tape->stage_size;
 		if (retval <= 0)
 			return (retval);
 	}
 	if (count) {
-		actually_written+=count;
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		actually_written += count;
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
 		tape->merge_stage_size += count;
 	}
 	return (actually_written);
@@ -4920,19 +5213,20 @@
 	idetape_pc_t pc;
 
 	if (!tape->onstream) {
-		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive, &pc)) {
-			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		/* Write a filemark */
+		idetape_create_write_filemark_cmd(drive, &pc, 1);
+		if (idetape_queue_pc_tail(drive, &pc)) {
+			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
 	} else if (!tape->raw) {
 		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 		if (tape->merge_stage != NULL) {
 			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros (drive, tape->stage_size);
+			idetape_pad_zeros(drive, tape->stage_size);
 			tape->logical_blk_num++;
-			__idetape_kfree_stage (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 		}
 		if (tape->filemark_cnt)
@@ -4950,11 +5244,11 @@
 
 	if (!tape->onstream || tape->raw)
 		return;
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
 		tape->eod_frame_addr = idetape_read_position(drive);
 		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros (drive, tape->stage_size);
+		idetape_pad_zeros(drive, tape->stage_size);
 		__idetape_kfree_stage (tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
@@ -4989,7 +5283,9 @@
 error:
 	tape->speed_control = speed_control;
 	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries);
+	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
+		"(at %d), %d retries\n", tape->name, logical_blk_num,
+		tape->logical_blk_num, retries);
 	return -EIO;
 ok:
 	tape->speed_control = speed_control;
@@ -5068,7 +5364,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+		printk(KERN_INFO "ide-tape: Handling MTIOCTOP "
+			"ioctl: mt_op=%d, mt_count=%d\n", mt_op, mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
@@ -5080,41 +5377,41 @@
 		case MTBSFM:
 			if (!mt_count)
 				return (0);
-			return (idetape_space_over_filemarks (drive,mt_op,mt_count));
+			return (idetape_space_over_filemarks(drive,mt_op,mt_count));
 		default:
 			break;
 	}
 	switch (mt_op) {
 		case MTWEOF:
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 			for (i = 0; i < mt_count; i++) {
 				retval = idetape_write_filemark(drive);
 				if (retval) return retval;
 			}
 			return (0);
 		case MTREW:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
 				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTNOP:
-			idetape_discard_read_pipeline (drive, 0);
-			return (idetape_flush_tape_buffers (drive));
+			idetape_discard_read_pipeline(drive, 0);
+			return (idetape_flush_tape_buffers(drive));
 		case MTRETEN:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -5128,8 +5425,8 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
 				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
@@ -5137,7 +5434,7 @@
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
-				idetape_flush_tape_buffers (drive);
+				idetape_flush_tape_buffers(drive);
 				idetape_write_header(drive, 0);
 				/*
 				 * write filler frames to the unused frames...
@@ -5145,13 +5442,13 @@
 				 */
 				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
 				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers (drive);
-				(void) idetape_rewind_tape (drive);
+				idetape_flush_tape_buffers(drive);
+				(void) idetape_rewind_tape(drive);
 				return 0;
 			}
-			(void) idetape_rewind_tape (drive);
-			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive, &pc));
+			(void) idetape_rewind_tape(drive);
+			idetape_create_erase_cmd(&pc);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -5164,21 +5461,21 @@
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
 				tape->user_bs_factor = mt_count / tape->tape_block_size;
-				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+				clear_bit(IDETAPE_DETECT_BS, &tape->flags);
 			} else
-				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
 			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline (drive, 0);
-				return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+				idetape_discard_read_pipeline(drive, 0);
+				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 			}
 			return idetape_seek_logical_blk(drive, mt_count);
 		case MTSETPART:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (tape->onstream)
 				return -EIO;
-			return (idetape_position_tape (drive, 0, mt_count, 0));
+			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
 			if (tape->onstream) {
@@ -5187,26 +5484,26 @@
 				if (mt_op == MTFSR)
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
 				else {
-					idetape_discard_read_pipeline (drive, 0);
+					idetape_discard_read_pipeline(drive, 0);
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
 				}
 			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
@@ -5236,7 +5533,7 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -5245,30 +5542,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->restart_speed_control_req = 1;
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
+		idetape_empty_write_pipeline(drive);
+		idetape_flush_tape_buffers(drive);
 	}
 	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
 		if ((position = idetape_read_position(drive)) < 0)
 			return -EIO;
 	}
 	switch (cmd) {
 		case MTIOCTOP:
-			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+			if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
 				return -EFAULT;
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+			return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
 		case MTIOCGET:
-			memset (&mtget, 0, sizeof (struct mtget));
+			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
-			if (!tape->onstream || tape->raw)
+			if (!tape->onstream || tape->raw) {
 				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-			else {
+			} else {
 				if (!idetape_get_logical_blk(drive, -1, 10, 0))
 					mtget.mt_blkno = -1;
 				else
@@ -5297,8 +5594,8 @@
 			return 0;
 		default:
 			if (tape->chrdev_direction == idetape_direction_read)
-				idetape_discard_read_pipeline (drive, 1);
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+				idetape_discard_read_pipeline(drive, 1);
+			return (idetape_blkdev_ioctl(drive,inode,file,cmd,arg));
 	}
 }
 
@@ -5318,7 +5615,7 @@
 	tape->wrt_pass_cntr = 0;
 	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage (tape, 0, 0);
+	stage = __idetape_kmalloc_stage(tape, 0, 0);
 	if (stage == NULL)
 		return 0;
 #if ONSTREAM_DEBUG
@@ -5326,16 +5623,17 @@
 		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)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		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;
 	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);
-		__idetape_kfree_stage (stage);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
@@ -5354,17 +5652,21 @@
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
-					 tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version "
+				"%d detected (current 3)\n",
+				 tape->name, tape->linux_media_version);
 	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
+		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
+			"(%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
 	}
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+		printk(KERN_INFO "ide-tape: %s: detected write pass "
+			"counter %d, eod frame addr %d\n", tape->name,
+			tape->wrt_pass_cntr, tape->eod_frame_addr);
 #endif
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return 1;
 }
 
@@ -5385,7 +5687,8 @@
 	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
-	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
+	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n",
+		tape->name);
 	return 0;
 ok:
 	if (position < OS_DATA_STARTFRAME1)
@@ -5403,23 +5706,23 @@
 	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");
 #endif /* IDETAPE_DEBUG_LOG */
 	
-	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+	if ((drive = get_drive_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	if (!tape->onstream) {	
 		idetape_read_position(drive);
-		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
-			(void) idetape_rewind_tape (drive);
+		if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+			(void) idetape_rewind_tape(drive);
 	} else {
 		if (minor & 64) {
 			tape->tape_block_size = tape->stage_size = 32768 + 512;
@@ -5436,14 +5739,16 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive, &pc)) {
+			if (!idetape_queue_pc_tail(drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -5458,22 +5763,22 @@
 
 static void idetape_write_release (struct inode *inode)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	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);
+	idetape_empty_write_pipeline(drive);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
-		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
 	idetape_write_eod(drive);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 	idetape_write_header(drive, minor >= 128);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 
 	return;
 }
@@ -5483,16 +5788,16 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	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);
 
 	lock_kernel();
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
@@ -5500,25 +5805,26 @@
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 		else
-			idetape_wait_for_pipeline (drive);
+			idetape_wait_for_pipeline(drive);
 	}
 	if (tape->cache_stage != NULL) {
-		__idetape_kfree_stage (tape->cache_stage);
+		__idetape_kfree_stage(tape->cache_stage);
 		tape->cache_stage = NULL;
 	}
 	if (minor < 128)
-		(void) idetape_rewind_tape (drive);
+		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive, &pc))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
+				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
-	clear_bit (IDETAPE_BUSY, &tape->flags);
+	clear_bit(IDETAPE_BUSY, &tape->flags);
 	unlock_kernel();
 	return 0;
 }
@@ -5532,120 +5838,121 @@
  *
  *	0 	If this tape driver is not currently supported by us.
  */
-static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+static int idetape_identify_device (ide_drive_t *drive)
 {
 	struct idetape_id_gcw gcw;
+	struct hd_driveid *id = drive->id;
 #if IDETAPE_DEBUG_INFO
 	unsigned short mask,i;
 #endif /* IDETAPE_DEBUG_INFO */
 
-	if (!id)
-		return 0;
+	if(drive->id_read == 0)
+		return 1;
 
 	*((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-	printk (KERN_INFO "ide-tape: Protocol Type: ");
+	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
+	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
-	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Command Packet Size: ");
+	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
-	}
-	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
+	}
+	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
-	printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+	printk("\n");
+	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk("%d ns\n",id->eide_dma_min);
 
-		printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk("%d ns\n",id->eide_dma_time);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio);
+			printk("%d ns\n",id->eide_pio);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
-		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_INFO */
 
 	/* Check that we can support this device */
 
 	if (gcw.protocol !=2 )
-		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 1)
-		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+		printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
 	else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
 		if (gcw.packet_size == 1)
-			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+			printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
 	} else
 		return 1;
 	return 0;
@@ -5672,8 +5979,8 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
 
@@ -5694,8 +6001,8 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
 
@@ -5711,9 +6018,9 @@
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
@@ -5733,8 +6040,8 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
 	/*
@@ -5756,8 +6063,8 @@
 	idetape_inquiry_result_t *inquiry;
 	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
 	inquiry = (idetape_inquiry_result_t *) pc.buffer;
@@ -5809,9 +6116,9 @@
 	idetape_mode_parameter_header_t *header;
 	onstream_tape_paramtr_page_t *prm;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -5819,7 +6126,7 @@
 
         tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
         if (debug) {
-	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
                drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
         }
 
@@ -5838,20 +6145,22 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
 	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
-		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
-		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
+		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+		tape->tape_block_size = 512;
+		tape->capabilities.ctl = 52;
+		tape->capabilities.speed = 450;
+		tape->capabilities.buffer_size = 6 * 52;
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
-	capabilities->max_speed = ntohs (capabilities->max_speed);
-	capabilities->ctl = ntohs (capabilities->ctl);
-	capabilities->speed = ntohs (capabilities->speed);
-	capabilities->buffer_size = ntohs (capabilities->buffer_size);
+	capabilities->max_speed = ntohs(capabilities->max_speed);
+	capabilities->ctl = ntohs(capabilities->ctl);
+	capabilities->speed = ntohs(capabilities->speed);
+	capabilities->buffer_size = ntohs(capabilities->buffer_size);
 
 	if (!capabilities->speed) {
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
@@ -5861,6 +6170,10 @@
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
 		capabilities->max_speed = 650;
 	}
+	if (!capabilities->ctl) {
+		printk(KERN_INFO "ide-tape: %s: overriding capabilities->ctl (assuming 26KB)\n", drive->name);
+		capabilities->ctl = 52;
+	}
 
 	tape->capabilities = *capabilities;		/* Save us a copy */
 	if (capabilities->blk512)
@@ -5871,33 +6184,33 @@
 		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
-	printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-	printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+	printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+	printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+	printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+	printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+	printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
 	
-	printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-	printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
-	printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+	printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+	printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+	printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+	printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
+	printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
@@ -5913,22 +6226,19 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_parameter_block_descriptor_t *block_descrp;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
-		if (tape->tape_block_size == 0) {
-			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
-			tape->tape_block_size =  32768;
-		}
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
 	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -5937,9 +6247,9 @@
  *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
  */
 	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
-	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
 	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
 	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
 	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
@@ -5984,29 +6294,24 @@
 	int stage_size;
 	struct sysinfo si;
 
-	memset (tape, 0, sizeof (idetape_tape_t));
+	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
-	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	/* An ATAPI device ignores DRDY */
+	drive->ready_stat = 0;
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
-	drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
-		/*
-		 * These two ide-pci host adapters appear to need DSC overlap disabled.
-		 * This probably needs further analysis.
-		 */
-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
-			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-		    	drive->dsc_overlap = 0;
-		}
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+			tape->name);
+		drive->dsc_overlap = 0;
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	tape->drive = drive;
 	tape->minor = minor;
-	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
+	tape->name[0] = 'h';
+	tape->name[1] = 't';
+	tape->name[2] = '0' + minor;
 	tape->chrdev_direction = idetape_direction_none;
 	tape->pc = tape->pc_stack;
 	tape->max_insert_speed = 10000;
@@ -6020,6 +6325,10 @@
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
 	idetape_get_blocksize_from_block_descriptor(drive);
+	if (tape->tape_block_size == 0) {
+		printk(KERN_WARNING "ide-tape: Zero block size, using 512\n");
+		tape->tape_block_size = 512;
+	}
 	if (tape->onstream) {
 		idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
 		idetape_configure_onstream(drive);
@@ -6044,7 +6353,7 @@
 	 *	Select the "best" DSC read/write polling frequency
 	 *	and pipeline size.
 	 */
-	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
+	speed = IDE_MAX(tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
@@ -6052,10 +6361,13 @@
 	 * 	Limit memory use for pipeline to 10% of physical memory
 	 */
 	si_meminfo(&si);
-	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
-	tape->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_MIN(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+	if (tape->max_stages == 0)
+		tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
 
 	t1 = (tape->stage_size * HZ) / (speed * 1000);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
@@ -6070,11 +6382,15 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
-	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
-		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
+	tape->best_dsc_rw_frequency = IDE_MAX(IDE_MIN(t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+		"%dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed,
+		(tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024,
+		tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ,
+		drive->using_dma ? ", DMA":"");
 
 	idetape_add_settings(drive);
 }
@@ -6085,24 +6401,24 @@
 	int minor = tape->minor;
 	unsigned long flags;
 
-	save_flags (flags);	/* all CPUs (overkill?) */
-	cli();			/* all CPUs (overkill?) */
-	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
-		restore_flags(flags);	/* all CPUs (overkill?) */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
+	    tape->first_stage != NULL || tape->merge_stage_size) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	idetape_chrdevs[minor].drive = NULL;
-	restore_flags (flags);	/* all CPUs (overkill?) */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver (drive);
+	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister (tape->de_r);
-	devfs_unregister (tape->de_n);
-	kfree (tape);
+	devfs_unregister(tape->de_r);
+	devfs_unregister(tape->de_n);
+	kfree(tape);
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
 		if (idetape_chrdevs[minor].drive != NULL)
 			return 0;
-	devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	idetape_chrdev_present = 0;
 	return 0;
 }
@@ -6132,7 +6448,8 @@
 
 #endif
 
-int idetape_reinit(ide_drive_t *drive);
+int idetape_init (void);
+int idetape_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6146,9 +6463,13 @@
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idetape_blkdev_ioctl,
 	open:			idetape_blkdev_open,
 	release:		idetape_blkdev_release,
@@ -6156,13 +6477,14 @@
 	revalidate:		NULL,
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
+	special:		NULL,
 	proc:			idetape_proc,
-	reinit:			idetape_reinit,
+	init:			idetape_init,
+	attach:			idetape_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idetape_init (void);
 static ide_module_t idetape_module = {
 	IDE_DRIVER_MODULE,
 	idetape_init,
@@ -6182,90 +6504,62 @@
 	release:	idetape_chrdev_release,
 };
 
-int idetape_reinit (ide_drive_t *drive)
+int idetape_attach (ide_drive_t *drive)
 {
-#if 0
 	idetape_tape_t *tape;
-	int minor, failed = 0, supported = 0;
-/* DRIVER(drive)->busy++; */
+	int minor = 0, ret = 0;
+
 	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,
+	if (idetape_identify_device(drive)) {
+		printk(KERN_ERR "ide-tape: %s: not supported by this "
+			"version of ide-tape\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	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);
+			ret = 1;
+			goto bye_game_over;
+		}
+	}
+	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);
+		ret = 1;
+		goto bye_game_over;
+	}
+	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);
+		ret = 1;
+		goto bye_game_over;
+	}
+	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,
+	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);
+	devfs_register_tape(tape->de_r);
+
+bye_game_over:
 	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
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -6278,94 +6572,120 @@
 
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
 		drive = idetape_chrdevs[minor].drive;
-		if (drive != NULL && idetape_cleanup (drive))
-		printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+		if (drive) {
+			if (idetape_cleanup(drive))
+				printk(KERN_ERR "ide-tape: %s: cleanup_module() "
+					"called while still busy\n", drive->name);
+#ifdef CONFIG_PROC_FS
+			if (drive->proc)
+				ide_remove_proc_entries(drive->proc, idetape_proc);
+#endif
+		}
 	}
+
 	ide_unregister_module(&idetape_module);
 }
 
-/*
- *	idetape_init will register the driver for each tape.
- */
 int idetape_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	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");
+	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);
+	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");
+		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");
+	    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");
+		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);
+		if (!idetape_identify_device(drive)) {
+			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-")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+				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);
+				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);
+			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);
+		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_setup(drive, tape, minor);
 		idetape_chrdevs[minor].drive = drive;
 		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+		    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,
+		    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);
+		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");
+		devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int minor = 0;
+
+	if (idetape_chrdev_present)
+		return 0;
+	idetape_chrdev_present = 1;
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+		idetape_chrdevs[minor].drive = NULL;
+	devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops);
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
+	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;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-taskfile.c linux-2.4.21-rc3/drivers/ide/ide-taskfile.c
--- linux-2.4.20/drivers/ide/ide-taskfile.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide-taskfile.c	2003-05-22 22:06:26.000000000 +0000
@@ -1,12 +1,29 @@
 /*
- * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ * linux/drivers/ide/ide-taskfile.c	Version 0.38	March 05, 2003
  *
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002	Klaus Smolin
+ *					IBM Storage Technology Division
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  The big the bad and the ugly.
  *
- * IDE_DEBUG(__LINE__);
+ *  Problems to be fixed because of BH interface or the lack therefore.
+ *
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -34,27 +51,50 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
 
+/*
+ *
+ */
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
+/*
+ * for now, taskfile requests are special :/
+ *
+ * However, upon the creation of the atapi version of packet_command
+ * data-phase ISR plus it own diagnostics and extensions for direct access
+ * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will
+ * come localized.
+ */
+inline char *task_map_rq (struct request *rq, unsigned long *flags)
+{
+	if (rq->bh)
+		return ide_map_buffer(rq, flags);
+	return rq->buffer + task_rq_offset(rq);
+}
+
+inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags)
+{
+	if (rq->bh)
+		ide_unmap_buffer(buf, flags);
+}
+
 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);
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
+EXPORT_SYMBOL(task_read_24);
+
 static void ata_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -65,381 +105,177 @@
 	}
 }
 
-#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) 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 ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte 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 = 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);
-	}
-}
-
 
-static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+void taskfile_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
-	ata_input_data(drive, buffer, wcount);
+	HWIF(drive)->ata_input_data(drive, buffer, wcount);
 	if (drive->bswap)
 		ata_bswap_data(buffer, wcount);
 }
 
-static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+EXPORT_SYMBOL(taskfile_input_data);
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
 	if (drive->bswap) {
 		ata_bswap_data(buffer, wcount);
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 		ata_bswap_data(buffer, wcount);
 	} else {
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 	}
 }
 
-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) {
-#if 0
-		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
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, 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;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
-		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
-		}
-#endif
-	} 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;
-}
+EXPORT_SYMBOL(taskfile_output_data);
 
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-	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);
-	}
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	if (drive->media == ide_disk)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, buf);
+}
 
-	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);
+EXPORT_SYMBOL(taskfile_lib_get_identify);
 
-	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)));
-	}
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
+{
+	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 0
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+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;
-
-	/*
-	 * (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);
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
 
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-	/* (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);
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG) {
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	}
+	SELECT_MASK(drive, 0);
+
+	if (drive->addressing == 1) {
+		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	hwif->OUTB(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);
+	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (task->handler != NULL) {
-#if 0
-		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) {
+		ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+		if (task->prehandler != NULL)
 			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-
-		/*
-		 * (KS) The drive command register is also mandatory.
-		 * Don't care about the out flags !
-		 */
-		OUT_BYTE(taskfile->command, 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;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
+		return ide_started;
+	}
+	/* for dma commands we down set the handler */
+#if 0
+	if (blk_fs_request(task->rq) && drive->using_dma) {
+		if (rq_data_dir(task->rq) == READ) {
+			if (hwif->ide_dma_read(drive))
+				return ide_stopped;
 		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
+			if (hwif->ide_dma_write(drive))
+				return ide_stopped;
 		}
-#endif
 	} 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 (!drive->using_dma && (task->handler == NULL))
+			return ide_stopped;
 
+		switch(taskfile->command) {
+			case WIN_WRITEDMA_ONCE:
+			case WIN_WRITEDMA:
+			case WIN_WRITEDMA_EXT:
+				hwif->ide_dma_write(drive);
+				break;
+			case WIN_READDMA_ONCE:
+			case WIN_READDMA:
+			case WIN_READDMA_EXT:
+			case WIN_IDENTIFY_DMA:
+				hwif->ide_dma_read(drive);
+				break;
+			default:
+				if (task->handler == NULL)
+					return ide_stopped;
+		}
+	}
 	return ide_started;
-}
+#else
+	switch(taskfile->command) {
+		case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_EXT:
+			if (drive->using_dma && !(hwif->ide_dma_write(drive)))
+				return ide_started;
+		case WIN_READDMA_ONCE:
+		case WIN_READDMA:
+		case WIN_READDMA_EXT:
+		case WIN_IDENTIFY_DMA:
+			if (drive->using_dma && !(hwif->ide_dma_read(drive)))
+				return ide_started;
+		default:
+			break;
+	}
+	return ide_stopped;
 #endif
+}
+
+EXPORT_SYMBOL(do_rw_taskfile);
 
-#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)
+u8 taskfile_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
+	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (stat & BUSY_STAT) {
 		printk("Busy ");
-	else {
+	} else {
 		if (stat & READY_STAT)	printk("DriveReady ");
 		if (stat & WRERR_STAT)	printk("DeviceFault ");
 		if (stat & SEEK_STAT)	printk("SeekComplete ");
@@ -452,61 +288,66 @@
 #endif  /* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		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);
+		if (drive->media == ide_disk)
+			goto media_out;
+
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)	printk("Bad%s", (err & ABRT_ERR) ? "CRC " : "Sector ");
+		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->addressing == 1) {
+				u64 sectors = 0;
+				u32 high = 0;
+				u32 low = task_read_24(drive);
+				hwif->OUTB(0x80, IDE_CONTROL_REG);
+				high = task_read_24(drive);
+				sectors = ((u64)high << 24) | low;
+				printk(", LBAsect=%lld", sectors);
+			} else {
+				u8 cur  = hwif->INB(IDE_SELECT_REG);
+				u8 low  = hwif->INB(IDE_LCYL_REG);
+				u8 high = hwif->INB(IDE_HCYL_REG);
+				u8 sect = hwif->INB(IDE_SECTOR_REG);
+				/* using LBA? */
+				if (cur & 0x40) {
+					printk(", LBAsect=%d", (u32)
+						((cur&0xf)<<24)|(high<<16)|
+						(low<<8)|sect);
 				} 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));
-					}
+					printk(", CHS=%d/%d/%d",
+						((high<<8) + low),
+						(cur & 0xf), sect);
 				}
-				if (HWGROUP(drive)->rq)
-					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
 			}
+			if (HWGROUP(drive)->rq)
+				printk(", sector=%lu",
+					HWGROUP(drive)->rq->sector);
 		}
+media_out:
 #endif  /* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	__restore_flags (flags);	/* local CPU only */
+	local_irq_restore(flags);
 	return err;
 }
 
+EXPORT_SYMBOL(taskfile_dump_status);
+
 /*
  * Clean up after success/failure of an explicit taskfile operation.
  */
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+void ide_end_taskfile (ide_drive_t *drive, u8 stat, u8 err)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 	ide_task_t *args;
@@ -519,28 +360,39 @@
 
 	command = args->tfRegister[IDE_COMMAND_OFFSET];
 
-	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+	if (rq->errors == 0)
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
+	if (args->tf_in_flags.b.data) {
+		u16 data = hwif->INW(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_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(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);
+		hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
 	}
 
+#if 0
 /*	taskfile_settings_update(drive, args, command); */
 
+	if (args->posthandler != NULL)
+		args->posthandler(drive, args);
+#endif
+
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
@@ -548,6 +400,8 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_end_taskfile);
+
 /*
  * try_to_flush_leftover_data() is invoked in response to a drive
  * unexpectedly having its DRQ_STAT bit set.  As an alternative to
@@ -565,53 +419,68 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		taskfile_input_data (drive, buffer, wcount);
+		taskfile_input_data(drive, buffer, wcount);
 	}
 }
 
+EXPORT_SYMBOL(task_try_to_flush_leftover_data);
+
 /*
  * 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)
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 
         err = taskfile_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
 	if (rq->cmd == IDE_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 */
+	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)) {
+		if (drive->media != ide_disk)
+			goto media_out;
+		if (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 */
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				/* UDMA crc error -- just retry the operation */
+				drive->crc_count++;
+			} 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;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
                 }
-                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+media_out:
+                if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
                         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 (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-			ide_end_request(0, HWGROUP(drive));
+		DRIVER(drive)->end_request(drive, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -623,20 +492,18 @@
 	}
 	return ide_stopped;
 }
-#endif
 
-/*
- * Handler for special commands without a data phase from ide-disk
- */
+EXPORT_SYMBOL(taskfile_error);
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
 ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 		drive->mult_count = drive->mult_req;
 	} else {
 		drive->mult_req = drive->mult_count = 0;
@@ -646,282 +513,368 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(set_multmode_intr);
+
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
 ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	int retries = 5;
+	u8 stat;
+
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+	if (OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_stopped;
 
 	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(set_geometry_intr);
+
 /*
  * 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();
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "recal_intr", stat);
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(recal_intr);
+
 /*
  * 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 */
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
 
+	local_irq_enable();
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+		DTF("%s: command opcode 0x%02x\n", drive->name,
+			args->tfRegister[IDE_COMMAND_OFFSET]);
+		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	}
 	if (args)
-		ide_end_drive_cmd (drive, stat, GET_ERR());
+		ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(task_no_data_intr);
+
 /*
- * Handler for command with PIO data-in phase
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.4 enable ...
+ *	DATA integrity issue upon error. <andre@linux-ide.org>
  */
 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;
+	ide_hwif_t *hwif	= HWIF(drive);
 	char *pBuf		= NULL;
+	u8 stat;
+	unsigned long flags;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_in_intr", stat);
+#if 0
+			DTF("%s: attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+			/*
+			 * Expect a BUG BOMB if we attempt to rewind the
+			 * offset in the BH aka PAGE in the current BLOCK
+			 * segment.  This is different than the HOST segment.
+			 */
+#endif
+			if (!rq->bh)
+				rq->current_nr_sectors++;
+			return DRIVER(drive)->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);
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 			return ide_started;  
 		}
 	}
-	DTF("stat: %02x\n", stat);
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	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);
-	drive->io_32bit = io_32bit;
-
-	if (--rq->current_nr_sectors <= 0) {
-		/* (hs): swapped next 2 lines */
-		DTF("Request Ended stat: %02x\n", GET_STAT());
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
-}
+#if 0
 
-#undef ALTSTAT_SCREW_UP
+	/*
+	 * Holding point for a brain dump of a thought :-/
+	 */
 
-#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;
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: READ attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_in_intr", stat);
+        }
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+#endif
 
-	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;
-		}
-	}
+	pBuf = task_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	task_unmap_rq(rq, pBuf, &flags);
+	/*
+	 * FIXME :: We really can not legally get a new page/bh
+	 * regardless, if this is the end of our segment.
+	 * BH walking or segment can only be updated after we have a good
+	 * hwif->INB(IDE_STATUS_REG); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 * ERM, it is techincally legal to leave/exit here but it makes
+	 * a mess of the code ...
 	 */
-	return(GET_STAT());
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
 }
 
-/*
- * (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 */
+EXPORT_SYMBOL(task_in_intr);
 
 /*
  * 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;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned int msect	= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
+	u8 stat;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulin_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-READ assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, 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) {
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
 		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we have a
+		 * good hwif->INB(IDE_STATUS_REG); return.
 		 */
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			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);
-			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 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-
-	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);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	ide_end_request(1, HWGROUP(drive));
-	return ide_stopped;
-}
+EXPORT_SYMBOL(task_mulin_intr);
 
+/*
+ * VERIFY ME before 2.4 ... unexpected race is possible based on details
+ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
+ */
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
-	ide_task_t *args = rq->special;
+	char *pBuf		= NULL;
+	unsigned long flags;
 	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");
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
+			drive->name,
+			drive->addressing ? "_EXT" : "");
 		return startstop;
 	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
-		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		return ide_started;
-	} 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);
-	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = task_map_rq(rq, &flags);
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	rq->current_nr_sectors--;
+	task_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(pre_task_out_intr);
+
 /*
- * Handler for command with PIO data-out phase
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
  */
 ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
+	u8 stat;
 
-	if (!rq->current_nr_sectors) { 
-		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 (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) {
+		DTF("%s: WRITE attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_out_intr", stat);
 	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
-		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-		drive->io_32bit = 0;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
+		task_unmap_rq(rq, pBuf, &flags);
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	if (rq->current_nr_sectors <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
-		return ide_started;
+EXPORT_SYMBOL(task_out_intr);
+
+#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	ide_hwif_t *hwif		= HWIF(drive);
+	char *pBuf			= NULL;
+	unsigned int nsect = 0, msect	= drive->mult_count;
+        u8 stat;
+	unsigned long flags;
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+#if 0
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+#endif
+
+	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->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
+		return startstop;
 	}
-	return ide_stopped;
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh) {
+					stat = hwif->INB(IDE_STATUS_REG);
+					return ide_stopped;
+				}
+		}
+	} while (msect);
+	rq->errors = 0;
+	return ide_started;
+#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+	if (!(drive_is_ready(drive))) {
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+
+	/*
+	 * WARNING :: if the drive as not acked good status we may not
+	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
+	 */
+	return args->handler(drive);
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
 }
 
+EXPORT_SYMBOL(pre_task_mulout_intr);
+
+/*
+ * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
+ */
 /*
  * Handler for command write multiple
  * Called directly from execute_drive_cmd for the first bunch of sectors,
@@ -929,93 +882,119 @@
  */
 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;
+	ide_hwif_t *hwif		= HWIF(drive);
+	u8 stat				= hwif->INB(IDE_STATUS_REG);
+	struct request *rq		= HWGROUP(drive)->rq;
+	char *pBuf			= NULL;
+	ide_startstop_t startstop	= ide_stopped;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent
+	 * 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);
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bh) {
+                                rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk(KERN_ERR "%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		if (!rq->bh)
+			DRIVER(drive)->end_request(drive, 1);
+		return startstop;
 	}
-
+	/*
+	 * DON'T be lazy code the above and below togather !!!
+	 */
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk(KERN_ERR "%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->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);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, 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 = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			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);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&io_request_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, lflags);
+	}
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		/*
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we
+		 * have a good  hwif->INB(IDE_STATUS_REG); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh)
+					return ide_stopped;
 		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	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);
-	drive->io_32bit = io_32bit;
+	} while (msect);
 	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_mulout_intr);
+
 /* Called by internal to feature out type of command being called */
+//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 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_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-//		case WIN_WRITEDMA:
-//		case WIN_WRITEDMA_QUEUED:
-//		case WIN_WRITEDMA_EXT:
-//		case WIN_WRITEDMA_QUEUED_EXT:
+			return &pre_task_mulout_intr;
+			
 				/* IDE_DRIVE_TASK_OUT */
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
@@ -1025,13 +1004,22 @@
 		case WIN_SMART:
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
 		default:
 			break;
 	}
 	return(NULL);
 }
 
+EXPORT_SYMBOL(ide_pre_handler_parser);
+
 /* Called by internal to feature out type of command being called */
+//ide_handler_t * ide_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
@@ -1040,6 +1028,7 @@
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ_BUFFER:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
 		case WIN_READ_EXT:
 			return &task_in_intr;
 		case WIN_SECURITY_DISABLE:
@@ -1051,11 +1040,16 @@
 		case WIN_WRITE_BUFFER:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:	
 		case WIN_WRITE_EXT:
 			return &task_out_intr;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
 		case WIN_MULTREAD_EXT:
 			return &task_mulin_intr;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
@@ -1074,13 +1068,16 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 			return &task_no_data_intr;
 		case WIN_SPECIFY:
 			return &set_geometry_intr;
-		case WIN_RESTORE:
+		case WIN_RECAL:
+	//	case WIN_RESTORE:
 			return &recal_intr;
+		case WIN_NOP:
 		case WIN_DIAGNOSE:
 		case WIN_FLUSH_CACHE:
 		case WIN_FLUSH_CACHE_EXT:
@@ -1111,11 +1108,13 @@
 			return &task_no_data_intr;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1130,14 +1129,31 @@
 	}	
 }
 
+EXPORT_SYMBOL(ide_handler_parser);
+
+ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_SPECIFY:	/* set_geometry_intr */
+		case WIN_RESTORE:	/* recal_intr */
+		case WIN_SETMULT:	/* set_multmode_intr */
+		default:
+			return(NULL);
+	}
+}
+
+EXPORT_SYMBOL(ide_post_handler_parser);
+
 /* 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);
+	task_struct_t *taskfile = (task_struct_t *) args->tfRegister;
+	hob_struct_t *hobfile   = (hob_struct_t *) args->hobRegister;
+
+	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
+	args->handler		= ide_handler_parser(taskfile, hobfile);
+	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
 
 	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
 		case WIN_IDENTIFY:
@@ -1145,18 +1161,28 @@
 			return IDE_DRIVE_TASK_IN;
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
+		case WIN_READ_EXT:
 		case WIN_READ_BUFFER:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		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_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
 			return IDE_DRIVE_TASK_IN;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		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:
@@ -1178,12 +1204,14 @@
 			}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		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_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1191,20 +1219,32 @@
 #endif
 		case WIN_SETFEATURES:
 			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_EN_8BIT:
+				case SETFEATURES_EN_WCACHE:
+					return IDE_DRIVE_TASK_NO_DATA;
 				case SETFEATURES_XFER:
 					return IDE_DRIVE_TASK_SET_XFER;
 				case SETFEATURES_DIS_DEFECT:
 				case SETFEATURES_EN_APM:
 				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_DIS_RETRY:
+				case SETFEATURES_EN_AAM:
+				case SETFEATURES_RW_LONG:
+				case SETFEATURES_SET_CACHE:
+				case SETFEATURES_DIS_RLA:
 				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_ECC:
 				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RETRY:
 				case SETFEATURES_EN_RLA:
 				case SETFEATURES_PREFETCH:
+				case SETFEATURES_4B_RW_LONG:
+				case SETFEATURES_DIS_AAM:
 				case SETFEATURES_EN_RPOD:
 				case SETFEATURES_DIS_RI:
 				case SETFEATURES_DIS_SI:
@@ -1215,6 +1255,7 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 		case WIN_SPECIFY:
@@ -1253,6 +1294,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_cmd_type_parser);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1262,127 +1305,158 @@
 	rq->cmd = IDE_DRIVE_TASK_NO_DATA;
 }
 
-/*
- * 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;
+EXPORT_SYMBOL(ide_init_drive_taskfile);
 
-	memset(&args, 0, sizeof(ide_task_t));
+#if 1
 
-	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;
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+	struct request rq;
 
 	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.cmd = IDE_DRIVE_TASKFILE;
 	rq.buffer = buf;
-	rq.special = &args;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0)
+			rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		/*	rq.hard_cur_sectors	*/
+		else
+			rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
+		/*	rq.hard_cur_sectors	*/
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+
+	}
+	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)
+#else
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 {
-	struct request rq;
-	ide_init_drive_taskfile(&rq);
-	rq.cmd = IDE_DRIVE_TASKFILE;
-	rq.buffer = buf;
+	struct request *rq;
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	struct list_head *queue_head = &drive->queue.queue_head;
+	DECLARE_COMPLETION(wait);
 
-	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];
+	if (HWIF(drive)->chipset == ide_pdc4030 && buf != NULL)
+		return -ENOSYS; /* special drive cmds not supported */
 
-	rq.special = args;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_TASKFILE;
+	rq->buffer = buf;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0) {
+			ata_nsector_t nsector;
+			nsector.b.low = args->hobRegister[IDE_NSECTOR_OFFSET_HOB];
+			nsector.b.high = args->tfRegister[IDE_NSECTOR_OFFSET];
+			rq.nr_sectors = nsector.all;
+		} else {
+			rq.nr_sectors = data_size / SECTOR_SIZE;
+		}
+		rq.current_nr_sectors = rq.nr_sectors;
+	//	rq.hard_cur_sectors = rq.nr_sectors;
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+	}
+	rq->special = args;
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->waiting = &wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	queue_head = queue_head->prev;
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);	/* wait for it to be serviced */
+	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 }
 
+#endif
+
+EXPORT_SYMBOL(ide_diag_taskfile);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+{
+	return ide_diag_taskfile(drive, args, 0, buf);
+}
 
+EXPORT_SYMBOL(ide_raw_taskfile);
+	
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 char * ide_ioctl_verbose (unsigned int cmd)
 {
 	return("unknown");
 }
 
-char * ide_task_cmd_verbose (byte task)
+char * ide_task_cmd_verbose (u8 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)
 
+ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+ide_startstop_t flagged_task_no_data_intr(ide_drive_t *);
+ide_startstop_t flagged_task_in_intr(ide_drive_t *);
+ide_startstop_t flagged_task_mulin_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_out_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_out_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_mulout_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_mulout_intr(ide_drive_t *);
+
 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;
+	u8 *outbuf		= NULL;
+	u8 *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;
+	u8 io_32bit		= drive->io_32bit;
+
+//	printk("IDE Taskfile ...\n");
 
 	req_task = kmalloc(tasksize, GFP_KERNEL);
 	if (req_task == NULL) return -ENOMEM;
@@ -1423,8 +1497,7 @@
 		}
 	}
 
-	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
-	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memset(&args, 0, sizeof(ide_task_t));
 	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
 	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
@@ -1440,88 +1513,92 @@
 		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
+	drive->io_32bit = 0;
 	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);
+			err = ide_diag_taskfile(drive, &args, taskout, 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);
+			err = ide_diag_taskfile(drive, &args, taskin, 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);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			args.prehandler = NULL;
 			args.handler = &task_in_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, 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 {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
-				printk("%s: %s Multimode Write " \
+				printk(KERN_ERR "%s: %s Multimode Write " \
 					"multcount is not set\n",
-					 drive->name, __FUNCTION__);
+					drive->name, __FUNCTION__);
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_mulout_intr;
+				args.handler = &flagged_task_mulout_intr;
+			} else {
+				args.prehandler = &pre_task_mulout_intr;
+				args.handler = &task_mulout_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			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);
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_out_intr;
+				args.handler    = &flagged_task_out_intr;
+			} else {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_out_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, 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 {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
-				printk("%s: %s Multimode Read failure " \
+				printk(KERN_ERR "%s: %s Multimode Read failure " \
 					"multcount is not set\n",
 					drive->name, __FUNCTION__);
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_mulin_intr;
+			} else {
+				args.handler = &task_mulin_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN:
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_in_intr;
+			} else {
+				args.handler = &task_in_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, 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);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_no_data_intr;
+			} else {
+				args.handler = &task_no_data_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, 0, NULL);
 			break;
 		default:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
 			err = -EFAULT;
 			goto abort;
 	}
@@ -1555,153 +1632,593 @@
 		kfree(outbuf);
 	if (inbuf != NULL)
 		kfree(inbuf);
+
+//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+	drive->io_32bit = io_32bit;
+
 	return err;
 }
 
-EXPORT_SYMBOL(task_read_24);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
-// EXPORT_SYMBOL(flagged_taskfile);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
 
-//EXPORT_SYMBOL(ide_end_taskfile);
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+	struct request rq;
+	u8 buffer[4];
 
-EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
+	if (!buf)
+		buf = buffer;
+	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = cmd;
+	*buf++ = nsect;
+	*buf++ = feature;
+	*buf++ = sectors;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-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_wait_cmd);
 
-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);
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 1
+	int err = -EIO;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
 
-#ifdef CONFIG_PKT_TASK_IOCTL
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
 
-#if 0
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	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 */
+		ide_set_xfer_rate(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;
+
+#else
+
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 0;
+	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;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	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 = (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+	}
+
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	tfargs.command_type = ide_cmd_type_parser(&tfargs);
+	err = ide_raw_taskfile(drive, &tfargs, argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
+	args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
+	args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
+	args[3] = 0;
+
+	if (copy_to_user((void *)arg, argbuf, 4))
+		err = -EFAULT;
+	if (argbuf != NULL) {
+		if (copy_to_user((void *)arg, argbuf + 4, argsize))
+			err = -EFAULT;
+		kfree(argbuf);
+	}
+	return err;
+
+#endif
+}
+
+EXPORT_SYMBOL(ide_cmd_ioctl);
+
+int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf)
 {
+	struct request rq;
 
-{ /* start cdrom */
+	ide_init_drive_cmd(&rq);
+	rq.cmd = IDE_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-	struct cdrom_info *info = drive->driver_data;
+EXPORT_SYMBOL(ide_wait_cmd_task);
 
-	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");
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	u8 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(ide_task_ioctl);
+
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations.  Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+#if DEBUG_TASKFILE
+	u8 status;
+#endif
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	/*
+	 * (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 (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 (drive->addressing == 1)
+			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+        }
+
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	SELECT_MASK(drive, 0);
+
+#if DEBUG_TASKFILE
+	status = hwif->INB(IDE_STATUS_REG);
+	if (status & 0x80) {
+		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+		udelay(100);
+		status = hwif->INB(IDE_STATUS_REG);
+		printk("flagged_taskfile -> Status = %02x\n", status);
+	}
+#endif
+
+	if (task->tf_out_flags.b.data) {
+		u16 data =  taskfile->data + (hobfile->data << 8);
+		hwif->OUTW(data, IDE_DATA_REG);
+	}
+
+	/* (ks) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+
+	/* (ks) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (ks) In the flagged taskfile approch, we will used all specified
+	 * registers and the register value will not be changed. Except the
+	 * select bit (master/slave) in the drive_head register. We must make
+	 * sure that the desired drive is selected.
+	 */
+	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	switch(task->data_phase) {
+
+   	        case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			hwif->ide_dma_write(drive);
+			break;
+
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			hwif->ide_dma_read(drive);
+			break;
+
+	        default:
+ 			if (task->handler == NULL)
+				return ide_stopped;
+
+			/* Issue the command */
+			ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+
+	return ide_started;
+}
+
+EXPORT_SYMBOL(flagged_taskfile);
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+
+	local_irq_enable();
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
 		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+ 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
 	}
 
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_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);
+	return ide_stopped;
+}
 
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
 
-	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 */
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
+
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+
+	if (--rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
 		return ide_started;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
 	}
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-} /* end cdrom */
+	return ide_stopped;
+}
 
-{ /* start floppy */
+ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+	unsigned int msect, nsect;
 
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
 
-	floppy->pc=pc;		/* Set the current packet command */
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
 
-	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);
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
+	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
 	}
-	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);
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_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));
+	return ide_stopped;
+}
+
+/*
+ * Pre handler for command with PIO data-out phase
+ */
+ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	ide_startstop_t startstop;
+
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-} /* end floppy */
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
 
-{ /* start tape */
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	idetape_tape_t *tape = drive->driver_data;
+	return ide_started;
+}
 
-#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 */
+ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
 
-	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);
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
 	}
 
-} /* end tape */
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
+	}
 
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
+		(int) rq->current_nr_sectors, stat);
+
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	--rq->current_nr_sectors;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
 }
-#endif
+
+ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	char *pBuf		= NULL;
+	ide_startstop_t startstop;
+	unsigned int msect, nsect;
+
+	if (!rq->current_nr_sectors) 
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect, nsect;
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	rq->current_nr_sectors -= nsect;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+
+#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)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide.c linux-2.4.21-rc3/drivers/ide/ide.c
--- linux-2.4.20/drivers/ide/ide.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide.c	2003-05-22 22:06:53.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
+ *  linux/drivers/ide/ide.c		Version 7.00beta3	Apr 22 2003
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -12,7 +12,8 @@
  *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
+ *   (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
  * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
@@ -113,16 +114,15 @@
  * Version 6.31		Debug Share INTR's and request queue streaming
  *			Native ATA-100 support
  *			Prep for Cascades Project
+ * Version 7.00alpha	First named revision of ide rearrange
+ * Version 7.00beta	(2.4 backport)
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
- *  To do, in likely order of completion:
- *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
-#define	REVISION	"Revision: 6.31"
-#define	VERSION		"Id: ide.c 6.31 2000/06/09"
+#define	REVISION	"Revision: 7.00beta3-.2.4"
+#define	VERSION		"Id: ide.c 7.00b3 20030422"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -141,9 +141,7 @@
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
 #include <linux/slab.h>
-#ifndef MODULE
 #include <linux/init.h>
-#endif /* MODULE */
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -159,81 +157,60 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-#ifdef __TASKFILE__IO
-#else /* !__TASKFILE__IO */
-#endif /* __TASKFILE__IO */
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
 
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+					IDE2_MAJOR, IDE3_MAJOR,
+					IDE4_MAJOR, IDE5_MAJOR,
+					IDE6_MAJOR, IDE7_MAJOR,
+					IDE8_MAJOR, IDE9_MAJOR };
+
+static int idebus_parameter;	/* holds the "idebus=" parameter */
+static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
+static int initializing;	/* set while initializing built-in drivers */
 
-static int	idebus_parameter; /* holds the "idebus=" parameter */
-static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
-static int	initializing;     /* set while initializing built-in drivers */
+static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#ifdef CONFIG_IDEDMA_AUTO
+int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
 
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-/*
- * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-static int	ide_lock;
-#endif /* __mc68000__ || CONFIG_APUS */
+EXPORT_SYMBOL(noautodma);
 
-int noautodma = 0;
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
+ide_module_t *ide_chipsets;
 ide_module_t *ide_modules;
 ide_module_t *ide_probe;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
 
-#if (DISK_RECOVERY_TIME > 0)
-/*
- * For really screwy hardware (hey, at least it *can* be used with Linux)
- * we can enforce a minimum delay time between successive operations.
- */
-static unsigned long read_timer (void)
-{
-	unsigned long t, flags;
-	int i;
+EXPORT_SYMBOL(ide_hwifs);
 
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	__restore_flags(flags);	/* local CPU only */
-	return (t - i);
-}
-#endif /* DISK_RECOVERY_TIME */
-
-static inline void set_recovery_timer (ide_hwif_t *hwif)
-{
-#if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
-}
+ide_devices_t *idedisk;
+ide_devices_t *idecd;
+ide_devices_t *idefloppy;
+ide_devices_t *idetape;
+ide_devices_t *idescsi;
+
+EXPORT_SYMBOL(idedisk);
+EXPORT_SYMBOL(idecd);
+EXPORT_SYMBOL(idefloppy);
+EXPORT_SYMBOL(idetape);
+EXPORT_SYMBOL(idescsi);
+
+extern ide_driver_t idedefault_driver;
+static void setup_driver_defaults (ide_drive_t *drive);
 
 /*
  * Do not even *think* about calling this!
@@ -264,6 +241,16 @@
 	hwif->name[2]	= 'e';
 	hwif->name[3]	= '0' + index;
 	hwif->bus_state = BUSSTATE_ON;
+	hwif->reset_poll= NULL;
+	hwif->pre_reset = NULL;
+
+	hwif->atapi_dma = 0;		/* disable all atapi dma */ 
+	hwif->ultra_mask = 0x80;	/* disable all ultra */
+	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
+	hwif->swdma_mask = 0x80;	/* disable all swdma */
+
+	default_hwif_iops(hwif);
+	default_hwif_transport(hwif);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
@@ -279,6 +266,10 @@
 		drive->name[1]			= 'd';
 		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		drive->using_dma		= 0;
+		drive->is_flash			= 0;
+		drive->driver			= &idedefault_driver;
+		setup_driver_defaults(drive);
 		init_waitqueue_head(&drive->wqueue);
 	}
 }
@@ -296,6 +287,9 @@
  * This is too bad, as otherwise we could dynamically allocate the
  * ide_drive_t structs as needed, rather than always consuming memory
  * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
+ *
+ * FIXME: We should stuff the setup data into __init and copy the
+ * relevant hwifs/allocate them properly during boot.
  */
 #define MAGIC_COOKIE 0x12345678
 static void __init init_ide_data (void)
@@ -314,1703 +308,141 @@
 	/* Add default hw interfaces */
 	ide_init_default_hwifs();
 
-	idebus_parameter = 0;
-	system_bus_speed = 0;
-}
-
-/*
- * CompactFlash cards and their brethern pretend to be removable hard disks, except:
- *	(1) they never have a slave unit, and
- *	(2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
- * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
- * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
- * At that time, we might also consider parameterizing the timeouts and retries,
- * since these are MUCH faster than mechanical drives.	-M.Lord
- */
-int drive_is_flashcard (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a) return 1;	/* CompactFlash */
-		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
-		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
-		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
-		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
-		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
-		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
-		{
-			return 1;	/* yes, it is a flash memory card */
-		}
-	}
-	return 0;	/* no, it is not a flash memory card */
-}
-
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
- */
-int ide_system_bus_speed (void)
-{
-	if (!system_bus_speed) {
-		if (idebus_parameter)
-			system_bus_speed = idebus_parameter;	/* user supplied value */
-#ifdef CONFIG_PCI
-		else if (pci_present())
-			system_bus_speed = 33;	/* safe default value for PCI */
-#endif /* CONFIG_PCI */
-		else
-			system_bus_speed = 50;	/* safe default value for VESA and PCI */
-		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
-			idebus_parameter ? "" : "; override with idebus=xx");
-	}
-	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 */
-}
-
-/*
- * This is our end_request replacement function.
- */
-void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
-{
-	struct request *rq;
-	unsigned long flags;
-	ide_drive_t *drive = hwgroup->drive;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = hwgroup->rq;
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		hwgroup->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
-		add_blkdev_randomness(MAJOR(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-        	hwgroup->rq = NULL;
-		end_that_request_last(rq);
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * This should get invoked any time we exit the driver to
- * wait for an interrupt response from a drive.  handler() points
- * at the appropriate code to handle the next interrupt, and a
- * timer is started to prevent us from waiting forever in case
- * something goes wrong (see the ide_timer_expiry() handler later on).
- */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-		      unsigned int timeout, ide_expiry_t *expiry)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (hwgroup->handler != NULL) {
-		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
-			drive->name, hwgroup->handler, handler);
-	}
-	hwgroup->handler	= handler;
-	hwgroup->expiry		= expiry;
-	hwgroup->timer.expires	= jiffies + timeout;
-	add_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
- */
-unsigned long current_capacity (ide_drive_t *drive)
-{
-	if (!drive->present)
-		return 0;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->capacity(drive);
-	return 0;
-}
-
-extern struct block_device_operations ide_fops[];
-/*
- * ide_geninit() is called exactly *once* for each interface.
- */
-void ide_geninit (ide_hwif_t *hwif)
-{
-	unsigned int unit;
-	struct gendisk *gd = hwif->gd;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-
-		if (!drive->present)
-			continue;
-		if (drive->media!=ide_disk && drive->media!=ide_floppy)
-			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
-#ifdef CONFIG_BLK_DEV_ISAPNP
-			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-			1<<PARTN_BITS, ide_fops,
-			current_capacity(drive));
-	}
-}
-
-static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	byte stat;
-
-	SELECT_DRIVE(HWIF(drive),drive);
-	udelay (10);
-
-	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
-		printk("%s: ATAPI reset complete\n", drive->name);
-	} else {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		hwgroup->poll_timeout = 0;	/* end of polling */
-		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		return do_reset1 (drive, 1);	/* do it the old fashioned way */
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tmp;
-
-	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
-		drive->failures++;
-	} else  {
-		printk("%s: reset: ", hwif->name);
-		if ((tmp = GET_ERR()) == 1) {
-			printk("success\n");
-			drive->failures = 0;
-		} else {
-			drive->failures++;
-#if FANCY_STATUS_DUMPS
-			printk("master: ");
-			switch (tmp & 0x7f) {
-				case 1: printk("passed");
-					break;
-				case 2: printk("formatter device error");
-					break;
-				case 3: printk("sector buffer error");
-					break;
-				case 4: printk("ECC circuitry error");
-					break;
-				case 5: printk("controlling MPU error");
-					break;
-				default:printk("error (0x%02x?)", tmp);
-			}
-			if (tmp & 0x80)
-				printk("; slave: failed");
-			printk("\n");
-#else
-			printk("failed\n");
-#endif /* FANCY_STATUS_DUMPS */
-		}
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-static void check_dma_crc (ide_drive_t *drive)
-{
-	if (drive->crc_count) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
-		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
-	} else {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-}
-
-static void pre_reset (ide_drive_t *drive)
-{
-	if (drive->driver != NULL)
-		DRIVER(drive)->pre_reset(drive);
-
-	if (!drive->keep_settings) {
-		if (drive->using_dma) {
-			check_dma_crc(drive);
-		} else {
-			drive->unmask = 0;
-			drive->io_32bit = 0;
-		}
-		return;
-	}
-	if (drive->using_dma)
-		check_dma_crc(drive);
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
-{
-	unsigned int unit;
-	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	/* For an ATAPI device, first try an ATAPI SRST. */
-	if (drive->media != ide_disk && !do_not_try_atapi) {
-		pre_reset(drive);
-		SELECT_DRIVE(hwif,drive);
-		udelay (20);
-		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		__restore_flags (flags);	/* local CPU only */
-		return ide_started;
-	}
-
-	/*
-	 * First, reset any device state data we were maintaining
-	 * for any of the drives on this interface.
-	 */
-	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		pre_reset(&hwif->drives[unit]);
-
-#if OK_TO_RESET_CONTROLLER
-	if (!IDE_CONTROL_REG) {
-		__restore_flags(flags);
-		return ide_stopped;
-	}
-	/*
-	 * Note that we also set nIEN while resetting the device,
-	 * to mask unwanted interrupts from the interface during the reset.
-	 * However, due to the design of PC hardware, this will cause an
-	 * immediate interrupt due to the edge transition it produces.
-	 * This single interrupt gives us a "fast poll" for drives that
-	 * recover from reset very quickly, saving us the first 50ms wait time.
-	 */
-	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
-	udelay(10);			/* more than enough time */
-	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);
-
-	/*
-	 * Some weird controller like resetting themselves to a strange
-	 * state when the disks are reset this way. At least, the Winbond
-	 * 553 documentation says that
-	 */
-	if (hwif->resetproc != NULL)
-		hwif->resetproc(drive);
-
-#endif	/* OK_TO_RESET_CONTROLLER */
-
-	__restore_flags (flags);	/* local CPU only */
-	return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
-	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
- */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
-{
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = HWGROUP(drive)->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	switch(rq->cmd) {
-		case IDE_DRIVE_CMD:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-			}
-			break;
-		}
-		case IDE_DRIVE_TASK:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-				args[3] = IN_BYTE(IDE_SECTOR_REG);
-				args[4] = IN_BYTE(IDE_LCYL_REG);
-				args[5] = IN_BYTE(IDE_HCYL_REG);
-				args[6] = IN_BYTE(IDE_SELECT_REG);
-			}
-			break;
-		}
-		case IDE_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);
-				}
-			}
-			break;
-		}
-		default:
-			break;
-	}
-	spin_lock_irqsave(&io_request_lock, flags);
-	blkdev_dequeue_request(rq);
-	HWGROUP(drive)->rq = NULL;
-	end_that_request_last(rq);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte ide_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 = read_24(drive);
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
-					high = read_24(drive);
-
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%llu, high=%d, low=%d",
-					       (unsigned long long) sectors,
-					       high, low);
-				} 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) && HWGROUP(drive)->rq)
-					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
-			}
-		}
-#endif	/* FANCY_STATUS_DUMPS */
-		printk("\n");
-	}
-	__restore_flags (flags);	/* local CPU only */
-	return err;
-}
-
-/*
- * 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*.
- */
-static void 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;
-		ide_input_data (drive, buffer, wcount);
-	}
-}
-
-/*
- * ide_error() takes action based on the error returned by the drive.
- */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
-{
-	struct request *rq;
-	byte err;
-
-	err = ide_dump_status(drive, msg, stat);
-	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return ide_stopped;
-	/* retry only "normal" I/O: */
-	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-		return ide_stopped;
-	}
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-//		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;
-		}
-		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
-			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;
-}
-
-/*
- * 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)
-{
-	ide_set_handler (drive, handler, WAIT_CMD, NULL);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive),drive,0);
-	OUT_BYTE(nsect,IDE_NSECTOR_REG);
-	OUT_BYTE(cmd,IDE_COMMAND_REG);
-}
-
-/*
- * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- */
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
-{
-	struct request *rq = HWGROUP(drive)->rq;
-	byte *args = (byte *) rq->buffer;
-	byte stat = GET_STAT();
-	int retries = 10;
-
-	ide__sti();	/* local CPU only */
-	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);
-		drive->io_32bit = io_32bit;
-		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-	return ide_stopped;
-}
-
-/*
- * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back.
- */
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-#ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_tune = 0;
-		if (tuneproc != NULL)
-			tuneproc(drive, drive->tune_req);
-	} else if (drive->driver != NULL) {
-		return DRIVER(drive)->special(drive);
-	} else if (s->all) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
-		s->all = 0;
-	}
-	return ide_stopped;
-}
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should just return.
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
- */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
-	byte stat;
-	int i;
-	unsigned long flags;
- 
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		*startstop = ide_stopped;
-		return 1;
-	}
-
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only */
-		timeout += jiffies;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout)) {
-				__restore_flags(flags);	/* local CPU only */
-				*startstop = ide_error(drive, "status timeout", stat);
-				return 1;
-			}
-		}
-		__restore_flags(flags);	/* local CPU only */
-	}
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), good, bad))
-			return 0;
-	}
-	*startstop = ide_error(drive, "status error", stat);
-	return 1;
-}
-
-/*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
- 	switch(rq->cmd) {
- 		case IDE_DRIVE_TASKFILE:
- 		{
- 			ide_task_t *args = rq->special;
- 
- 			if (!(args)) break;
- 
-#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;
- 		}
- 		case IDE_DRIVE_TASK:
- 		{
- 			byte *args = rq->buffer;
- 			byte sel;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			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);
- 			OUT_BYTE(args[4], IDE_LCYL_REG);
- 			OUT_BYTE(args[5], IDE_HCYL_REG);
- 			sel = (args[6] & ~0x10);
- 			if (drive->select.b.unit)
- 				sel |= 0x10;
- 			OUT_BYTE(sel, IDE_SELECT_REG);
- 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		case IDE_DRIVE_CMD:
- 		{
- 			byte *args = rq->buffer;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			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);
- 				OUT_BYTE(0xc2, IDE_HCYL_REG);
- 				OUT_BYTE(args[2],IDE_FEATURE_REG);
- 				OUT_BYTE(args[1],IDE_SECTOR_REG);
- 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- 				return ide_started;
- 			}
- 			OUT_BYTE(args[2],IDE_FEATURE_REG);
- 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		default:
- 			break;
- 	}
- 	/*
- 	 * 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);
-#endif
- 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- 	return ide_stopped;
-}
-
-/*
- * start_request() initiates handling of a new I/O request
- * needed to reverse the perverted changes anonymously made back
- * 2.3.99-pre6
- */
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long block, blockend;
-	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
-	ide_hwif_t *hwif = HWIF(drive);
-
-#ifdef DEBUG
-	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
-#endif
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		goto kill_rq;
-	}
-
-	if (unit >= MAX_DRIVES) {
-		printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
-		goto kill_rq;
-	}
-#ifdef DEBUG
-	if (rq->bh && !buffer_locked(rq->bh)) {
-		printk("%s: block not locked\n", drive->name);
-		goto kill_rq;
-	}
-#endif
-	block    = rq->sector;
-	blockend = block + rq->nr_sectors;
-
-	if ((rq->cmd == READ || rq->cmd == WRITE) &&
-	    (drive->media == ide_disk || drive->media == ide_floppy)) {
-		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
-			printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
-			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
-			goto kill_rq;
-		}
-		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-	}
-	/* Yecch - this will shift the entire interval,
-	   possibly killing some innocent following sector */
-	if (block == 0 && drive->remap_0_to_1 == 1)
-		block = 1;  /* redirect MBR access to EZ-Drive partn table */
-
-#if (DISK_RECOVERY_TIME > 0)
-	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
-#endif
-
-	SELECT_DRIVE(hwif, drive);
-	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
-		printk("%s: drive not ready for command\n", drive->name);
-		return startstop;
-	}
-	if (!drive->special.all) {
-		switch(rq->cmd) {
-			case IDE_DRIVE_CMD:
-			case IDE_DRIVE_TASK:
-			case IDE_DRIVE_TASKFILE:
-				return execute_drive_cmd(drive, rq);
-			default:
-				break;
-		}
-		if (drive->driver != NULL) {
-			return (DRIVER(drive)->do_request(drive, rq, block));
-		}
-		printk("%s: media type %d not supported\n", drive->name, drive->media);
-		goto kill_rq;
-	}
-	return do_special(drive);
-kill_rq:
-	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(0, HWGROUP(drive));
-	else
-		ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
-}
-
-ide_startstop_t restart_request (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	rq = hwgroup->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	return start_request(drive, rq);
-}
-
-/*
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the hwgroup by sleeping for timeout jiffies.
- */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
-{
-	if (timeout > WAIT_WORSTCASE)
-		timeout = WAIT_WORSTCASE;
-	drive->sleep = timeout + jiffies;
-}
-
-#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
-
-/*
- * choose_drive() selects the next drive which will be serviced.
- */
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
-{
-	ide_drive_t *drive, *best;
-
-repeat:	
-	best = NULL;
-	drive = hwgroup->drive;
-	do {
-		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
-			if (!best
-			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
-			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
-			{
-				if( !drive->queue.plugged )
-					best = drive;
-			}
-		}
-	} while ((drive = drive->next) != hwgroup->drive);
-	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
-		long t = (signed long)(WAKEUP(best) - jiffies);
-		if (t >= WAIT_MIN_SLEEP) {
-			/*
-			 * We *may* have some time to spare, but first let's see if
-			 * someone can potentially benefit from our nice mood today..
-			 */
-			drive = best->next;
-			do {
-				if (!drive->sleep
-				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
-				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
-				{
-					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
-					goto repeat;
-				}
-			} while ((drive = drive->next) != best);
-		}
-	}
-	return best;
-}
-
-/*
- * Issue a new request to a drive from hwgroup
- * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
- *
- * A hwgroup is a serialized group of IDE interfaces.  Usually there is
- * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
- * may have both interfaces in a single hwgroup to "serialize" access.
- * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
- * together into one hwgroup for serialized access.
- *
- * Note also that several hwgroups can end up sharing a single IRQ,
- * possibly along with many other devices.  This is especially common in
- * PCI-based systems with off-board IDE controller cards.
- *
- * The IDE driver uses the single global io_request_lock spinlock to protect
- * access to the request queues, and to protect the hwgroup->busy flag.
- *
- * The first thread into the driver for a particular hwgroup sets the
- * hwgroup->busy flag to indicate that this hwgroup is now active,
- * and then initiates processing of the top request from the request queue.
- *
- * Other threads attempting entry notice the busy setting, and will simply
- * queue their new requests and exit immediately.  Note that hwgroup->busy
- * remains set even when the driver is merely awaiting the next interrupt.
- * Thus, the meaning is "this hwgroup is busy processing a request".
- *
- * When processing of a request completes, the completing thread or IRQ-handler
- * will start the next request from the queue.  If no more work remains,
- * the driver will clear the hwgroup->busy flag and exit.
- *
- * The io_request_lock (spinlock) is used to protect all access to the
- * hwgroup->busy flag, but is otherwise not needed for most processing in
- * the driver.  This makes the driver much more friendlier to shared IRQs
- * than previous designs, while remaining 100% (?) SMP safe and capable.
- */
-/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
- *         into life on wakeup from machine sleep.
- */ 
-void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
-	ide_drive_t	*drive;
-	ide_hwif_t	*hwif;
-	struct request	*rq;
-	ide_startstop_t	startstop;
-
-	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
-
-	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
-
-	while (!hwgroup->busy) {
-		hwgroup->busy = 1;
-		drive = choose_drive(hwgroup);
-		if (drive == NULL) {
-			unsigned long sleep = 0;
-			hwgroup->rq = NULL;
-			drive = hwgroup->drive;
-			do {
-				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
-					sleep = drive->sleep;
-			} while ((drive = drive->next) != hwgroup->drive);
-			if (sleep) {
-				/*
-				 * Take a short snooze, and then wake up this hwgroup again.
-				 * This gives other hwgroups on the same a chance to
-				 * play fairly with us, just in case there are big differences
-				 * in relative throughputs.. don't want to hog the cpu too much.
-				 */
-				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
-					sleep = jiffies + WAIT_MIN_SLEEP;
-#if 1
-				if (timer_pending(&hwgroup->timer))
-					printk("ide_set_handler: timer already active\n");
-#endif
-				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
-				mod_timer(&hwgroup->timer, sleep);
-				/* we purposely leave hwgroup->busy==1 while sleeping */
-			} else {
-				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
-				ide_release_lock(&ide_lock);	/* for atari only */
-				hwgroup->busy = 0;
-			}
-			return;		/* no more work for this hwgroup (for now) */
-		}
-		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
-			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(hwif, drive);
-		}
-		hwgroup->hwif = hwif;
-		hwgroup->drive = drive;
-		drive->sleep = 0;
-		drive->service_start = jiffies;
-
-		if ( drive->queue.plugged )	/* paranoia */
-			printk("%s: Huh? nuking plugged queue\n", drive->name);
-
-		rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
-		/*
-		 * Some systems have trouble with IDE IRQs arriving while
-		 * the driver is still setting things up.  So, here we disable
-		 * the IRQ used by this interface while the request is being started.
-		 * This may look bad at first, but pretty much the same thing
-		 * happens anyway when any interrupt comes in, IDE or otherwise
-		 *  -- the kernel masks the IRQ while it is being handled.
-		 */
-		if (masked_irq && hwif->irq != masked_irq)
-			disable_irq_nosync(hwif->irq);
-		spin_unlock(&io_request_lock);
-		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
-		spin_lock_irq(&io_request_lock);
-		if (masked_irq && hwif->irq != masked_irq)
-			enable_irq(hwif->irq);
-		if (startstop == ide_stopped)
-			hwgroup->busy = 0;
-	}
-}
-
-/*
- * ide_get_queue() returns the queue which corresponds to a given device.
- */
-request_queue_t *ide_get_queue (kdev_t dev)
-{
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
-
-	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
-}
-
-/*
- * Passes the stuff to ide_do_request
- */
-void do_ide_request(request_queue_t *q)
-{
-	ide_do_request(q->queuedata, 0);
-}
-
-/*
- * un-busy the hwgroup etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-void ide_dma_timeout_retry(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct request *rq;
-
-	/*
-	 * end current dma transaction
-	 */
-	(void) hwif->dmaproc(ide_dma_end, drive);
-
-	/*
-	 * complain a little, later we might remove some of this verbosity
-	 */
-	printk("%s: timeout waiting for DMA\n", drive->name);
-	(void) hwif->dmaproc(ide_dma_timeout, drive);
-
-	/*
-	 * disable dma for now, but remember that we did so because of
-	 * a timeout -- we'll reenable after we finish this next request
-	 * (or rather the first chunk of it) in pio.
-	 */
-	drive->retry_pio++;
-	drive->state = DMA_PIO_RETRY;
-	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	/*
-	 * un-busy drive etc (hwgroup->busy is cleared on return) and
-	 * make sure request is sane
-	 */
-	rq = HWGROUP(drive)->rq;
-	HWGROUP(drive)->rq = NULL;
-
-	rq->errors = 0;
-	rq->sector = rq->bh->b_rsector;
-	rq->current_nr_sectors = rq->bh->b_size >> 9;
-	rq->buffer = rq->bh->b_data;
-}
-
-/*
- * ide_timer_expiry() is our timeout function for all drive operations.
- * But note that it can also be invoked as a result of a "sleep" operation
- * triggered by the mod_timer() call in ide_do_request.
- */
-void ide_timer_expiry (unsigned long data)
-{
-	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
-	ide_handler_t	*handler;
-	ide_expiry_t	*expiry;
- 	unsigned long	flags;
-	unsigned long	wait;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	del_timer(&hwgroup->timer);
-
-	if ((handler = hwgroup->handler) == NULL) {
-		/*
-		 * Either a marginal timeout occurred
-		 * (got the interrupt just as timer expired),
-		 * or we were "sleeping" to give other devices a chance.
-		 * Either way, we don't really want to complain about anything.
-		 */
-		if (hwgroup->sleeping) {
-			hwgroup->sleeping = 0;
-			hwgroup->busy = 0;
-		}
-	} else {
-		ide_drive_t *drive = hwgroup->drive;
-		if (!drive) {
-			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
-			hwgroup->handler = NULL;
-		} else {
-			ide_hwif_t *hwif;
-			ide_startstop_t startstop;
-			if (!hwgroup->busy) {
-				hwgroup->busy = 1;	/* paranoia */
-				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
-			}
-			if ((expiry = hwgroup->expiry) != NULL) {
-				/* continue */
-				if ((wait = expiry(drive)) != 0) {
-					/* reset timer */
-					hwgroup->timer.expires  = jiffies + wait;
-					add_timer(&hwgroup->timer);
-					spin_unlock_irqrestore(&io_request_lock, flags);
-					return;
-				}
-			}
-			hwgroup->handler = NULL;
-			/*
-			 * We need to simulate a real interrupt when invoking
-			 * the handler() function, which means we need to globally
-			 * mask the specific IRQ:
-			 */
-			spin_unlock(&io_request_lock);
-			hwif  = HWIF(drive);
-#if DISABLE_IRQ_NOSYNC
-			disable_irq_nosync(hwif->irq);
-#else
-			disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-#endif /* DISABLE_IRQ_NOSYNC */
-			__cli();	/* local CPU only, as if we were handling an interrupt */
-			if (hwgroup->poll_timeout != 0) {
-				startstop = handler(drive);
-			} else if (drive_is_ready(drive)) {
-				if (drive->waiting_for_dma)
-					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
-				(void)ide_ack_intr(hwif);
-				printk("%s: lost interrupt\n", drive->name);
-				startstop = handler(drive);
-			} else {
-				if (drive->waiting_for_dma) {
-					startstop = ide_stopped;
-					ide_dma_timeout_retry(drive);
-				} else
-					startstop = ide_error(drive, "irq timeout", GET_STAT());
-			}
-			set_recovery_timer(hwif);
-			drive->service_time = jiffies - drive->service_start;
-			enable_irq(hwif->irq);
-			spin_lock_irq(&io_request_lock);
-			if (startstop == ide_stopped)
-				hwgroup->busy = 0;
-		}
-	}
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * There's nothing really useful we can do with an unexpected interrupt,
- * other than reading the status register (to clear it), and logging it.
- * There should be no way that an irq can happen before we're ready for it,
- * so we needn't worry much about losing an "important" interrupt here.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- *
- * This routine assumes __cli() is in effect when called.
- *
- * If an unexpected interrupt happens on irq15 while we are handling irq14
- * and if the two interfaces are "serialized" (CMD640), then it looks like
- * we could screw up by interfering with a new request being set up for irq15.
- *
- * In reality, this is a non-issue.  The new command is not sent unless the
- * drive is ready to accept one, in which case we know the drive is not
- * trying to interrupt us.  And ide_set_handler() is always invoked before
- * completing the issuance of any new drive command, so we will not be
- * accidentally invoked as a result of any valid command completion interrupt.
- *
- */
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
-{
-	byte stat;
-	ide_hwif_t *hwif = hwgroup->hwif;
-
-	/*
-	 * handle the unexpected interrupt
-	 */
-	do {
-		if (hwif->irq == irq) {
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
-				/* Try to not flood the console with msgs */
-				static unsigned long last_msgtime, count;
-				++count;
-				if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
-					last_msgtime = jiffies;
-					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
-					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
-				}
-			}
-		}
-	} while ((hwif = hwif->next) != hwgroup->hwif);
-}
-
-/*
- * entry point for all interrupts, caller does __cli() for us
- */
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
-	ide_hwif_t *hwif;
-	ide_drive_t *drive;
-	ide_handler_t *handler;
-	ide_startstop_t startstop;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwif = hwgroup->hwif;
-
-	if (!ide_ack_intr(hwif)) {
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
-		/*
-		 * Not expecting an interrupt from this drive.
-		 * That means this could be:
-		 *	(1) an interrupt from another PCI device
-		 *	sharing the same PCI INT# as us.
-		 * or	(2) a drive just entered sleep or standby mode,
-		 *	and is interrupting to let us know.
-		 * or	(3) a spurious interrupt of unknown origin.
-		 *
-		 * For PCI, we cannot tell the difference,
-		 * so in that case we just ignore it and hope it goes away.
-		 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-		{
-			/*
-			 * Probably not a shared PCI interrupt,
-			 * so we can safely try to do something about it:
-			 */
-			unexpected_intr(irq, hwgroup);
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		} else {
-			/*
-			 * Whack the status register, just in case we have a leftover pending IRQ.
-			 */
-			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-		}
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	drive = hwgroup->drive;
-	if (!drive) {
-		/*
-		 * This should NEVER happen, and there isn't much we could do about it here.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!drive_is_ready(drive)) {
-		/*
-		 * This happens regularly when we share a PCI IRQ with another device.
-		 * Unfortunately, it can also happen with some buggy drives that trigger
-		 * the IRQ before their status register is up to date.  Hopefully we have
-		 * enough advance overhead that the latter isn't a problem.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!hwgroup->busy) {
-		hwgroup->busy = 1;	/* paranoia */
-		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
-	}
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock(&io_request_lock);
-
-	if (drive->unmask)
-		ide__sti();	/* local CPU only */
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
-	spin_lock_irq(&io_request_lock);
-
-	/*
-	 * Note that handler() may have set things up for another
-	 * interrupt to occur soon, but it cannot happen until
-	 * we exit from this routine, because it will be the
-	 * same irq as is currently being serviced here, and Linux
-	 * won't allow another of the same (on any CPU) until we return.
-	 */
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
-	if (startstop == ide_stopped) {
-		if (hwgroup->handler == NULL) {	/* paranoia */
-			hwgroup->busy = 0;
-			ide_do_request(hwgroup, hwif->irq);
-		} else {
-			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
-		}
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	idebus_parameter = 0;
+	system_bus_speed = 0;
 }
 
 /*
- * get_info_ptr() returns the (ide_drive_t *) for a given device number.
- * It returns NULL if the given device number does not match any present drives.
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev)
+int ide_system_bus_speed (void)
 {
-	int		major = MAJOR(i_rdev);
-#if 0
-	int		minor = MINOR(i_rdev) & PARTN_MASK;
-#endif
-	unsigned int	h;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_hwif_t  *hwif = &ide_hwifs[h];
-		if (hwif->present && major == hwif->major) {
-			unsigned unit = DEVICE_NR(i_rdev);
-			if (unit < MAX_DRIVES) {
-				ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-				if ((drive->present) && (drive->part[minor].nr_sects))
-#else
-				if (drive->present)
-#endif
-					return drive;
-			}
-			break;
+	if (!system_bus_speed) {
+		if (idebus_parameter) {
+			/* user supplied value */
+			system_bus_speed = idebus_parameter;
+		} else if (pci_present()) {
+			/* safe default value for PCI */
+			system_bus_speed = 33;
+		} else {
+			/* safe default value for VESA and PCI */
+			system_bus_speed = 50;
 		}
+		printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+			"for PIO modes%s\n", system_bus_speed,
+			idebus_parameter ? "" : "; override with idebus=xx");
 	}
-	return NULL;
+	return system_bus_speed;
 }
 
 /*
- * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ * current_capacity() returns the capacity (in sectors) of a drive
+ * according to its current geometry/LBA settings.
  */
-void ide_init_drive_cmd (struct request *rq)
+unsigned long current_capacity (ide_drive_t *drive)
+{
+	if (!drive->present)
+		return 0;
+	return DRIVER(drive)->capacity(drive);
+}
+
+EXPORT_SYMBOL(current_capacity);
+
+static inline u32 read_24 (ide_drive_t *drive)
 {
-	memset(rq, 0, sizeof(*rq));
-	rq->cmd = IDE_DRIVE_CMD;
+	return  (HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
 /*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned int major = HWIF(drive)->major;
-	struct list_head *queue_head = &drive->queue.queue_head;
-	DECLARE_COMPLETION(wait);
+	u8 err = 0;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
-		return -ENOSYS;  /* special drive cmds not supported */
-#endif
-	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
-	if (action == ide_wait)
-		rq->waiting = &wait;
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (list_empty(queue_head) || action == ide_preempt) {
-		if (action == ide_preempt)
-			hwgroup->rq = NULL;
+	local_irq_set(flags);
+	printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT) {
+		printk("Busy ");
 	} else {
-		if (action == ide_wait || action == ide_end) {
-			queue_head = queue_head->prev;
-		} else
-			queue_head = queue_head->next;
-	}
-	list_add(&rq->queue, queue_head);
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	if (action == ide_wait) {
-		wait_for_completion(&wait);	/* wait for it to be serviced */
-		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+		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 ");
 	}
-	return 0;
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = hwif->INB(IDE_ERROR_REG);
+		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("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+			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 high = 0;
+					u32 low = read_24(drive);
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
 
+					sectors = ((u64)high << 24) | low;
+					printk(", LBAsect=%llu, high=%d, low=%d",
+					       (u64) sectors,
+					       high, low);
+				} else {
+					u8 cur = hwif->INB(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(hwif->INB(IDE_HCYL_REG)<<16)
+						 |(hwif->INB(IDE_LCYL_REG)<<8)
+						 | hwif->INB(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (hwif->INB(IDE_HCYL_REG)<<8) +
+						  hwif->INB(IDE_LCYL_REG),
+						  cur & 0xf,
+						  hwif->INB(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive) && HWGROUP(drive)->rq)
+					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return err;
 }
 
+EXPORT_SYMBOL(ide_dump_status);
+
+
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -2058,7 +490,9 @@
 	return 0;
 }
 
-static void revalidate_drives (void)
+EXPORT_SYMBOL(ide_revalidate_disk);
+
+static void revalidate_drives (int revaldiate)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
@@ -2070,26 +504,28 @@
 			drive = &ide_hwifs[index].drives[unit];
 			if (drive->revalidate) {
 				drive->revalidate = 0;
-				if (!initializing)
+				if ((!initializing) && (revaldiate))
 					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
 }
 
-static void ide_probe_module (void)
+void ide_probe_module (int revaldiate)
 {
 	if (!ide_probe) {
-#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if  defined(CONFIG_BLK_DEV_IDE_MODULE)
 		(void) request_module("ide-probe-mod");
-#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif
 	} else {
 		(void) ide_probe->init();
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
-static void ide_driver_module (void)
+EXPORT_SYMBOL(ide_probe_module);
+
+void ide_driver_module (int revaldiate)
 {
 	int index;
 	ide_module_t *module = ide_modules;
@@ -2097,45 +533,46 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present)
 			goto search;
-	ide_probe_module();
+	ide_probe_module(revaldiate);
 search:
 	while (module) {
 		(void) module->init();
 		module = module->next;
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
+EXPORT_SYMBOL(ide_driver_module);
+
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
-	if (drive->driver == NULL)
-		ide_driver_module();
-#ifdef CONFIG_KMOD
-	if (drive->driver == NULL) {
+	if (drive->driver == &idedefault_driver)
+		ide_driver_module(1);
+	if (drive->driver == &idedefault_driver) {
 		if (drive->media == ide_disk)
 			(void) request_module("ide-disk");
+		if (drive->scsi)
+			(void) request_module("ide-scsi");
 		if (drive->media == ide_cdrom)
 			(void) request_module("ide-cd");
 		if (drive->media == ide_tape)
 			(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 */
+	
+	/* The locking here isnt enough, but this is hard to fix
+	   in the 2.4 cases */
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
 	drive->usage++;
-	if (drive->driver != NULL)
+	if (!drive->dead)
 		return DRIVER(drive)->open(inode, filp, drive);
-	printk ("%s: driver not present\n", drive->name);
+	printk(KERN_WARNING "%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
 }
@@ -2150,28 +587,11 @@
 
 	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
 		drive->usage--;
-		if (drive->driver != NULL)
-			DRIVER(drive)->release(inode, file, drive);
+		DRIVER(drive)->release(inode, file, drive);
 	}
 	return 0;
 }
 
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->busy || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	ide_driver_module();
-	drive->driver_req[0] = 0;
-	ide_driver_module();
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
 #ifdef CONFIG_PROC_FS
 ide_proc_entry_t generic_subdriver_entries[] = {
 	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
@@ -2179,6 +599,10 @@
 };
 #endif
 
+
+#define hwif_release_region(addr, num) \
+	((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
+
 /*
  * Note that we only release the standard ports,
  * and do not even try to handle any extra ports
@@ -2186,36 +610,33 @@
  */
 void hwif_unregister (ide_hwif_t *hwif)
 {
-	if (hwif->straight8) {
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-		goto jump_eight;
-	}
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
+	u32 i = 0;
+
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+
+	if (hwif->straight8) {
+		hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		return;
+	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		if (hwif->io_ports[i]) {
+			hwif_release_region(hwif->io_ports[i], 1);
+		}
+	}
 }
 
-void ide_unregister (unsigned int index)
+EXPORT_SYMBOL(hwif_unregister);
+
+extern void init_hwif_data(unsigned int index);
+
+int ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
 	ide_drive_t *drive, *d;
@@ -2227,9 +648,9 @@
 	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
-		return;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+		BUG();
+		
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
@@ -2239,7 +660,7 @@
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		if (DRIVER(drive)->shutdown(drive))
 			goto abort;
 	}
 	hwif->present = 0;
@@ -2247,11 +668,12 @@
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
-	sti();
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
+		DRIVER(drive)->cleanup(drive);
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
@@ -2263,7 +685,8 @@
 		destroy_proc_ide_drives(hwif);
 #endif
 	}
-	cli();
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwgroup = hwif->hwgroup;
 
 	/*
@@ -2293,7 +716,7 @@
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
 		if (drive->de) {
-			devfs_unregister (drive->de);
+			devfs_unregister(drive->de);
 			drive->de = NULL;
 		}
 		if (!drive->present)
@@ -2320,12 +743,19 @@
 	else
 		hwgroup->hwif = HWIF(hwgroup->drive);
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#if !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
 		(void) ide_release_dma(hwif);
+
 		hwif->dma_base = 0;
+		hwif->dma_master = 0;
+		hwif->dma_command = 0;
+		hwif->dma_vendor1 = 0;
+		hwif->dma_status = 0;
+		hwif->dma_vendor3 = 0;
+		hwif->dma_prdtable = 0;
 	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 
 	/*
 	 * Remove us from the kernel's knowledge
@@ -2343,49 +773,137 @@
 		kfree(gd->sizes);
 		kfree(gd->part);
 		if (gd->de_arr)
-			kfree (gd->de_arr);
+			kfree(gd->de_arr);
 		if (gd->flags)
-			kfree (gd->flags);
+			kfree(gd->flags);
 		kfree(gd);
 		hwif->gd = NULL;
 	}
-	old_hwif		= *hwif;
-	init_hwif_data (index);	/* restore hwif data to pristine status */
-	hwif->hwgroup		= old_hwif.hwgroup;
-	hwif->tuneproc		= old_hwif.tuneproc;
-	hwif->speedproc		= old_hwif.speedproc;
-	hwif->selectproc	= old_hwif.selectproc;
-	hwif->resetproc		= old_hwif.resetproc;
-	hwif->intrproc		= old_hwif.intrproc;
-	hwif->maskproc		= old_hwif.maskproc;
-	hwif->quirkproc		= old_hwif.quirkproc;
-	hwif->rwproc		= old_hwif.rwproc;
-	hwif->ideproc		= old_hwif.ideproc;
-	hwif->dmaproc		= old_hwif.dmaproc;
-	hwif->busproc		= old_hwif.busproc;
-	hwif->bus_state		= old_hwif.bus_state;
-	hwif->dma_base		= old_hwif.dma_base;
-	hwif->dma_extra		= old_hwif.dma_extra;
-	hwif->config_data	= old_hwif.config_data;
-	hwif->select_data	= old_hwif.select_data;
-	hwif->proc		= old_hwif.proc;
-#ifndef CONFIG_BLK_DEV_IDECS
-	hwif->irq		= old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
-	hwif->major		= old_hwif.major;
-	hwif->chipset		= old_hwif.chipset;
-	hwif->autodma		= old_hwif.autodma;
-	hwif->udma_four		= old_hwif.udma_four;
+
+	old_hwif			= *hwif;
+	init_hwif_data(index);	/* restore hwif data to pristine status */
+	hwif->hwgroup			= old_hwif.hwgroup;
+
+	hwif->proc			= old_hwif.proc;
+
+	hwif->major			= old_hwif.major;
+//	hwif->index			= old_hwif.index;
+//	hwif->channel			= old_hwif.channel;
+	hwif->straight8			= old_hwif.straight8;
+	hwif->bus_state			= old_hwif.bus_state;
+
+	hwif->atapi_dma			= old_hwif.atapi_dma;
+	hwif->ultra_mask		= old_hwif.ultra_mask;
+	hwif->mwdma_mask		= old_hwif.mwdma_mask;
+	hwif->swdma_mask		= old_hwif.swdma_mask;
+
+	hwif->chipset			= old_hwif.chipset;
+
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	hwif->pci_dev		= old_hwif.pci_dev;
-	hwif->pci_devid		= old_hwif.pci_devid;
+	hwif->pci_dev			= old_hwif.pci_dev;
+	hwif->cds			= old_hwif.cds;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
-	hwif->straight8		= old_hwif.straight8;
-	hwif->hwif_data		= old_hwif.hwif_data;
+
+#if 0
+	hwif->hwifops			= old_hwif.hwifops;
+#else
+	hwif->identify			= old_hwif.identify;
+	hwif->tuneproc			= old_hwif.tuneproc;
+	hwif->speedproc			= old_hwif.speedproc;
+	hwif->selectproc		= old_hwif.selectproc;
+	hwif->reset_poll		= old_hwif.reset_poll;
+	hwif->pre_reset			= old_hwif.pre_reset;
+	hwif->resetproc			= old_hwif.resetproc;
+	hwif->intrproc			= old_hwif.intrproc;
+	hwif->maskproc			= old_hwif.maskproc;
+	hwif->quirkproc			= old_hwif.quirkproc;
+	hwif->busproc			= old_hwif.busproc;
+#endif
+
+#if 0
+	hwif->pioops			= old_hwif.pioops;
+#else
+	hwif->ata_input_data		= old_hwif.ata_input_data;
+	hwif->ata_output_data		= old_hwif.ata_output_data;
+	hwif->atapi_input_bytes		= old_hwif.atapi_input_bytes;
+	hwif->atapi_output_bytes	= old_hwif.atapi_output_bytes;
+#endif
+
+#if 0
+	hwif->dmaops			= old_hwif.dmaops;
+#else
+	hwif->ide_dma_read		= old_hwif.ide_dma_read;
+	hwif->ide_dma_write		= old_hwif.ide_dma_write;
+	hwif->ide_dma_begin		= old_hwif.ide_dma_begin;
+	hwif->ide_dma_end		= old_hwif.ide_dma_end;
+	hwif->ide_dma_check		= old_hwif.ide_dma_check;
+	hwif->ide_dma_on		= old_hwif.ide_dma_on;
+	hwif->ide_dma_off		= old_hwif.ide_dma_off;
+	hwif->ide_dma_off_quietly	= old_hwif.ide_dma_off_quietly;
+	hwif->ide_dma_test_irq		= old_hwif.ide_dma_test_irq;
+	hwif->ide_dma_host_on		= old_hwif.ide_dma_host_on;
+	hwif->ide_dma_host_off		= old_hwif.ide_dma_host_off;
+	hwif->ide_dma_bad_drive		= old_hwif.ide_dma_bad_drive;
+	hwif->ide_dma_good_drive	= old_hwif.ide_dma_good_drive;
+	hwif->ide_dma_count		= old_hwif.ide_dma_count;
+	hwif->ide_dma_verbose		= old_hwif.ide_dma_verbose;
+	hwif->ide_dma_retune		= old_hwif.ide_dma_retune;
+	hwif->ide_dma_lostirq		= old_hwif.ide_dma_lostirq;
+	hwif->ide_dma_timeout		= old_hwif.ide_dma_timeout;
+#endif
+
+#if 0
+	hwif->iops			= old_hwif.iops;
+#else
+	hwif->OUTB		= old_hwif.OUTB;
+	hwif->OUTBSYNC		= old_hwif.OUTBSYNC;
+	hwif->OUTW		= old_hwif.OUTW;
+	hwif->OUTL		= old_hwif.OUTL;
+	hwif->OUTSW		= old_hwif.OUTSW;
+	hwif->OUTSL		= old_hwif.OUTSL;
+
+	hwif->INB		= old_hwif.INB;
+	hwif->INW		= old_hwif.INW;
+	hwif->INL		= old_hwif.INL;
+	hwif->INSW		= old_hwif.INSW;
+	hwif->INSL		= old_hwif.INSL;
+#endif
+
+	hwif->mmio			= old_hwif.mmio;
+	hwif->rqsize			= old_hwif.rqsize;
+	hwif->addressing		= old_hwif.addressing;
+#ifndef CONFIG_BLK_DEV_IDECS
+	hwif->irq			= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
+	hwif->initializing		= old_hwif.initializing;
+
+	hwif->dma_base			= old_hwif.dma_base;
+	hwif->dma_master		= old_hwif.dma_master;
+	hwif->dma_command		= old_hwif.dma_command;
+	hwif->dma_vendor1		= old_hwif.dma_vendor1;
+	hwif->dma_status		= old_hwif.dma_status;
+	hwif->dma_vendor3		= old_hwif.dma_vendor3;
+	hwif->dma_prdtable		= old_hwif.dma_prdtable;
+
+	hwif->dma_extra			= old_hwif.dma_extra;
+	hwif->config_data		= old_hwif.config_data;
+	hwif->select_data		= old_hwif.select_data;
+	hwif->autodma			= old_hwif.autodma;
+	hwif->udma_four			= old_hwif.udma_four;
+	hwif->no_dsc			= old_hwif.no_dsc;
+
+	hwif->hwif_data			= old_hwif.hwif_data;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+
 abort:
-	restore_flags(flags);	/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 1;
+	
 }
 
+EXPORT_SYMBOL(ide_unregister);
+
 /*
  * Setup hw_regs_t structure described by parameters.  You
  * may set up the hw structure yourself OR use this routine to
@@ -2394,7 +912,11 @@
 void ide_setup_ports (	hw_regs_t *hw,
 			ide_ioreg_t base, int *offsets,
 			ide_ioreg_t ctrl, ide_ioreg_t intr,
-			ide_ack_intr_t *ack_intr, int irq)
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
 {
 	int i;
 
@@ -2420,8 +942,13 @@
 	hw->irq = irq;
 	hw->dma = NO_DMA;
 	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
 }
 
+EXPORT_SYMBOL(ide_setup_ports);
+
 /*
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
@@ -2439,8 +966,8 @@
 		}
 		for (index = 0; index < MAX_HWIFS; ++index) {
 			hwif = &ide_hwifs[index];
-			if ((!hwif->present && !hwif->mate && !initializing) ||
-			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
+			if (!hwif->hold && ((!hwif->present && !hwif->mate && !initializing) ||
+			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)))
 				goto found;
 		}
 		for (index = 0; index < MAX_HWIFS; index++)
@@ -2450,6 +977,8 @@
 found:
 	if (hwif->present)
 		ide_unregister(index);
+	else if (!hwif->hold)
+		init_hwif_data(index);
 	if (hwif->present)
 		return -1;
 	memcpy(&hwif->hw, hw, sizeof(*hw));
@@ -2459,11 +988,11 @@
 	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
-		ide_probe_module();
+		ide_probe_module(1);
 #ifdef CONFIG_PROC_FS
 		create_proc_ide_interfaces();
 #endif
-		ide_driver_module();
+		ide_driver_module(1);
 	}
 
 	if (hwifp)
@@ -2472,6 +1001,8 @@
 	return (initializing || hwif->present) ? index : -1;
 }
 
+EXPORT_SYMBOL(ide_register_hw);
+
 /*
  * Compatability function with existing drivers.  If you want
  * something different, use the function above.
@@ -2484,10 +1015,47 @@
 	return ide_register_hw(&hw, NULL);
 }
 
-void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+EXPORT_SYMBOL(ide_register);
+
+
+/*
+ *	Locks for IDE setting functionality
+ */
+
+DECLARE_MUTEX(ide_setting_sem);
+EXPORT_SYMBOL(ide_setting_sem);
+
+/**
+ *	ide_add_setting	-	add an ide setting option
+ *	@drive: drive to use
+ *	@name: setting name
+ *	@rw: true if the function is read write
+ *	@read_ioctl: function to call on read
+ *	@write_ioctl: function to call on write
+ *	@data_type: type of data
+ *	@min: range minimum
+ *	@max: range maximum
+ *	@mul_factor: multiplication scale
+ *	@div_factor: divison scale
+ *	@data: private data field
+ *	@set: setting
+ *
+ *	Removes the setting named from the device if it is present.
+ *	The function takes the settings_lock to protect against 
+ *	parallel changes. This function must not be called from IRQ
+ *	context. Returns 0 on success or -1 on failure.
+ *
+ *	BUGS: This code is seriously over-engineered. There is also
+ *	magic about how the driver specific features are setup. If
+ *	a driver is attached we assume the driver settings are auto
+ *	remove.
+ */
+ 
+int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
+	down(&ide_setting_sem);
 	while ((*p) && strcmp((*p)->name, name) < 0)
 		p = &((*p)->next);
 	if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
@@ -2495,34 +1063,89 @@
 	memset(setting, 0, sizeof(*setting));
 	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
 		goto abort;
-	strcpy(setting->name, name);		setting->rw = rw;
-	setting->read_ioctl = read_ioctl;	setting->write_ioctl = write_ioctl;
-	setting->data_type = data_type;		setting->min = min;
-	setting->max = max;			setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;	setting->data = data;
-	setting->set = set;			setting->next = *p;
-	if (drive->driver)
+	strcpy(setting->name, name);
+	setting->rw = rw;
+	setting->read_ioctl = read_ioctl;
+	setting->write_ioctl = write_ioctl;
+	setting->data_type = data_type;
+	setting->min = min;
+	setting->max = max;
+	setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;
+	setting->data = data;
+	setting->set = set;
+	
+	setting->next = *p;
+	if (drive->driver != &idedefault_driver)
 		setting->auto_remove = 1;
 	*p = setting;
-	return;
+	up(&ide_setting_sem);
+	return 0;
 abort:
+	up(&ide_setting_sem);
 	if (setting)
 		kfree(setting);
+	return -1;
 }
 
-void ide_remove_setting (ide_drive_t *drive, char *name)
+EXPORT_SYMBOL(ide_add_setting);
+
+/**
+ *	__ide_remove_setting	-	remove an ide setting option
+ *	@drive: drive to use
+ *	@name: setting name
+ *
+ *	Removes the setting named from the device if it is present.
+ *	The caller must hold the setting semaphore.
+ */
+ 
+static void __ide_remove_setting (ide_drive_t *drive, char *name)
 {
-	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
+	ide_settings_t **p, *setting;
+
+	p = (ide_settings_t **) &drive->settings;
 
 	while ((*p) && strcmp((*p)->name, name))
 		p = &((*p)->next);
 	if ((setting = (*p)) == NULL)
 		return;
+
 	(*p) = setting->next;
+	
 	kfree(setting->name);
 	kfree(setting);
 }
 
+/**
+ *	ide_remove_setting	-	remove an ide setting option
+ *	@drive: drive to use
+ *	@name: setting name
+ *
+ *	Removes the setting named from the device if it is present.
+ *	The function takes the settings_lock to protect against 
+ *	parallel changes. This function must not be called from IRQ
+ *	context.
+ */
+ 
+void ide_remove_setting (ide_drive_t *drive, char *name)
+{
+	down(&ide_setting_sem);
+	__ide_remove_setting(drive, name);
+	up(&ide_setting_sem);
+}
+
+EXPORT_SYMBOL(ide_remove_setting);
+
+/**
+ *	ide_find_setting_by_ioctl	-	find a drive specific ioctl
+ *	@drive: drive to scan
+ *	@cmd: ioctl command to handle
+ *
+ *	Scan's the device setting table for a matching entry and returns
+ *	this or NULL if no entry is found. The caller must hold the
+ *	setting semaphore
+ */
+ 
 static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
 {
 	ide_settings_t *setting = drive->settings;
@@ -2532,9 +1155,20 @@
 			break;
 		setting = setting->next;
 	}
+	
 	return setting;
 }
 
+/**
+ *	ide_find_setting_by_name	-	find a drive specific setting
+ *	@drive: drive to scan
+ *	@name: setting name
+ *
+ *	Scan's the device setting table for a matching entry and returns
+ *	this or NULL if no entry is found. The caller must hold the
+ *	setting semaphore
+ */
+ 
 ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
 {
 	ide_settings_t *setting = drive->settings;
@@ -2547,6 +1181,15 @@
 	return setting;
 }
 
+/**
+ *	auto_remove_settings	-	remove driver specific settings
+ *	@drive: drive
+ *
+ *	Automatically remove all the driver specific settings for this
+ *	drive. This function may sleep and must not be called from IRQ
+ *	context. Caller must hold the setting lock.
+ */
+ 
 static void auto_remove_settings (ide_drive_t *drive)
 {
 	ide_settings_t *setting;
@@ -2554,13 +1197,26 @@
 	setting = drive->settings;
 	while (setting) {
 		if (setting->auto_remove) {
-			ide_remove_setting(drive, setting->name);
+			__ide_remove_setting(drive, setting->name);
 			goto repeat;
 		}
 		setting = setting->next;
 	}
 }
 
+/**
+ *	ide_read_setting	-	read an IDE setting
+ *	@drive: drive to read from
+ *	@setting: drive setting
+ *
+ *	Read a drive setting and return the value. The caller
+ *	must hold the ide_setting_sem when making this call.
+ *
+ *	BUGS: the data return and error are the same return value
+ *	so an error -EINVAL and true return of the same value cannot
+ *	be told apart
+ */
+ 
 int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
 {
 	int		val = -EINVAL;
@@ -2595,23 +1251,36 @@
 	while (hwgroup->busy) {
 		unsigned long lflags;
 		spin_unlock_irq(&io_request_lock);
-		__save_flags(lflags);	/* local CPU only */
-		__sti();		/* local CPU only; needed for jiffies */
-		if (0 < (signed long)(jiffies - timeout)) {
-			__restore_flags(lflags);	/* local CPU only */
-			printk("%s: channel busy\n", drive->name);
+		local_irq_set(lflags);
+		if (time_after(jiffies, timeout)) {
+			local_irq_restore(lflags);
+			printk(KERN_ERR "%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		__restore_flags(lflags);	/* local CPU only */
+		local_irq_restore(lflags);
 		spin_lock_irq(&io_request_lock);
 	}
 	return 0;
 }
 
-/*
- * FIXME:  This should be changed to enqueue a special request
- * to the driver to change settings, and then wait on a sema for completion.
- * The current scheme of polling is kludgey, though safe enough.
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+
+/**
+ *	ide_write_setting	-	read an IDE setting
+ *	@drive: drive to read from
+ *	@setting: drive setting
+ *	@val: value
+ *
+ *	Write a drive setting if it is possible. The caller
+ *	must hold the ide_setting_sem when making this call.
+ *
+ *	BUGS: the data return and error are the same return value
+ *	so an error -EINVAL and true return of the same value cannot
+ *	be told apart
+ *
+ *	FIXME:  This should be changed to enqueue a special request
+ *	to the driver to change settings, and then wait on a sema for completion.
+ *	The current scheme of polling is kludgy, though safe enough.
  */
 int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
 {
@@ -2648,6 +1317,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_write_setting);
+
 static int set_io_32bit(ide_drive_t *drive, int arg)
 {
 	drive->io_32bit = arg;
@@ -2660,12 +1331,21 @@
 
 static int set_using_dma (ide_drive_t *drive, int arg)
 {
-	if (!drive->driver || !DRIVER(drive)->supports_dma)
+	if (!DRIVER(drive)->supports_dma)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+	if (!(drive->id->capability & 1))
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+	if (HWIF(drive)->ide_dma_check == NULL)
+		return -EPERM;
+	if (HWIF(drive)->ide_dma_check(drive) != 0)
 		return -EIO;
+	if (arg) {
+		if (HWIF(drive)->ide_dma_check(drive) != 0)
+			return -EIO;
+		if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+	} else {
+		if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
+	}
 	return 0;
 }
 
@@ -2678,9 +1358,37 @@
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
-	drive->tune_req = (byte) arg;
+	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+	return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+	int err = ide_wait_cmd(drive,
+			WIN_SETFEATURES, (u8) arg,
+			SETFEATURES_XFER, 0, NULL);
+
+	if (!err && arg) {
+		ide_set_xfer_rate(drive, (u8) arg);
+		ide_driveid_update(drive);
+	}
+	return err;
+}
+
+int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
+{
+	if (drive->media == ide_disk) {
+		drive->scsi = 0;
+		return 0;
+	}
+	if (DRIVER(drive)->cleanup(drive)) {
+		drive->scsi = 0;
+		return 0;
+	}
+	drive->scsi = (u8) arg;
+	ide_attach_drive(drive);
 	return 0;
 }
 
@@ -2696,37 +1404,14 @@
 	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
 	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
 	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"ide_scsi",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			NULL);
-	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->current_speed,		NULL);
+	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
+	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
 	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
-}
-
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
-{
-	struct request rq;
-	byte buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.cmd = IDE_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+#if 0
+	/* Experimental, but this needs the setting/register locking rewritten to be used */	
+	if (drive->media != ide_disk)
+		ide_add_setting(drive,	"ide-scsi",		SETTING_RW,					-1,		HDIO_SET_IDE_SCSI,		TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			ide_atapi_to_scsi);
+#endif		
 }
 
 /*
@@ -2743,23 +1428,57 @@
 	mdelay(50);
 #else
 	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/20);
+	schedule_timeout(1+HZ/20);
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
+EXPORT_SYMBOL(ide_delay_50ms);
+
 int system_bus_clock (void)
 {
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
-int ide_reinit_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(system_bus_clock);
+
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->busy || drive->usage || drive->dead)
+		goto abort;
+	if (DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	ide_driver_module(0);
+	drive->driver_req[0] = 0;
+	ide_driver_module(0);
+	if (!strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_replace_subdriver);
+
+int ide_attach_drive (ide_drive_t *drive)
 {
+	/* Someone unplugged the device on us */
+	if(drive->dead)
+		return 1;
+		
+#ifdef CONFIG_BLK_DEV_IDESCSI
+	if (drive->scsi) {
+		extern int idescsi_attach(ide_drive_t *drive);
+		if (idescsi_attach(drive))
+			return 0;
+	}
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+
 	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))
+			extern int ide_cdrom_attach(ide_drive_t *drive);
+			if (ide_cdrom_attach(drive))
 				return 1;
 			break;
 		}
@@ -2767,8 +1486,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDISK
 		case ide_disk:
 		{
-			extern int idedisk_reinit(ide_drive_t *drive);
-			if (idedisk_reinit(drive))
+			extern int idedisk_attach(ide_drive_t *drive);
+			if (idedisk_attach(drive))
 				return 1;
 			break;
 		}
@@ -2776,8 +1495,8 @@
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
 		case ide_floppy:
 		{
-			extern int idefloppy_reinit(ide_drive_t *drive);
-			if (idefloppy_reinit(drive))
+			extern int idefloppy_attach(ide_drive_t *drive);
+			if (idefloppy_attach(drive))
 				return 1;
 			break;
 		}
@@ -2785,28 +1504,25 @@
 #ifdef CONFIG_BLK_DEV_IDETAPE
 		case ide_tape:
 		{
-			extern int idetape_reinit(ide_drive_t *drive);
-			if (idetape_reinit(drive))
+			extern int idetape_attach(ide_drive_t *drive);
+			if (idetape_attach(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:
+		{
+			extern int idedefault_attach(ide_drive_t *drive);
+			if(idedefault_attach(drive))
+				printk(KERN_CRIT "ide: failed to attach default driver.\n");
 			return 1;
+		}
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_attach_drive);
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2822,27 +1538,33 @@
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 
+	down(&ide_setting_sem);
 	if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
 		if (cmd == setting->read_ioctl) {
 			err = ide_read_setting(drive, setting);
+			up(&ide_setting_sem);
 			return err >= 0 ? put_user(err, (long *) arg) : err;
 		} else {
 			if ((MINOR(inode->i_rdev) & PARTN_MASK))
-				return -EINVAL;
-			return ide_write_setting(drive, setting, arg);
+				err = -EINVAL;
+			else 
+				err = ide_write_setting(drive, setting, arg);
+			up(&ide_setting_sem);
+			return err;
 		}
 	}
+	up(&ide_setting_sem);
 
 	ide_init_drive_cmd (&rq);
 	switch (cmd) {
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+			u16 bios_cyl = drive->bios_cyl; /* truncate */
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2852,8 +1574,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2864,8 +1586,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2885,7 +1607,7 @@
 		case HDIO_GET_IDENTITY:
 			if (MINOR(inode->i_rdev) & PARTN_MASK)
 				return -EINVAL;
-			if (drive->id == NULL)
+			if (drive->id_read == 0)
 				return -ENOMSG;
 			if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
 				return -EFAULT;
@@ -2918,72 +1640,19 @@
 #endif /* CONFIG_IDE_TASK_IOCTL */
 
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			ide_task_t tfargs;
-
 			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;
-
-			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);
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
 
-			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;
-		}
 		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];
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!capable(CAP_SYS_RAWIO)) return -EACCES;
 			if (copy_from_user(args, (void *)arg, 3 * sizeof(int)))
 				return -EFAULT;
 			if (ide_register(args[0], args[1], args[2]) == -1)
@@ -2991,14 +1660,12 @@
 			return 0;
 		}
 	        case HDIO_UNREGISTER_HWIF:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!capable(CAP_SYS_RAWIO)) return -EACCES;
 			/* (arg > MAX_HWIFS) checked in function */
 			ide_unregister(arg);
 			return 0;
 		case HDIO_SET_NICE:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (drive->driver == NULL)
-				return -EPERM;
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
@@ -3011,22 +1678,28 @@
 		case HDIO_DRIVE_RESET:
 		{
 			unsigned long flags;
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-#if 1
+			
+			/*
+			 *	Abort the current command on the
+			 *	group if there is one, taking
+			 *	care not to allow anything else
+			 *	to be queued and to die on the
+			 *	spot if we miss one somehow
+			 */
+
 			spin_lock_irqsave(&io_request_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);
-			}
+			
+			DRIVER(drive)->abort(drive, "drive reset");
+			if(HWGROUP(drive)->handler)
+				BUG();
+				
+			/* Ensure nothing gets queued after we
+			   drop the lock. Reset will clear the busy */
+			   
+			HWGROUP(drive)->busy = 1;
 			spin_unlock_irqrestore(&io_request_lock, flags);
 
-#endif
 			(void) ide_do_reset(drive);
 			if (drive->suspend_reset) {
 /*
@@ -3064,12 +1737,11 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(drive, (int)arg);
-			return 0;
+				return HWIF(drive)->busproc(drive, (int)arg);
+			return -EOPNOTSUPP;
 
 		default:
-			if (drive->driver != NULL)
-				return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
+			return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
 			return -EPERM;
 	}
 }
@@ -3080,36 +1752,7 @@
 
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->media_change(drive);
-	return 0;
-}
-
-void ide_fixstring (byte *s, const int bytecount, const int byteswap)
-{
-	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-	if (byteswap) {
-		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;) {
-			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = ntohs(*pp);
-		}
-	}
-
-	/* strip leading blanks */
-	while (s != end && *s == ' ')
-		++s;
-
-	/* compress internal blanks and strip trailing blanks */
-	while (s != end && *s) {
-		if (*s++ != ' ' || (s != end && *s && *s != ' '))
-			*p++ = *(s-1);
-	}
-
-	/* wipe out trailing garbage */
-	while (p != end)
-		*p++ = '\0';
+	return DRIVER(drive)->media_change(drive);
 }
 
 /*
@@ -3274,7 +1917,7 @@
 	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
 		return 0;
 
-	printk("ide_setup: %s", s);
+	printk(KERN_INFO "ide_setup: %s", s);
 	init_ide_data ();
 
 #ifdef CONFIG_BLK_DEV_IDEDOUBLER
@@ -3288,7 +1931,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
 
 	if (!strcmp(s, "ide=nodma")) {
-		printk("IDE: Prevented DMA\n");
+		printk(" : Prevented DMA\n");
 		noautodma = 1;
 		return 1;
 	}
@@ -3418,7 +2061,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,10 +2080,6 @@
 		}
 
 		switch (i) {
-			case -19: /* nohighio */
-				hwif->no_highio = 1;
-				printk("%s: disabled high i/o capability\n", hwif->name);
-				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -3580,21 +2219,12 @@
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_BLK_DEV_IDEPCI
 	if (pci_present())
 	{
-#ifdef CONFIG_BLK_DEV_IDEPCI
 		ide_scan_pcibus(ide_scan_direction);
-#else
-#ifdef CONFIG_BLK_DEV_RZ1000
-		{
-			extern void ide_probe_for_rz100x(void);
-			ide_probe_for_rz100x();
-		}
-#endif /* CONFIG_BLK_DEV_RZ1000 */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -3676,39 +2306,9 @@
 #endif /* CONFIG_BLK_DEV_ISAPNP */
 }
 
-void __init ide_init_builtin_drivers (void)
+void __init ide_init_builtin_subdrivers (void)
 {
-	/*
-	 * Probe for special PCI and other "known" interface chipsets
-	 */
-	probe_for_hwifs ();
-
-#ifdef CONFIG_BLK_DEV_IDE
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_lock, NULL, NULL);	/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-
-	(void) ideprobe_init();
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_lock);	/* for atari only */
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-#endif /* CONFIG_BLK_DEV_IDE */
-
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
-	/*
-	 * Attempt to match drivers for the available drives
-	 */
+	idedefault_init();
 #ifdef CONFIG_BLK_DEV_IDEDISK
 	(void) idedisk_init();
 #endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -3730,32 +2330,135 @@
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 }
 
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+/*
+ * Attempt to match drivers for the available drives
+ */
+void ide_attach_devices (void)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	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 && !drive->dead)
+				ide_attach_drive(drive);
+		}
+	}
+}
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+
+void __init ide_init_builtin_drivers (void)
+{
+	/*
+	 * Probe for special PCI and other "known" interface chipsets
+	 */
+	probe_for_hwifs ();
+
+#ifdef CONFIG_BLK_DEV_IDE
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_get_lock(NULL, NULL); /* for atari only */
+
+	(void) ideprobe_init();
+
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_release_lock();	/* for atari only */
+#endif /* CONFIG_BLK_DEV_IDE */
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_create();
+#endif
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+	ide_attach_devices();
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+}
+
+/*
+ *	Actually unregister the subdriver. Called with the
+ *	request lock dropped.
+ */
+ 
 static int default_cleanup (ide_drive_t *drive)
 {
 	return ide_unregister_subdriver(drive);
 }
 
+/*
+ *	Check if we can unregister the subdriver. Called with the
+ *	request lock held.
+ */
+ 
+static int default_shutdown(ide_drive_t *drive)
+{
+	if (drive->usage || drive->busy || DRIVER(drive)->busy) {
+		return 1;
+	}
+	drive->dead = 1;
+	return 0;
+}
+
 static int default_standby (ide_drive_t *drive)
 {
 	return 0;
 }
 
+static int default_suspend (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_resume (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)
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	ide_end_request(0, HWGROUP(drive));
+	ide_end_request(drive, 0);
 	return ide_stopped;
 }
- 
-static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+
+static int default_end_request (ide_drive_t *drive, int uptodate)
+{
+	return ide_end_request(drive, uptodate);
+}
+
+static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	return ide_dump_status(drive, msg, stat);
+}
+
+static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
-	ide_end_request(uptodate, hwgroup);
+	return ide_error(drive, msg, stat);
 }
-  
+
+static ide_startstop_t default_abort (ide_drive_t *drive, const char *msg)
+{
+	return ide_abort(drive, msg);
+}
+
 static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg)
 {
@@ -3795,9 +2498,15 @@
 	return ide_stopped;
 }
 
-static int default_reinit (ide_drive_t *drive)
+static int default_init (void)
 {
-	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
+	return 0;
+}
+
+static int default_attach (ide_drive_t *drive)
+{
+	printk(KERN_ERR "%s: does not support hotswap of device class !\n",
+		drive->name);
 
 	return 0;
 }
@@ -3807,10 +2516,16 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->shutdown == NULL)	d->shutdown = default_shutdown;
 	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->suspend == NULL)		d->suspend = default_suspend;
+	if (d->resume == NULL)		d->resume = default_resume;
 	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->sense == NULL)		d->sense = default_sense;
+	if (d->error == NULL)		d->error = default_error;
+	if (d->error == NULL)		d->abort = default_abort;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
 	if (d->open == NULL)		d->open = default_open;
 	if (d->release == NULL)		d->release = default_release;
@@ -3818,12 +2533,16 @@
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
-	if (d->reinit == NULL)		d->reinit = default_reinit;
+	if (d->init == NULL)		d->init = default_init;
+	if (d->attach == NULL)		d->attach = default_attach;
 }
 
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+ide_drive_t *ide_scan_devices (u8 media, const char *name, ide_driver_t *driver, int n)
 {
 	unsigned int unit, index, i;
+	
+	if(driver == NULL)	/* No driver is actually &idedefault_driver */
+		driver = &idedefault_driver;
 
 	for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
 		ide_hwif_t *hwif = &ide_hwifs[index];
@@ -3834,37 +2553,37 @@
 			char *req = drive->driver_req;
 			if (*req && !strstr(name, req))
 				continue;
-			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+			if (drive->present && drive->media == media &&
+			    drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
 	return NULL;
 }
 
+EXPORT_SYMBOL(ide_scan_devices);
+
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		restore_flags(flags);	/* all CPUs */
+	BUG_ON(drive->driver == NULL);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
+	    drive->driver != &idedefault_driver || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	drive->driver = driver;
 	setup_driver_defaults(drive);
-	restore_flags(flags);		/* all CPUs */
+	printk("%s: attached %s driver.\n", drive->name, driver->name);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	if (drive->autotune != 2) {
-		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
-			/*
-			 * Force DMAing for the beginning of the check.
-			 * Some chipsets appear to do interesting things,
-			 * if not checked and cleared.
-			 *   PARANOIA!!!
-			 */
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
-			(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
-		}
+		/* DMA timings and setup moved to ide-probe.c */
+		if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
+//			HWIF(drive)->ide_dma_off_quietly(drive);
+			HWIF(drive)->ide_dma_off(drive);
 		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
 		drive->nice1 = 1;
 	}
@@ -3877,14 +2596,17 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_subdriver);
+
 int ide_unregister_subdriver (ide_drive_t *drive)
 {
 	unsigned long flags;
-	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
-		restore_flags(flags);	/* all CPUs */
+
+	down(&ide_setting_sem);	
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (drive->usage || drive->busy || DRIVER(drive)->busy) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		up(&ide_setting_sem);
 		return 1;
 	}
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
@@ -3894,12 +2616,16 @@
 	ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
 	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
 #endif
+	drive->driver = &idedefault_driver;
+	setup_driver_defaults(drive);
 	auto_remove_settings(drive);
-	drive->driver = NULL;
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	up(&ide_setting_sem);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
 int ide_register_module (ide_module_t *module)
 {
 	ide_module_t *p = ide_modules;
@@ -3911,10 +2637,12 @@
 	}
 	module->next = ide_modules;
 	ide_modules = module;
-	revalidate_drives();
+	revalidate_drives(1);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_module);
+
 void ide_unregister_module (ide_module_t *module)
 {
 	ide_module_t **p;
@@ -3924,6 +2652,8 @@
 		*p = (*p)->next;
 }
 
+EXPORT_SYMBOL(ide_unregister_module);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3933,10 +2663,34 @@
 	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_module);
-EXPORT_SYMBOL(ide_unregister_module);
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(ide_fops);
+
+/*
+ * ide_geninit() is called exactly *once* for each interface.
+ */
+void ide_geninit (ide_hwif_t *hwif)
+{
+	unsigned int unit;
+	struct gendisk *gd = hwif->gd;
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (!drive->present)
+			continue;
+		if (drive->media!=ide_disk && drive->media!=ide_floppy)
+			continue;
+		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+			(drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+			1<<PARTN_BITS, ide_fops,
+			current_capacity(drive));
+	}
+}
+
+EXPORT_SYMBOL(ide_geninit);
+
 
 /*
  * Probe module
@@ -3944,65 +2698,7 @@
 devfs_handle_t ide_devfs_handle;
 
 EXPORT_SYMBOL(ide_probe);
-EXPORT_SYMBOL(drive_is_flashcard);
-EXPORT_SYMBOL(ide_timer_expiry);
-EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_fops);
-EXPORT_SYMBOL(ide_get_queue);
-EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(ide_devfs_handle);
-EXPORT_SYMBOL(do_ide_request);
-/*
- * Driver module
- */
-EXPORT_SYMBOL(ide_scan_devices);
-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(drive_is_ready);
-EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
-EXPORT_SYMBOL(ide_error);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(ide_wait_stat);
-EXPORT_SYMBOL(ide_do_reset);
-EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ide_init_drive_cmd);
-EXPORT_SYMBOL(ide_do_drive_cmd);
-EXPORT_SYMBOL(ide_end_drive_cmd);
-EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_disk);
-EXPORT_SYMBOL(ide_cmd);
-EXPORT_SYMBOL(ide_wait_cmd);
-EXPORT_SYMBOL(ide_wait_cmd_task);
-EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_stall_queue);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(ide_add_proc_entries);
-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);
-
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_register);
-EXPORT_SYMBOL(ide_unregister);
-EXPORT_SYMBOL(ide_setup_ports);
-EXPORT_SYMBOL(hwif_unregister);
-EXPORT_SYMBOL(get_info_ptr);
-EXPORT_SYMBOL(current_capacity);
-
-EXPORT_SYMBOL(system_bus_clock);
-
-EXPORT_SYMBOL(ide_reinit_drive);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -4019,7 +2715,7 @@
 			return NOTIFY_DONE;
 	}
 
-	printk("flushing ide devices: ");
+	printk(KERN_INFO "flushing ide devices: ");
 
 	for (i = 0; i < MAX_HWIFS; i++) {
 		hwif = &ide_hwifs[i];
@@ -4033,11 +2729,11 @@
 			/* set the drive to standby */
 			printk("%s ", drive->name);
 			if (event != SYS_RESTART)
-				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
-				continue;
+				if (DRIVER(drive)->standby(drive))
+					continue;
 
-			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-				continue;
+			DRIVER(drive)->cleanup(drive);
+			continue;
 		}
 	}
 	printk("\n");
@@ -4060,12 +2756,16 @@
 
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+		ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
 		system_bus_speed = ide_system_bus_speed();
 		banner_printed = 1;
 	}
 
-	init_ide_data ();
+	init_ide_data();
+
+#ifndef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 	initializing = 1;
 	ide_init_builtin_drivers();
@@ -4113,10 +2813,10 @@
 	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)
+#if !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
 			(void) ide_release_dma(&ide_hwifs[index]);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 	}
 
 #ifdef CONFIG_PROC_FS
@@ -4128,5 +2828,6 @@
 #else /* !MODULE */
 
 __setup("", ide_setup);
+module_init(ide_init);
 
 #endif /* MODULE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide_modes.h linux-2.4.21-rc3/drivers/ide/ide_modes.h
--- linux-2.4.20/drivers/ide/ide_modes.h	2001-11-22 19:46:58.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ide_modes.h	2003-05-22 22:06:50.000000000 +0000
@@ -16,8 +16,6 @@
  * breaking the fragile cmd640.c support.
  */
 
-#ifdef CONFIG_BLK_DEV_IDE_MODES
-
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
  * These timings are for access to the IDE data port register *only*.
@@ -31,206 +29,13 @@
 } ide_pio_timings_t;
 
 typedef struct ide_pio_data_s {
-	byte pio_mode;
-	byte use_iordy;
-	byte overridden;
-	byte blacklisted;
+	u8 pio_mode;
+	u8 use_iordy;
+	u8 overridden;
+	u8 blacklisted;
 	unsigned int cycle_time;
 } ide_pio_data_t;
 	
-#ifndef _IDE_C
-
-int ide_scan_pio_blacklist (char *model);
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
 extern const ide_pio_timings_t ide_pio_timings[6];
-
-#else /* _IDE_C */
-
-const ide_pio_timings_t ide_pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
-	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
-	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
-};
-
-/*
- * Black list. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- */
-static struct ide_pio_info {
-	const char	*name;
-	int		pio;
-} ide_pio_blacklist [] = {
-/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
-	{ "Conner Peripherals 540MB - CFS540A", 3 },
-
-	{ "WDC AC2700",  3 },
-	{ "WDC AC2540",  3 },
-	{ "WDC AC2420",  3 },
-	{ "WDC AC2340",  3 },
-	{ "WDC AC2250",  0 },
-	{ "WDC AC2200",  0 },
-	{ "WDC AC21200", 4 },
-	{ "WDC AC2120",  0 },
-	{ "WDC AC2850",  3 },
-	{ "WDC AC1270",  3 },
-	{ "WDC AC1170",  1 },
-	{ "WDC AC1210",  1 },
-	{ "WDC AC280",   0 },
-/*	{ "WDC AC21000", 4 }, */
-	{ "WDC AC31000", 3 },
-	{ "WDC AC31200", 3 },
-/*	{ "WDC AC31600", 4 }, */
-
-	{ "Maxtor 7131 AT", 1 },
-	{ "Maxtor 7171 AT", 1 },
-	{ "Maxtor 7213 AT", 1 },
-	{ "Maxtor 7245 AT", 1 },
-	{ "Maxtor 7345 AT", 1 },
-	{ "Maxtor 7546 AT", 3 },
-	{ "Maxtor 7540 AV", 3 },
-
-	{ "SAMSUNG SHD-3121A", 1 },
-	{ "SAMSUNG SHD-3122A", 1 },
-	{ "SAMSUNG SHD-3172A", 1 },
-
-/*	{ "ST51080A", 4 },
- *	{ "ST51270A", 4 },
- *	{ "ST31220A", 4 },
- *	{ "ST31640A", 4 },
- *	{ "ST32140A", 4 },
- *	{ "ST3780A",  4 },
- */
-	{ "ST5660A",  3 },
-	{ "ST3660A",  3 },
-	{ "ST3630A",  3 },
-	{ "ST3655A",  3 },
-	{ "ST3391A",  3 },
-	{ "ST3390A",  1 },
-	{ "ST3600A",  1 },
-	{ "ST3290A",  0 },
-	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
-
-	{ "QUANTUM ELS127A", 0 },
-	{ "QUANTUM ELS170A", 0 },
-	{ "QUANTUM LPS240A", 0 },
-	{ "QUANTUM LPS210A", 3 },
-	{ "QUANTUM LPS270A", 3 },
-	{ "QUANTUM LPS365A", 3 },
-	{ "QUANTUM LPS540A", 3 },
-	{ "QUANTUM LIGHTNING 540A", 3 },
-	{ "QUANTUM LIGHTNING 730A", 3 },
-
-        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
-        { "QUANTUM FIREBALL_1080", 3 },
-        { "QUANTUM FIREBALL_1280", 3 },
-	{ NULL,	0 }
-};
-
-/*
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-int ide_scan_pio_blacklist (char *model)
-{
-	struct ide_pio_info *p;
-
-	for (p = ide_pio_blacklist; p->name != NULL; p++) {
-		if (strncmp(p->name, model, strlen(p->name)) == 0)
-			return p->pio;
-	}
-	return -1;
-}
-
-/*
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-/*
- * Drive PIO mode auto selection
- */
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
-{
-	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
-	int blacklisted = 0;
-
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		blacklisted = 1;
-		use_iordy = (pio_mode > 2);
-	} else {
-		pio_mode = id->tPIO;
-		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
-			pio_mode = 2;
-			overridden = 1;
-		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
-				if (id->eide_pio_modes & 7) {
-					overridden = 0;
-					if (id->eide_pio_modes & 4)
-						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
-						pio_mode = 4;
-					else
-						pio_mode = 3;
-				}
-			} else {
-				cycle_time = id->eide_pio;
-			}
-		}
-
-#if 0
-		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
-#endif
-
-		/*
-		 * Conservative "downgrade" for all pre-ATA2 drives
-		 */
-		if (pio_mode && pio_mode < 4) {
-			pio_mode--;
-			overridden = 1;
-#if 0
-			use_iordy = (pio_mode > 2);
-#endif
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
-		}
-	}
-	if (pio_mode > max_mode) {
-		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-		d->blacklisted = blacklisted;
-	}
-	return pio_mode;
-}
-
-#endif /* _IDE_C */
-#endif /* CONFIG_BLK_DEV_IDE_MODES */
 #endif /* _IDE_MODES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/it8172.c linux-2.4.21-rc3/drivers/ide/it8172.c
--- linux-2.4.20/drivers/ide/it8172.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/it8172.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,286 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *      IT8172 IDE controller support
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *              stevel@mvista.com or source@mvista.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 the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/it8172/it8172_int.h>
-
-#include "ide_modes.h"
-
-/*
- * Prototypes
- */
-static void it8172_tune_drive (ide_drive_t *drive, byte pio);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-static byte it8172_dma_2_pio (byte xfer_rate);
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
-static int it8172_config_chipset_for_dma (ide_drive_t *drive);
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-#endif
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
-void __init ide_init_it8172 (ide_hwif_t *hwif);
-
-
-static void it8172_tune_drive (ide_drive_t *drive, byte pio)
-{
-    unsigned long flags;
-    u16 drive_enables;
-    u32 drive_timing;
-    int is_slave	= (&HWIF(drive)->drives[1] == drive);
-    
-    pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-    pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables);
-    pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing);
-
-    /*
-     * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
-     * are being left at the default values of 8 PCI clocks (242 nsec
-     * for a 33 MHz clock). These can be safely shortened at higher
-     * PIO modes. The DIOR/DIOW pulse width and recovery times only
-     * apply to PIO modes, not to the DMA modes.
-     */
-    
-    /*
-     * Enable port 0x44. The IT8172G spec is confused; it calls
-     * this register the "Slave IDE Timing Register", but in fact,
-     * it controls timing for both master and slave drives.
-     */
-    drive_enables |= 0x4000;
-
-    if (is_slave) {
-	drive_enables &= 0xc006;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0060;
-    } else {
-	drive_enables &= 0xc060;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0006;
-    }
-
-    save_flags(flags);
-    cli();
-    pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables);
-    restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-/*
- *
- */
-static byte it8172_dma_2_pio (byte xfer_rate)
-{
-    switch(xfer_rate) {
-    case XFER_UDMA_5:
-    case XFER_UDMA_4:
-    case XFER_UDMA_3:
-    case XFER_UDMA_2:
-    case XFER_UDMA_1:
-    case XFER_UDMA_0:
-    case XFER_MW_DMA_2:
-    case XFER_PIO_4:
-	return 4;
-    case XFER_MW_DMA_1:
-    case XFER_PIO_3:
-	return 3;
-    case XFER_SW_DMA_2:
-    case XFER_PIO_2:
-	return 2;
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_1:
-    case XFER_SW_DMA_0:
-    case XFER_PIO_1:
-    case XFER_PIO_0:
-    case XFER_PIO_SLOW:
-    default:
-	return 0;
-    }
-}
-
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
-{
-    ide_hwif_t *hwif	= HWIF(drive);
-    struct pci_dev *dev	= hwif->pci_dev;
-    int a_speed		= 3 << (drive->dn * 4);
-    int u_flag		= 1 << drive->dn;
-    int u_speed		= 0;
-    int err		= 0;
-    byte reg48, reg4a;
-
-    pci_read_config_byte(dev, 0x48, &reg48);
-    pci_read_config_byte(dev, 0x4a, &reg4a);
-
-    /*
-     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
-     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
-     * transfers on some drives, even though both numbers meet the minimum
-     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
-     * So the faster times are just commented out here. The good news is
-     * that the slower cycle time has very little affect on transfer
-     * performance.
-     */
-    
-    switch(speed) {
-    case XFER_UDMA_4:
-    case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
-    case XFER_UDMA_5:
-    case XFER_UDMA_3:
-    case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
-    case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-    case XFER_MW_DMA_2:
-    case XFER_MW_DMA_1:
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_2:	break;
-    default:		return -1;
-    }
-
-    if (speed >= XFER_UDMA_0) {
-	pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-	reg4a &= ~a_speed;
-	pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-    } else {
-	pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-	pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-    }
-
-    it8172_tune_drive(drive, it8172_dma_2_pio(speed));
-
-    if (!drive->init_speed)
-	drive->init_speed = speed;
-    err = ide_config_drive_speed(drive, speed);
-    drive->current_speed = speed;
-    return err;
-}
-
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
-    struct hd_driveid *id = drive->id;
-    byte speed;
-
-    if (id->dma_ultra & 0x0010) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0008) {
-	speed = XFER_UDMA_1;
-    } 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 if (id->dma_1word & 0x0004) {
-	speed = XFER_SW_DMA_2;
-    } else {
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL);
-    }
-
-    (void) it8172_tune_chipset(drive, speed);
-
-    return ((int)((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);
-}
-
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-    switch (func) {
-    case ide_dma_check:
-	return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive),
-			   drive);
-    default :
-	break;
-    }
-    /* Other cases are done by generic IDE-DMA code. */
-    return ide_dmaproc(func, drive);
-}
-
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
-
-
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
-{
-    unsigned char progif;
-    
-    /*
-     * Place both IDE interfaces into PCI "native" mode
-     */
-    (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
-
-    return IT8172_IDE_IRQ;
-}
-
-
-void __init ide_init_it8172 (ide_hwif_t *hwif)
-{
-    struct pci_dev* dev = hwif->pci_dev;
-    unsigned long cmdBase, ctrlBase;
-    
-    hwif->tuneproc = &it8172_tune_drive;
-    hwif->drives[0].autotune = 1;
-    hwif->drives[1].autotune = 1;
-
-    if (!hwif->dma_base)
-	return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-    hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_IT8172_TUNING
-    hwif->autodma = 1;
-    hwif->dmaproc = &it8172_dmaproc;
-    hwif->speedproc = &it8172_tune_chipset;
-#endif /* CONFIG_IT8172_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-
-    cmdBase = dev->resource[0].start;
-    ctrlBase = dev->resource[1].start;
-    
-    ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
-    memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-    hwif->noprobe = 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/Makefile linux-2.4.21-rc3/drivers/ide/legacy/Makefile
--- linux-2.4.20/drivers/ide/legacy/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/Makefile	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,27 @@
+
+O_TARGET := idedriver-legacy.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
+obj-$(CONFIG_BLK_DEV_PDC4030)		+= pdc4030.o
+obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+
+obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+
+# Last of all
+obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ali14xx.c linux-2.4.21-rc3/drivers/ide/legacy/ali14xx.c
--- linux-2.4.20/drivers/ide/legacy/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/ali14xx.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,304 @@
+/*
+ *  linux/drivers/ide/legacy/ali14xx.c		Version 0.03	Feb 09, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Works for ALI M1439/1443/1445/1487/1489 chipsets.
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function.  The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk.  I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg  (derekn@ece.cmu.edu)
+ * 95-sep-26
+ *
+ * Update 96-jul-13:
+ *
+ * I've since upgraded to two disks and a CD-ROM, with no trouble, and
+ * I've also heard from several others who have used it successfully.
+ * This driver appears to work with both the 1443/1445 and the 1487/1489
+ * chipsets.  I've added support for PIO mode 4 for the 1487.  This
+ * seems to work just fine on the 1443 also, although I'm not sure it's
+ * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
+ * mode 4 for a while now with no trouble.)  -Derek
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_ALI14XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_ALI14XX_MODULE */
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static RegInitializer initData[] __initdata = {
+	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+	{0x35, 0x03}, {0x00, 0x00}
+};
+
+#define ALI_MAX_PIO 4
+
+/* timing parameter registers for each drive */
+static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
+	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+};
+
+static int basePort;	/* base port address */
+static int regPort;	/* port for register number */
+static int dataPort;	/* port for register data */
+static u8 regOn;	/* output to base port to access registers */
+static u8 regOff;	/* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline u8 inReg (u8 reg)
+{
+	outb_p(reg, regPort);
+	return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg (u8 data, u8 reg)
+{
+	outb_p(reg, regPort);
+	outb_p(data, dataPort);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int driveNum;
+	int time1, time2;
+	u8 param1, param2, param3, param4;
+	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+
+	/* calculate timing, according to PIO mode */
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	if (pio < 3) {
+		param3 += 8;
+		param4 += 8;
+	}
+	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+		drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+	/* stuff timing parameters into controller registers */
+	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(regOn, basePort);
+	outReg(param1, regTab[driveNum].reg1);
+	outReg(param2, regTab[driveNum].reg2);
+	outReg(param3, regTab[driveNum].reg3);
+	outReg(param4, regTab[driveNum].reg4);
+	outb_p(regOff, basePort);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int __init findPort (void)
+{
+	int i;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < ALI_NUM_PORTS; ++i) {
+		basePort = ports[i];
+		regOff = inb(basePort);
+		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+			outb_p(regOn, basePort);
+			if (inb(basePort) == regOn) {
+				regPort = basePort + 4;
+				dataPort = basePort + 8;
+				t = inReg(0) & 0xf0;
+				outb_p(regOff, basePort);
+				local_irq_restore(flags);
+				if (t != 0x50)
+					return 0;
+				return 1;  /* success */
+			}
+		}
+		outb_p(regOff, basePort);
+	}
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int __init initRegisters (void) {
+	RegInitializer *p;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	outb_p(regOn, basePort);
+	for (p = initData; p->reg != 0; ++p)
+		outReg(p->data, p->reg);
+	outb_p(0x01, regPort);
+	t = inb(regPort) & 0x01;
+	outb_p(regOff, basePort);
+	local_irq_restore(flags);
+	return t;
+}
+
+int __init probe_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+	if (!findPort()) {
+		printk(KERN_ERR "ali14xx: not found.\n");
+		return 1;
+	}
+
+	printk(KERN_DEBUG "ali14xx: base= 0x%03x, regOn = 0x%02x.\n", basePort, regOn);
+	ide_hwifs[0].chipset = ide_ali14xx;
+	ide_hwifs[1].chipset = ide_ali14xx;
+	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+	/* initialize controller registers */
+	if (!initRegisters()) {
+		printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
+		return 1;
+	}
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init ali14xx_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx)
+		return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_ali14xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+        if (findPort())
+		if (probe_ali14xx())
+			goto no_detect;
+	return;
+
+no_detect:
+	printk(KERN_ERR "ali14xx: not found.\n");
+	ali14xx_release();
+}
+
+#else
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init ali14xx_mod_init(void)
+{
+	/* auto-detect IDE controller port */
+	if (findPort())
+		if (probe_ali14xx()) {
+			ali14xx_release();
+			return -ENODEV;
+		}
+
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx) {
+		ali14xx_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(ali14xx_mod_init);
+
+void __init ali14xx_mod_exit(void)
+{
+	ali14xx_release();
+}
+module_exit(ali14xx_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/buddha.c linux-2.4.21-rc3/drivers/ide/legacy/buddha.c
--- linux-2.4.20/drivers/ide/legacy/buddha.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/buddha.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,233 @@
+/*
+ *  linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *
+ *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+ *
+ *  This driver was written based on the specifications in README.buddha and
+ *  the X-Surf info from Inside_XSurf.txt available at
+ *  http://www.jschoenfeld.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  TODO:
+ *    - test it :-)
+ *    - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
+     */
+
+#define BUDDHA_NUM_HWIFS	2
+#define CATWEASEL_NUM_HWIFS	3
+#define XSURF_NUM_HWIFS         2
+
+    /*
+     *  Bases of the IDE interfaces (relative to the board address)
+     */
+
+#define BUDDHA_BASE1	0x800
+#define BUDDHA_BASE2	0xa00
+#define BUDDHA_BASE3	0xc00
+
+#define XSURF_BASE1     0xb000 /* 2.5" Interface */
+#define XSURF_BASE2     0xd000 /* 3.5" Interface */
+
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+     XSURF_BASE1, XSURF_BASE2
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define BUDDHA_DATA	0x00
+#define BUDDHA_ERROR	0x06		/* see err-bits */
+#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define BUDDHA_SECTOR	0x0e		/* starting sector */
+#define BUDDHA_LCYL	0x12		/* starting cylinder */
+#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
+#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS	0x1e		/* see status-bits */
+#define BUDDHA_CONTROL	0x11a
+#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
+
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
+};
+
+static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
+};
+
+    /*
+     *  Other registers
+     */
+
+#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2	0xf40		/* interrupt */
+#define BUDDHA_IRQ3	0xf80
+
+#define XSURF_IRQ1      0x7e
+#define XSURF_IRQ2      0x7e
+
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+    XSURF_IRQ1, XSURF_IRQ2
+};
+
+#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
+
+
+    /*
+     *  Board information
+     */
+
+typedef enum BuddhaType_Enum {
+    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+static int xsurf_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+    /*
+     *  Probe for a Buddha or Catweasel IDE interface
+     */
+
+void __init buddha_init(void)
+{
+	hw_regs_t hw;
+	int i, index;
+
+	struct zorro_dev *z = NULL;
+	u_long buddha_board = 0;
+	BuddhaType type;
+	int buddha_num_hwifs;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		unsigned long board;
+		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+			type=BOARD_BUDDHA;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
+			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+			type=BOARD_CATWEASEL;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
+			buddha_num_hwifs = XSURF_NUM_HWIFS;
+			type=BOARD_XSURF;
+		} else 
+			continue;
+		
+		board = z->resource.start;
+
+/*
+ * FIXME: we now have selectable mmio v/s iomio transports.
+ */
+
+		if(type != BOARD_XSURF) {
+			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
+				continue;
+		} else {
+			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+				continue;
+			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+				goto fail_base2;
+			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+				release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+				release_mem_region(board+XSURF_BASE1, 0x1000);
+				continue;
+			}
+		}	  
+		buddha_board = ZTWO_VADDR(board);
+		
+		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
+		/* X-Surf doesn't have this.  IRQs are always on */
+		if (type != BOARD_XSURF)
+			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+		
+		for(i=0;i<buddha_num_hwifs;i++) {
+			if(type != BOARD_XSURF) {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
+						buddha_offsets, 0,
+						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
+						buddha_ack_intr,
+//						budda_iops,
+						IRQ_AMIGA_PORTS);
+			} else {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
+						xsurf_offsets, 0,
+						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
+						xsurf_ack_intr,
+//						xsurf_iops,
+						IRQ_AMIGA_PORTS);
+			}	
+			
+			index = ide_register_hw(&hw, NULL);
+			if (index != -1) {
+				printk("ide%d: ", index);
+				switch(type) {
+				case BOARD_BUDDHA:
+					printk("Buddha");
+					break;
+				case BOARD_CATWEASEL:
+					printk("Catweasel");
+					break;
+				case BOARD_XSURF:
+					printk("X-Surf");
+					break;
+				}
+				printk(" IDE interface\n");	    
+			}		      
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/dtc2278.c linux-2.4.21-rc3/drivers/ide/legacy/dtc2278.c
--- linux-2.4.20/drivers/ide/legacy/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/dtc2278.c	2003-05-22 22:06:43.000000000 +0000
@@ -0,0 +1,203 @@
+/*
+ *  linux/drivers/ide/legacy/dtc2278.c		Version 0.02	Feb 10, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_DTC2278_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_DTC2278_MODULE */
+
+/*
+ * Changing this #undef to #define may solve start up problems in some systems.
+ */
+#undef ALWAYS_SET_DTC2278_PIO_MODE
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem  corrupted with -u1, but under heavy disk load only :-)
+ *
+ * This card is now forced to use the "serialize" feature,
+ * and irq-unmasking is disallowed.  If io_32bit is enabled,
+ * it must be done for BOTH drives on each interface.
+ *
+ * This code was written for the DTC2278E, but might work with any of these:
+ *
+ * DTC2278S has only a single IDE interface.
+ * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
+ * DTC2278E also has serial ports and a printer port
+ * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
+ *
+ * There may be a fourth controller type. The S and D versions use the
+ * Winbond chip, and I think the E version does also.
+ *
+ */
+
+static void sub22 (char b, char c)
+{
+	int i;
+
+	for(i = 0; i < 3; ++i) {
+		inb(0x3f6);
+		outb_p(b,0xb0);
+		inb(0x3f6);
+		outb_p(c,0xb4);
+		inb(0x3f6);
+		if(inb(0xb4) == c) {
+			outb_p(7,0xb0);
+			inb(0x3f6);
+			return;	/* success */
+		}
+	}
+}
+
+static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	if (pio >= 3) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		/*
+		 * This enables PIO mode4 (3?) on the first interface
+		 */
+		sub22(1,0xc3);
+		sub22(0,0xa0);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else {
+		/* we don't know how to set it back again.. */
+	}
+
+	/*
+	 * 32bit I/O has to be enabled for *both* drives at the same time.
+	 */
+	drive->io_32bit = 1;
+	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+}
+
+void __init probe_dtc2278 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * This enables the second interface
+	 */
+	outb_p(4,0xb0);
+	inb(0x3f6);
+	outb_p(0x20,0xb4);
+	inb(0x3f6);
+#ifdef ALWAYS_SET_DTC2278_PIO_MODE
+	/*
+	 * This enables PIO mode4 (3?) on the first interface
+	 * and may solve start-up problems for some people.
+	 */
+	sub22(1,0xc3);
+	sub22(0,0xa0);
+#endif
+	local_irq_restore(flags);
+
+	ide_hwifs[0].serialized = 1;
+	ide_hwifs[1].serialized = 1;
+	ide_hwifs[0].chipset = ide_dtc2278;
+	ide_hwifs[1].chipset = ide_dtc2278;
+	ide_hwifs[0].tuneproc = &tune_dtc2278;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init dtc2278_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278)
+		return;
+
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[0].drives[0].no_unmask = 0;
+	ide_hwifs[0].drives[1].no_unmask = 0;
+	ide_hwifs[1].drives[0].no_unmask = 0;
+	ide_hwifs[1].drives[1].no_unmask = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_dtc2278:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_dtc2278 (void)
+{
+	probe_dtc2278();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init dtc2278_mod_init(void)
+{
+	probe_dtc2278();
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278) {
+		dtc2278_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(dtc2278_mod_init);
+
+void __init dtc2278_mod_exit(void)
+{
+	dtc2278_release();
+}
+module_exit(dtc2278_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/falconide.c linux-2.4.21-rc3/drivers/ide/legacy/falconide.c
--- linux-2.4.20/drivers/ide/legacy/falconide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/falconide.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,78 @@
+/*
+ *  linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver
+ *
+ *     Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+
+    /*
+     *  Base of the IDE interface
+     */
+
+#define ATA_HD_BASE	0xfff00000
+
+    /*
+     *  Offsets from the above base
+     */
+
+#define ATA_HD_DATA	0x00
+#define ATA_HD_ERROR	0x05		/* see err-bits */
+#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
+#define ATA_HD_SECTOR	0x0d		/* starting sector */
+#define ATA_HD_LCYL	0x11		/* starting cylinder */
+#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
+#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS	0x1d		/* see status-bits */
+#define ATA_HD_CONTROL	0x39
+
+static int falconide_offsets[IDE_NR_PORTS] __initdata = {
+    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+    /*
+     *  falconide_intr_lock is used to obtain access to the IDE interrupt,
+     *  which is shared between several drivers.
+     */
+
+int falconide_intr_lock;
+
+
+    /*
+     *  Probe for a Falcon IDE interface
+     */
+
+void __init falconide_init(void)
+{
+    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+	hw_regs_t hw;
+	int index;
+
+	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
+			0, 0, NULL,
+//			falconide_iops,
+			IRQ_MFP_IDE);
+	index = ide_register_hw(&hw, NULL);
+
+	if (index != -1)
+	    printk("ide%d: Falcon IDE interface\n", index);
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/gayle.c linux-2.4.21-rc3/drivers/ide/legacy/gayle.c
--- linux-2.4.20/drivers/ide/legacy/gayle.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/gayle.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,189 @@
+/*
+ *  linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver
+ *
+ *     Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
+#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define GAYLE_DATA	0x00
+#define GAYLE_ERROR	0x06		/* see err-bits */
+#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define GAYLE_SECTOR	0x0e		/* starting sector */
+#define GAYLE_LCYL	0x12		/* starting cylinder */
+#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
+#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS	0x1e		/* see status-bits */
+#define GAYLE_CONTROL	0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
+    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+    /*
+     *  These are at different offsets from the base
+     */
+
+#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
+
+
+    /*
+     *  Offset of the secondary port for IDE doublers
+     *  Note that GAYLE_CONTROL is NOT available then!
+     */
+
+#define GAYLE_NEXT_PORT	0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS		1
+#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG	1
+#define GAYLE_IDEREG_SIZE	0x2000
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS		2
+#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
+					       GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
+#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
+int ide_doubler = 0;	/* support IDE doublers? */
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+    return 1;
+}
+
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
+
+void __init gayle_init(void)
+{
+    int a4000, i;
+
+    if (!MACH_IS_AMIGA)
+	return;
+
+    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
+	return;
+
+    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+	ide_ioreg_t base, ctrlport, irqport;
+	ide_ack_intr_t *ack_intr;
+	hw_regs_t hw;
+	ide_hwif_t *hwif;
+	int index;
+	unsigned long phys_base, res_start, res_n;
+
+	if (a4000) {
+	    phys_base = GAYLE_BASE_4000;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+	    ack_intr = gayle_ack_intr_a4000;
+	} else {
+	    phys_base = GAYLE_BASE_1200;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+	    ack_intr = gayle_ack_intr_a1200;
+	}
+/*
+ * FIXME: we now have selectable modes between mmio v/s iomio
+ */
+
+	phys_base += i*GAYLE_NEXT_PORT;
+
+	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+	res_n = GAYLE_IDEREG_SIZE;
+
+	if (!request_mem_region(res_start, res_n, "IDE"))
+	    continue;
+
+	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
+	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+	ide_setup_ports(&hw, base, gayle_offsets,
+			ctrlport, irqport, ack_intr,
+//			&gayle_iops,
+			IRQ_AMIGA_PORTS);
+
+	index = ide_register_hw(&hw, &hwif);
+	if (index != -1) {
+	    hwif->mmio = 2;
+	    switch (i) {
+		case 0:
+		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+			   a4000 ? 4000 : 1200);
+		    break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+		case 1:
+		    printk("ide%d: IDE doubler\n", index);
+		    break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+	    }
+	} else
+	    release_mem_region(res_start, res_n);
+
+#if 1 /* TESTING */
+	if (i == 1) {
+	    volatile u_short *addr = (u_short *)base;
+	    u_short data;
+	    printk("+++ Probing for IDE doubler... ");
+	    *addr = 0xffff;
+	    data = *addr;
+	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
+	}
+#endif /* TESTING */
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/hd.c linux-2.4.21-rc3/drivers/ide/legacy/hd.c
--- linux-2.4.20/drivers/ide/legacy/hd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/hd.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,925 @@
+/*
+ *  linux/drivers/ide/legacy/hd.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ * 
+ *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *
+ *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  in the early extended-partition checks and added DM partitions
+ *
+ *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ *  and general streamlining by Mark Lord.
+ *
+ *  Removed 99% of above. Use Mark's ide driver for those options.
+ *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ *  Modified 1995 Russell King for ARM processor.
+ *
+ *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ *  off in a hurry once you queue things up - Paul G. 02/2001
+ */
+  
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+  
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#include <linux/blk.h>
+
+#ifdef __arm__
+#undef  HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+static int revalidate_hddisk(kdev_t, int);
+
+#define	HD_DELAY	0
+
+#define MAX_ERRORS     16	/* Max read/write errors/sector */
+#define RESET_FREQ      8	/* Reset controller every 8th retry */
+#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
+#define MAX_HD		2
+
+#define STAT_OK		(READY_STAT|SEEK_STAT)
+#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+static int access_count[MAX_HD];
+static char busy[MAX_HD];
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
+
+static int reset;
+static int hd_error;
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
+
+/*
+ *  This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+	unsigned int head,sect,cyl,wpcom,lzone,ctl;
+};
+	
+#ifdef HD_TYPE
+static struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct hd_struct hd[MAX_HD<<6];
+static int hd_sizes[MAX_HD<<6];
+static int hd_blocksizes[MAX_HD<<6];
+static int hd_hardsectsizes[MAX_HD<<6];
+static int hd_maxsect[MAX_HD<<6];
+
+static struct timer_list device_timer;
+
+#define SET_TIMER 							\
+	do {								\
+		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
+	} while (0)
+
+#define CLEAR_TIMER del_timer(&device_timer);
+
+#undef SET_INTR
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+	SET_TIMER; \
+else \
+	CLEAR_TIMER;
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+	unsigned long t, flags;
+	int i;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb(0x40) << 8;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return(t - i);
+}
+#endif
+
+void __init hd_setup(char *str, int *ints)
+{
+	int hdind = 0;
+
+	if (ints[0] != 3)
+		return;
+	if (hd_info[0].head != 0)
+		hdind=1;
+	hd_info[hdind].head = ints[2];
+	hd_info[hdind].sect = ints[3];
+	hd_info[hdind].cyl = ints[1];
+	hd_info[hdind].wpcom = 0;
+	hd_info[hdind].lzone = ints[1];
+	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+	NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+	unsigned long flags;
+	char devc;
+
+	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+	save_flags (flags);
+	sti();
+#ifdef VERBOSE_ERRORS
+	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
+	if (stat & BUSY_STAT)	printk("Busy ");
+	if (stat & READY_STAT)	printk("DriveReady ");
+	if (stat & WRERR_STAT)	printk("WriteFault ");
+	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("}\n");
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+		if (hd_error & BBD_ERR)		printk("BadSector ");
+		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
+		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
+		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
+		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+			printk(", CHS=%d/%d/%d",
+				(inb(HD_HCYL)<<8) + inb(HD_LCYL),
+				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+			if (!QUEUE_EMPTY)
+				printk(", sector=%ld", CURRENT->sector);
+		}
+		printk("\n");
+	}
+#else
+	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+	}
+#endif	/* verbose errors */
+	restore_flags (flags);
+}
+
+void check_status(void)
+{
+	int i = inb_p(HD_STATUS);
+
+	if (!OK_STATUS(i)) {
+		dump_status("check_status", i);
+		bad_rw_intr();
+	}
+}
+
+static int controller_busy(void)
+{
+	int retries = 100000;
+	unsigned char status;
+
+	do {
+		status = inb_p(HD_STATUS);
+	} while ((status & BUSY_STAT) && --retries);
+	return status;
+}
+
+static int status_ok(void)
+{
+	unsigned char status = inb_p(HD_STATUS);
+
+	if (status & BUSY_STAT)
+		return 1;	/* Ancient, but does it make sense??? */
+	if (status & WRERR_STAT)
+		return 0;
+	if (!(status & READY_STAT))
+		return 0;
+	if (!(status & SEEK_STAT))
+		return 0;
+	return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+	int retry = 100;
+
+	do {
+		if (controller_busy() & BUSY_STAT)
+			return 0;
+		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+		if (status_ok())
+			return 1;
+	} while (--retry);
+	return 0;
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+		unsigned int head,unsigned int cyl,unsigned int cmd,
+		void (*intr_addr)(void))
+{
+	unsigned short port;
+
+#if (HD_DELAY > 0)
+	while (read_timer() - last_req < HD_DELAY)
+		/* nothing */;
+#endif
+	if (reset)
+		return;
+	if (!controller_ready(drive, head)) {
+		reset = 1;
+		return;
+	}
+	SET_INTR(intr_addr);
+	outb_p(hd_info[drive].ctl,HD_CMD);
+	port=HD_DATA;
+	outb_p(hd_info[drive].wpcom>>2,++port);
+	outb_p(nsect,++port);
+	outb_p(sect,++port);
+	outb_p(cyl,++port);
+	outb_p(cyl>>8,++port);
+	outb_p(0xA0|(drive<<4)|head,++port);
+	outb_p(cmd,++port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+	unsigned int i;
+	unsigned char c;
+
+	for (i = 0; i < 500000 ; i++) {
+		c = inb_p(HD_STATUS);
+		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+			return 0;
+	}
+	dump_status("reset timed out", c);
+	return 1;
+}
+
+static void reset_controller(void)
+{
+	int	i;
+
+	outb_p(4,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	if (drive_busy())
+		printk("hd: controller still busy\n");
+	else if ((hd_error = inb(HD_ERROR)) != 1)
+		printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+	static int i;
+
+repeat:
+	if (reset) {
+		reset = 0;
+		i = -1;
+		reset_controller();
+	} else {
+		check_status();
+		if (reset)
+			goto repeat;
+	}
+	if (++i < NR_HD) {
+		special_op[i] = recalibrate[i] = 1;
+		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
+			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+		if (reset)
+			goto repeat;
+	} else
+		hd_request();
+}
+
+void do_reset_hd(void)
+{
+	DEVICE_INTR = NULL;
+	reset = 1;
+	reset_hd();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
+ * drive enters "idle", "standby", or "sleep" mode, so if the status looks
+ * "good", we just ignore the interrupt completely.
+ */
+void unexpected_hd_interrupt(void)
+{
+	unsigned int stat = inb_p(HD_STATUS);
+
+	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+		dump_status ("unexpected interrupt", stat);
+		SET_TIMER;
+	}
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
+static void bad_rw_intr(void)
+{
+	int dev;
+
+	if (QUEUE_EMPTY)
+		return;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+		end_request(0);
+		special_op[dev] = recalibrate[dev] = 1;
+	} else if (CURRENT->errors % RESET_FREQ == 0)
+		reset = 1;
+	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+		special_op[dev] = recalibrate[dev] = 1;
+	/* Otherwise just retry */
+}
+
+static inline int wait_DRQ(void)
+{
+	int retries = 100000, stat;
+
+	while (--retries > 0)
+		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+			return 0;
+	dump_status("wait_DRQ", stat);
+	return -1;
+}
+
+static void read_intr(void)
+{
+	int i, retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if (i & DRQ_STAT)
+			goto ok_to_read;
+	} while (--retries > 0);
+	dump_status("read_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_read:
+	insw(HD_DATA,CURRENT->buffer,256);
+	CURRENT->sector++;
+	CURRENT->buffer += 512;
+	CURRENT->errors = 0;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+#ifdef DEBUG
+	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+		(unsigned long) CURRENT->buffer+512));
+#endif
+	if (CURRENT->current_nr_sectors <= 0)
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&read_intr);
+		return;
+	}
+	(void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	if (!QUEUE_EMPTY)
+		hd_request();
+	return;
+}
+
+static void write_intr(void)
+{
+	int i;
+	int retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
+			goto ok_to_write;
+	} while (--retries > 0);
+	dump_status("write_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_write:
+	CURRENT->sector++;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+	CURRENT->buffer += 512;
+	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&write_intr);
+		outsw(HD_DATA,CURRENT->buffer,256);
+		sti();
+	} else {
+#if (HD_DELAY > 0)
+		last_req = read_timer();
+#endif
+		hd_request();
+	}
+	return;
+}
+
+static void recal_intr(void)
+{
+	check_status();
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+	unsigned int dev;
+
+	DEVICE_INTR = NULL;
+	if (QUEUE_EMPTY)
+		return;
+	disable_irq(HD_IRQ);
+	sti();
+	reset = 1;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	printk("hd%c: timeout\n", dev+'a');
+	if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+		printk("hd%c: too many errors\n", dev+'a');
+#endif
+		end_request(0);
+	}
+	cli();
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+	if (recalibrate[dev]) {
+		recalibrate[dev] = 0;
+		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+		return reset;
+	}
+	if (hd_info[dev].head > 16) {
+		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+		end_request(0);
+	}
+	special_op[dev] = 0;
+	return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible.  In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+	unsigned int dev, block, nsect, sec, track, head, cyl;
+
+	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
+	if (DEVICE_INTR)
+		return;
+repeat:
+	del_timer(&device_timer);
+	sti();
+	INIT_REQUEST;
+	if (reset) {
+		cli();
+		reset_hd();
+		return;
+	}
+	dev = MINOR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
+#ifdef DEBUG
+		if (dev >= (NR_HD<<6))
+			printk("hd: bad minor number: device=%s\n",
+			       kdevname(CURRENT->rq_dev));
+		else
+			printk("hd%c: bad access: block=%d, count=%d\n",
+				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
+#endif
+		end_request(0);
+		goto repeat;
+	}
+	block += hd[dev].start_sect;
+	dev >>= 6;
+	if (special_op[dev]) {
+		if (do_special_op(dev))
+			goto repeat;
+		return;
+	}
+	sec   = block % hd_info[dev].sect + 1;
+	track = block / hd_info[dev].sect;
+	head  = track % hd_info[dev].head;
+	cyl   = track / hd_info[dev].head;
+#ifdef DEBUG
+	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
+#endif
+	if (CURRENT->cmd == READ) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+		if (reset)
+			goto repeat;
+		return;
+	}
+	if (CURRENT->cmd == WRITE) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+		if (reset)
+			goto repeat;
+		if (wait_DRQ()) {
+			bad_rw_intr();
+			goto repeat;
+		}
+		outsw(HD_DATA,CURRENT->buffer,256);
+		return;
+	}
+	panic("unknown hd-command");
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+	disable_irq(HD_IRQ);
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+	int dev;
+
+	if ((!inode) || !(inode->i_rdev))
+		return -EINVAL;
+	dev = DEVICE_NR(inode->i_rdev);
+	if (dev >= NR_HD)
+		return -EINVAL;
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g; 
+			if (!loc)  return -EINVAL;
+			g.heads = hd_info[dev].head;
+			g.sectors = hd_info[dev].sect;
+			g.cylinders = hd_info[dev].cyl;
+			g.start = hd[MINOR(inode->i_rdev)].start_sect;
+			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+		}
+
+         	case BLKGETSIZE:   /* Return device size */
+			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
+					(unsigned long *) arg);
+         	case BLKGETSIZE64:
+			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
+					(u64 *) arg);
+
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return revalidate_hddisk(inode->i_rdev, 1);
+
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+	int target;
+	target =  DEVICE_NR(inode->i_rdev);
+
+	if (target >= NR_HD)
+		return -ENODEV;
+	while (busy[target])
+		sleep_on(&busy_wait);
+	access_count[target]++;
+	return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static int hd_release(struct inode * inode, struct file * file)
+{
+        int target =  DEVICE_NR(inode->i_rdev);
+	access_count[target]--;
+	return 0;
+}
+
+extern struct block_device_operations hd_fops;
+
+static struct gendisk hd_gendisk = {
+	major:		MAJOR_NR,
+	major_name:	"hd",
+	minor_shift:	6,
+	max_p:		1 << 6,
+	part:		hd,
+	sizes:		hd_sizes,
+	fops:		&hd_fops,
+};
+	
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*handler)(void) = DEVICE_INTR;
+
+	DEVICE_INTR = NULL;
+	del_timer(&device_timer);
+	if (!handler)
+		handler = unexpected_hd_interrupt;
+	handler();
+	sti();
+}
+
+static struct block_device_operations hd_fops = {
+	open:		hd_open,
+	release:	hd_release,
+	ioctl:		hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled:  this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines.
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+static void __init hd_geninit(void)
+{
+	int drive;
+
+	for(drive=0; drive < (MAX_HD << 6); drive++) {
+		hd_blocksizes[drive] = 1024;
+		hd_hardsectsizes[drive] = 512;
+		hd_maxsect[drive]=255;
+	}
+	blksize_size[MAJOR_NR] = hd_blocksizes;
+	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+	max_sectors[MAJOR_NR] = hd_maxsect;
+
+#ifdef __i386__
+	if (!NR_HD) {
+		extern struct drive_info drive_info;
+		unsigned char *BIOS = (unsigned char *) &drive_info;
+		unsigned long flags;
+		int cmos_disks;
+
+		for (drive=0 ; drive<2 ; drive++) {
+			hd_info[drive].cyl = *(unsigned short *) BIOS;
+			hd_info[drive].head = *(2+BIOS);
+			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+			hd_info[drive].ctl = *(8+BIOS);
+			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+			hd_info[drive].sect = *(14+BIOS);
+#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
+			if (hd_info[drive].cyl && NR_HD == drive)
+				NR_HD++;
+#endif
+			BIOS += 16;
+		}
+
+	/*
+		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
+		BIOS table, but not register compatible, and therefore
+		not present in CMOS.
+
+		Furthermore, we will assume that our ST-506 drives
+		<if any> are the primary drives in the system, and 
+		the ones reflected as drive 1 or 2.
+
+		The first drive is stored in the high nibble of CMOS
+		byte 0x12, the second in the low nibble.  This will be
+		either a 4 bit drive type or 0xf indicating use byte 0x19 
+		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+		Needless to say, a non-zero value means we have 
+		an AT controller hard disk for that drive.
+
+		Currently the rtc_lock is a bit academic since this
+		driver is non-modular, but someday... ?         Paul G.
+	*/
+
+		spin_lock_irqsave(&rtc_lock, flags);
+		cmos_disks = CMOS_READ(0x12);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
+		if (cmos_disks & 0xf0) {
+			if (cmos_disks & 0x0f)
+				NR_HD = 2;
+			else
+				NR_HD = 1;
+		}
+	}
+#endif /* __i386__ */
+#ifdef __arm__
+	if (!NR_HD) {
+		/* We don't know anything about the drive.  This means
+		 * that you *MUST* specify the drive parameters to the
+		 * kernel yourself.
+		 */
+		printk("hd: no drives specified - use hd=cyl,head,sectors"
+			" on kernel command line\n");
+	}
+#endif
+
+	for (drive=0 ; drive < NR_HD ; drive++) {
+		hd[drive<<6].nr_sects = hd_info[drive].head *
+			hd_info[drive].sect * hd_info[drive].cyl;
+		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
+			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
+			hd_info[drive].head, hd_info[drive].sect);
+	}
+	if (!NR_HD)
+		return;
+
+	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+		printk("hd: unable to get IRQ%d for the hard disk driver\n",
+			HD_IRQ);
+		NR_HD = 0;
+		return;
+	}
+	request_region(HD_DATA, 8, "hd");
+	request_region(HD_CMD, 1, "hd(cmd)");
+
+	hd_gendisk.nr_real = NR_HD;
+
+	for(drive=0; drive < NR_HD; drive++)
+		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
+			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
+			hd_info[drive].cyl);
+}
+
+int __init hd_init(void)
+{
+	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+		return -1;
+	}
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
+	add_gendisk(&hd_gendisk);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
+	hd_geninit();
+	return 0;
+}
+
+#define DEVICE_BUSY busy[target]
+#define USAGE access_count[target]
+#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
+/* We assume that the BIOS parameters do not change, so the disk capacity
+   will not change */
+#undef MAYBE_REINIT
+#define GENDISK_STRUCT hd_gendisk
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+static int revalidate_hddisk(kdev_t dev, int maxusage)
+{
+	int target;
+	struct gendisk * gdev;
+	int max_p;
+	int start;
+	int i;
+	long flags;
+
+	target = DEVICE_NR(dev);
+	gdev = &GENDISK_STRUCT;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (DEVICE_BUSY || USAGE > maxusage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	DEVICE_BUSY = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for (i=max_p - 1; i >=0 ; i--) {
+		int minor = start + i;
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+
+#ifdef MAYBE_REINIT
+	MAYBE_REINIT;
+#endif
+
+	grok_partitions(gdev, target, 1<<6, CAPACITY);
+
+	DEVICE_BUSY = 0;
+	wake_up(&busy_wait);
+	return 0;
+}
+
+static int parse_hd_setup (char *line) {
+	int ints[6];
+
+	(void) get_options(line, ARRAY_SIZE(ints), ints);
+	hd_setup(NULL, ints);
+
+	return 1;
+}
+__setup("hd=", parse_hd_setup);
+
+module_init(hd_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ht6560b.c linux-2.4.21-rc3/drivers/ide/legacy/ht6560b.c
--- linux-2.4.20/drivers/ide/legacy/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/ht6560b.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,430 @@
+/*
+ *  linux/drivers/ide/legacy/ht6560b.c		Version 0.07	Feb  1, 2000
+ *
+ *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+ */
+
+/*
+ *
+ *  Version 0.01        Initial version hacked out of ide.c
+ *
+ *  Version 0.02        Added support for PIO modes, auto-tune
+ *
+ *  Version 0.03        Some cleanups
+ *
+ *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
+ *
+ *  Version 0.06        Prefetch mode now defaults no OFF. To set
+ *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
+ *                      Unmask irq is disabled when prefetch mode
+ *                      is enabled.
+ *
+ *  Version 0.07        Trying to fix CD-ROM detection problem.
+ *                      "Prefetch" mode bit OFF for ide disks and
+ *                      ON for anything else.
+ *
+ *
+ *  HT-6560B EIDE-controller support
+ *  To activate controller support use kernel parameter "ide0=ht6560b".
+ *  Use hdparm utility to enable PIO mode support.
+ *
+ *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
+ *             Jan Evert van Grootheest   <janevert@iae.nl>
+ *
+ *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_HT6560B_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_HT6560B_MODULE */
+
+/* #define DEBUG */  /* remove comments for DEBUG messages */
+
+/*
+ * The special i/o-port that HT-6560B uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit2 (0x04): "1" enables FIFO function
+ *    bit5 (0x20): "1" enables prefetched data read function  (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit1 (0x02): "1" enables prefetched data read function
+ *    bit2 (0x04): "0" enables multi-master system	      (?)
+ *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
+ */
+#define HT_CONFIG_PORT	  0x3e6
+#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+/*
+ * FIFO + PREFETCH (both a/b-model)
+ */
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF	  0x01
+#define HT_PREFETCH_MODE  0x20
+
+/*
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use IDE_SELECT_REG to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives.   [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
+ * of the value is the Active Time  (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
+ *
+ * Timing byte consists of
+ *	High nibble:  Recovery Cycle Time  (rt)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ *	Low nibble:   Active Cycle Time	   (at)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ * You can obtain optimized timing values by running Holtek IDESETUP.COM
+ * for DOS. DOS drivers get their timing values from command line, where
+ * the first value is the Recovery Time and the second value is the
+ * Active Time for each drive. Smaller value gives higher speed.
+ * In case of failures you should probably fall back to a higher value.
+ */
+#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
+
+/*
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+static void ht6560b_selectproc (ide_drive_t *drive)
+{
+	unsigned long flags;
+	static u8 current_select = 0;
+	static u8 current_timing = 0;
+	u8 select, timing;
+	
+	local_irq_save(flags);
+	
+	select = HT_CONFIG(drive);
+	timing = HT_TIMING(drive);
+	
+	if (select != current_select || timing != current_timing) {
+		current_select = select;
+		current_timing = timing;
+		if (drive->media != ide_disk || !drive->present)
+			select |= HT_PREFETCH_MODE;
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+		/*
+		 * Set timing for this drive:
+		 */
+		HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
+#ifdef DEBUG
+		printk("ht6560b: %s: select=%#x timing=%#x\n",
+			drive->name, select, timing);
+#endif
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+static int __init try_to_init_ht6560b(void)
+{
+	u8 orig_value;
+	int i;
+	
+	/* Autodetect ht6560b */
+	if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
+		return 0;
+	
+	for (i=3;i>0;i--) {
+		outb(0x00, HT_CONFIG_PORT);
+		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+			outb(orig_value, HT_CONFIG_PORT);
+			return 0;
+		}
+	}
+	outb(0x00, HT_CONFIG_PORT);
+	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+		outb(orig_value, HT_CONFIG_PORT);
+		return 0;
+	}
+	/*
+	 * Ht6560b autodetected
+	 */
+	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+	(void) inb(0x1f7);               /* IDE_STATUS_REG */
+	
+	printk("\nht6560b " HT6560B_VERSION
+	       ": chipset detected and initialized"
+#ifdef DEBUG
+	       " with debug enabled"
+#endif
+		);
+	return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+{
+	int active_time, recovery_time;
+	int active_cycles, recovery_cycles;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+	
+        if (pio) {
+		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+		
+		/*
+		 *  Just like opti621.c we try to calculate the
+		 *  actual cycle time for recovery and activity
+		 *  according system bus speed.
+		 */
+		active_time = ide_pio_timings[pio].active_time;
+		recovery_time = d.cycle_time 
+			- active_time
+			- ide_pio_timings[pio].setup_time;
+		/*
+		 *  Cycle times should be Vesa bus cycles
+		 */
+		active_cycles   = (active_time   * bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+		/*
+		 *  Upper and lower limits
+		 */
+		if (active_cycles   < 2)  active_cycles   = 2;
+		if (recovery_cycles < 2)  recovery_cycles = 2;
+		if (active_cycles   > 15) active_cycles   = 15;
+		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+		
+		return (u8)((recovery_cycles << 4) | active_cycles);
+	} else {
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+		
+		return HT_TIMING_DEFAULT;    /* default setting */
+	}
+}
+
+/*
+ *  Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, u8 state)
+{
+	unsigned long flags;
+	int t = HT_PREFETCH_MODE << 8;
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	/*
+	 *  Prefetch mode and unmask irq seems to conflict
+	 */
+	if (state) {
+		drive->drive_data |= t;   /* enable prefetch mode */
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+	} else {
+		drive->drive_data &= ~t;  /* disable prefetch mode */
+		drive->no_unmask = 0;
+	}
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	u8 timing;
+	
+	switch (pio) {
+	case 8:         /* set prefetch off */
+	case 9:         /* set prefetch on */
+		ht_set_prefetch(drive, pio & 1);
+		return;
+	}
+	
+	timing = ht_pio2timings(drive, pio);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+void __init probe_ht6560b (void)
+{
+	int t;
+	
+	request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
+	ide_hwifs[0].chipset = ide_ht6560b;
+	ide_hwifs[1].chipset = ide_ht6560b;
+	ide_hwifs[0].selectproc = &ht6560b_selectproc;
+	ide_hwifs[1].selectproc = &ht6560b_selectproc;
+	ide_hwifs[0].tuneproc = &tune_ht6560b;
+	ide_hwifs[1].tuneproc = &tune_ht6560b;
+	ide_hwifs[0].serialized = 1;  /* is this needed? */
+	ide_hwifs[1].serialized = 1;  /* is this needed? */
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+			
+	/*
+	 * Setting default configurations for drives
+	 */
+	t = (HT_CONFIG_DEFAULT << 8);
+	t |= HT_TIMING_DEFAULT;
+	ide_hwifs[0].drives[0].drive_data = t;
+	ide_hwifs[0].drives[1].drive_data = t;
+	t |= (HT_SECONDARY_IF << 8);
+	ide_hwifs[1].drives[0].drive_data = t;
+	ide_hwifs[1].drives[1].drive_data = t;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init ht6560b_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ht6560b &&
+	    ide_hwifs[1].chipset != ide_ht6560b)
+                return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].selectproc = NULL;
+	ide_hwifs[1].selectproc = NULL;
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+
+	ide_hwifs[0].drives[0].drive_data = 0;
+	ide_hwifs[0].drives[1].drive_data = 0;
+	ide_hwifs[1].drives[0].drive_data = 0;
+	ide_hwifs[1].drives[1].drive_data = 0;
+	release_region(HT_CONFIG_PORT, 1);
+}
+
+#ifndef MODULE
+/*
+ * init_ht6560b:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ht6560b (void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return;
+	}
+	if (!try_to_init_ht6560b()) {
+                printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return;
+	}
+	probe_ht6560b();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
+
+int __init ht6560b_mod_init(void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return -ENODEV;
+	}
+
+	if (!try_to_init_ht6560b()) {
+		printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	probe_ht6560b();
+        if (ide_hwifs[0].chipset != ide_ht6560b &&
+            ide_hwifs[1].chipset != ide_ht6560b) {
+                ht6560b_release();
+                return -ENODEV;
+        }
+        return 0;
+}
+module_init(ht6560b_mod_init);
+
+void __init ht6560b_mod_exit(void)
+{
+        ht6560b_release();
+}
+module_exit(ht6560b_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ide-cs.c linux-2.4.21-rc3/drivers/ide/legacy/ide-cs.c
--- linux-2.4.20/drivers/ide/legacy/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/ide-cs.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,500 @@
+/*======================================================================
+
+    A driver for PCMCIA IDE/ATA disk cards
+
+    ide_cs.c 1.26 1999/11/16 02:10:49
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/major.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+#ifdef IDE4_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
+#endif
+};
+
+typedef struct ide_info_t {
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
+    struct tq_struct rel_task;
+} ide_info_t;
+
+static void ide_config(dev_link_t *link);
+static void ide_release(void *arg);
+static int ide_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide-cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ide_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    INIT_TQUEUE(&info->rel_task, ide_release, link);
+
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ide_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    ide_info_t *info = link->priv;
+    int ret;
+
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    if (link->state & DEV_CONFIG) {
+	schedule_task(&info->rel_task);
+	flush_scheduled_tasks();
+    }
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(info);
+    
+} /* ide_detach */
+
+/*======================================================================
+
+    ide_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+int idecs_register (int arg1, int arg2, int irq)
+{
+        hw_regs_t hw;
+        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 */
+        return ide_register_hw(&hw, NULL);
+}
+
+void ide_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
+	}
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
+	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* 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) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release(link);
+
+} /* ide_config */
+
+/*======================================================================
+
+    After a card is removed, ide_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void ide_release(void *arg)
+{
+    dev_link_t *link = arg;
+    ide_info_t *info = link->priv;
+    
+    if (!(link->state & DEV_CONFIG))
+	return;
+
+    DEBUG(0, "ide_do_release(0x%p)\n", link);
+
+    if (info->ndev) {
+        /* FIXME: if this fails we need to queue the cleanup somehow
+           -- need to investigate the required PCMCIA magic */
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+
+    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+    if (link->io.NumPorts2)
+	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+    
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* ide_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the ide drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    ide_info_t *info = link->priv;
+
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    schedule_task(&info->rel_task);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
+
+/*====================================================================*/
+
+static int __init init_ide_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
+}
+
+static void __exit exit_ide_cs(void)
+{
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/macide.c linux-2.4.21-rc3/drivers/ide/legacy/macide.c
--- linux-2.4.20/drivers/ide/legacy/macide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/macide.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,153 @@
+/*
+ *  linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver
+ *
+ *     Copyright (C) 1998 by Michael Schmitz
+ *
+ *  This driver was written based on information obtained from the MacOS IDE
+ *  driver binary by Mikael Forselius
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_baboon.h>
+
+#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
+
+/*
+ * Generic IDE registers as offsets from the base
+ * These match MkLinux so they should be correct.
+ */
+
+#define IDE_DATA	0x00
+#define IDE_ERROR	0x04	/* see err-bits */
+#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
+#define IDE_SECTOR	0x0c	/* starting sector */
+#define IDE_LCYL	0x10	/* starting cylinder */
+#define IDE_HCYL	0x14	/* high byte of starting cyl */
+#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS	0x1c	/* see status-bits */
+#define IDE_CONTROL	0x38	/* control/altstatus */
+
+/*
+ * Mac-specific registers
+ */
+
+/*
+ * this register is odd; it doesn't seem to do much and it's
+ * not word-aligned like virtually every other hardware register
+ * on the Mac...
+ */
+
+#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
+				 *
+				 * Bit 0+1: some interrupt flags
+				 * Bit 2+3: some interrupt enable
+				 * Bit 4:   ??
+				 * Bit 5:   IDE interrupt flag (any hwif)
+				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
+				 * Bit 7:   Any interrupt condition
+				 */
+
+volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
+
+static int macide_offsets[IDE_NR_PORTS] = {
+    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
+    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
+};
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+	if (*ide_ifr & 0x20) {
+		*ide_ifr &= ~0x20;
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int state = baboon->mb_status & 0x04;
+
+	printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
+}
+#endif
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+void macide_init(void)
+{
+	hw_regs_t hw;
+	int index = -1;
+
+	switch (macintosh_config->ide_type) {
+	case MAC_IDE_QUADRA:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				quadra_ide_iops,
+				IRQ_NUBUS_F);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_PB:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				macide_pb_iops,
+				IRQ_NUBUS_C);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_BABOON:
+		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
+				0, 0, NULL,
+//				macide_baboon_iops,
+				IRQ_BABOON_1);
+		index = ide_register_hw(&hw, NULL);
+		if (index == -1) break;
+		if (macintosh_config->ident == MAC_MODEL_PB190) {
+
+			/* Fix breakage in ide-disk.c: drive capacity	*/
+			/* is not initialized for drives without a 	*/
+			/* hardware ID, and we can't get that without	*/
+			/* probing the drive which freezes a 190.	*/
+
+			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+        		drive->capacity = drive->cyl*drive->head*drive->sect;
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
+					IRQ_FLG_FAST, "mediabay",
+					macide_mediabay_interrupt);
+#endif
+		}
+		break;
+
+	default:
+	    return;
+	}
+
+        if (index != -1) {
+		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_PB)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+		else
+			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.c linux-2.4.21-rc3/drivers/ide/legacy/pdc4030.c
--- linux-2.4.20/drivers/ide/legacy/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/pdc4030.c	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,865 @@
+/*  -*- linux-c -*-
+ *  linux/drivers/ide/legacy/pdc4030.c		Version 0.90  May 27, 1999
+ *
+ *  Copyright (C) 1995-2002  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  Peter Denison <promise@pnd-pc.demon.co.uk>
+ *
+ *  This file provides support for the second port and cache of Promise
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
+ *
+ *  Thanks are due to Mark Lord for advice and patiently answering stupid
+ *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
+ *  especially Andre Hedrick.
+ *
+ *  Version 0.01	Initial version, #include'd in ide.c rather than
+ *                      compiled separately.
+ *                      Reads use Promise commands, writes as before. Drives
+ *                      on second channel are read-only.
+ *  Version 0.02        Writes working on second channel, reads on both
+ *                      channels. Writes fail under high load. Suspect
+ *			transfers of >127 sectors don't work.
+ *  Version 0.03        Brought into line with ide.c version 5.27.
+ *                      Other minor changes.
+ *  Version 0.04        Updated for ide.c version 5.30
+ *                      Changed initialization strategy
+ *  Version 0.05	Kernel integration.  -ml
+ *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
+ *  Version 0.07	Added support for DC4030 variants
+ *			Secondary interface autodetection
+ *  Version 0.08	Renamed to pdc4030.c
+ *  Version 0.09	Obsolete - never released - did manual write request
+ *			splitting before max_sectors[major][minor] available.
+ *  Version 0.10	Updated for 2.1 series of kernels
+ *  Version 0.11	Updated for 2.3 series of kernels
+ *			Autodetection code added.
+ *
+ *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
+ */
+
+/*
+ * Once you've compiled it in, you'll have to also enable the interface
+ * setup routine from the kernel command line, as in 
+ *
+ *	'linux ide0=dc4030' or 'linux ide1=dc4030'
+ *
+ * It should now work as a second controller also ('ide1=dc4030') but only
+ * if you DON'T have BIOS V4.44, which has a bug. If you have this version
+ * and EPROM programming facilities, you need to fix 4 bytes:
+ * 	2496:	81	81
+ *	2497:	3E	3E
+ *	2498:	22	98	*
+ *	2499:	06	05	*
+ *	249A:	F0	F0
+ *	249B:	01	01
+ *	...
+ *	24A7:	81	81
+ *	24A8:	3E	3E
+ *	24A9:	22	98	*
+ *	24AA:	06	05	*
+ *	24AB:	70	70
+ *	24AC:	01	01
+ *
+ * As of January 1999, Promise Technology Inc. have finally supplied me with
+ * some technical information which has shed a glimmer of light on some of the
+ * problems I was having, especially with writes. 
+ *
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
+ */
+
+#define DEBUG_READ
+#define DEBUG_WRITE
+#define __PROMISE_4030
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "pdc4030.h"
+
+static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+
+/*
+ * promise_selectproc() is invoked by ide.c
+ * in preparation for access to the specified drive.
+ */
+static void promise_selectproc (ide_drive_t *drive)
+{
+	unsigned int number;
+
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	HWIF(drive)->OUTB(number, IDE_FEATURE_REG);
+}
+
+/*
+ * pdc4030_cmd handles the set of vendor specific commands that are initiated
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
+ */
+int pdc4030_cmd(ide_drive_t *drive, u8 cmd)
+{
+	u32 timeout;
+	u8 status_val;
+
+	promise_selectproc(drive);	/* redundant? */
+	HWIF(drive)->OUTB(0xF3, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(cmd, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	timeout = HZ * 10;
+	timeout += jiffies;
+	do {
+		if(time_after(jiffies, timeout)) {
+			return 2; /* device timed out */
+		}
+		/* Delays at least 10ms to give interface a chance */
+		mdelay(10);
+		status_val = HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (status_val != 0x50 && status_val != 0x70);
+
+	if(status_val == 0x50)
+		return 0; /* device returned success */
+	else
+		return 1; /* device returned failure */
+}
+
+/*
+ * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
+ */
+int pdc4030_identify(ide_drive_t *drive)
+{
+	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
+}
+
+int enable_promise_support;
+
+/*
+ * setup_pdc4030()
+ * Completes the setup of a Promise DC4030 controller card, once found.
+ */
+int __init setup_pdc4030(ide_hwif_t *hwif)
+{
+        ide_drive_t *drive;
+	ide_hwif_t *hwif2;
+	struct dc_ident ident;
+	int i;
+	ide_startstop_t startstop;
+	
+	if (!hwif) return 0;
+
+	drive = &hwif->drives[0];
+	hwif2 = &ide_hwifs[hwif->index+1];
+	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+		return 1;
+
+	if (hwif->INB(IDE_NSECTOR_REG) == 0xFF ||
+	    hwif->INB(IDE_SECTOR_REG) == 0xFF) {
+		return 0;
+	}
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(0x08, IDE_CONTROL_REG);
+	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
+		return 0;
+	}
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+		printk(KERN_INFO
+			"%s: Failed Promise read config!\n",hwif->name);
+		return 0;
+	}
+	hwif->ata_input_data(drive, &ident, SECTOR_WORDS);
+	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+		return 0;
+	}
+	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
+	switch(ident.type) {
+		case 0x43:	printk("DC4030VL-2, "); break;
+		case 0x41:	printk("DC4030VL-1, "); break;
+		case 0x40:	printk("DC4030VL, "); break;
+		default:
+			printk("unknown - type 0x%02x - please report!\n"
+			       ,ident.type);
+			printk("Please e-mail the following data to "
+			       "promise@pnd-pc.demon.co.uk along with\n"
+			       "a description of your card and drives:\n");
+			for (i=0; i < 0x90; i++) {
+				printk("%02x ", ((unsigned char *)&ident)[i]);
+				if ((i & 0x0f) == 0x0f) printk("\n");
+			}
+			return 0;
+	}
+	printk("%dKB cache, ",(int)ident.cache_mem);
+	switch(ident.irq) {
+            case 0x00: hwif->irq = 14; break;
+            case 0x01: hwif->irq = 12; break;
+            default:   hwif->irq = 15; break;
+	}
+	printk("on IRQ %d\n",hwif->irq);
+
+	/*
+	 * Once found and identified, we set up the next hwif in the array
+	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
+	 * and other settings as the main hwif. This gives us two "mated"
+	 * hwifs pointing to the Promise card.
+	 *
+	 * We also have to shift the default values for the remaining
+	 * interfaces "up by one" to make room for the second interface on the
+	 * same set of values.
+	 */
+
+	hwif->chipset	= hwif2->chipset = ide_pdc4030;
+	hwif->mate	= hwif2;
+	hwif2->mate	= hwif;
+	hwif2->channel	= 1;
+	hwif->rqsize	= hwif2->rqsize = 127;
+	hwif->addressing = hwif2->addressing = 1;
+	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
+	hwif->serialized = hwif2->serialized = 1;
+	/* DC4030 hosted drives need their own identify... */
+	hwif->identify = hwif2->identify = &pdc4030_identify;
+
+	/* Shift the remaining interfaces up by one */
+	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
+		ide_hwif_t *h = &ide_hwifs[i];
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif /* DEBUG */
+		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
+		h->noprobe = (h-1)->noprobe;
+	}
+	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
+	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
+	hwif2->irq = hwif->irq;
+	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
+	for (i=0; i<2 ; i++) {
+		hwif->drives[i].io_32bit = 3;
+		hwif2->drives[i].io_32bit = 3;
+		hwif->drives[i].keep_settings = 1;
+		hwif2->drives[i].keep_settings = 1;
+		if (!ident.current_tm[i].cyl)
+			hwif->drives[i].noprobe = 1;
+		if (!ident.current_tm[i+2].cyl)
+			hwif2->drives[i].noprobe = 1;
+	}
+	
+	/* Now override the normal ide disk read/write */
+	hwif->rw_disk = promise_rw_disk;
+	hwif2->rw_disk = promise_rw_disk;
+	
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[hwif->index]);
+	probe_hwif_init(&ide_hwifs[hwif2->index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+        return 1;
+}
+
+/*
+ * detect_pdc4030()
+ * Tests for the presence of a DC4030 Promise card on this interface
+ * Returns: 1 if found, 0 if not found
+ */
+int __init detect_pdc4030(ide_hwif_t *hwif)
+{
+	ide_drive_t *drive = &hwif->drives[0];
+
+	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
+		return 0;
+	}
+	hwif->OUTB(0xF3, IDE_SECTOR_REG);
+	hwif->OUTB(0x14, IDE_SELECT_REG);
+	hwif->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	
+	ide_delay_50ms();
+
+	if (hwif->INB(IDE_ERROR_REG) == 'P' &&
+	    hwif->INB(IDE_NSECTOR_REG) == 'T' &&
+	    hwif->INB(IDE_SECTOR_REG) == 'I') {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+#ifndef MODULE
+void __init ide_probe_for_pdc4030(void)
+#else
+int ide_probe_for_pdc4030(void)
+#endif
+{
+	unsigned int	index;
+	ide_hwif_t	*hwif;
+
+#ifndef MODULE
+	if (enable_promise_support == 0)
+		return;
+#endif
+
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
+#ifndef MODULE
+			setup_pdc4030(hwif);
+#else
+			return setup_pdc4030(hwif);
+#endif
+		}
+	}
+#ifdef MODULE
+	return 0;
+#endif
+}
+
+void __init release_pdc4030(ide_hwif_t *hwif, ide_hwif_t *mate)
+{
+	hwif->chipset = ide_unknown;
+	hwif->selectproc = NULL;
+	hwif->serialized = 0;
+	hwif->drives[0].io_32bit = 0;
+	hwif->drives[1].io_32bit = 0;
+	hwif->drives[0].keep_settings = 0;
+	hwif->drives[1].keep_settings = 0;
+	hwif->drives[0].noprobe = 0;
+	hwif->drives[1].noprobe = 0;
+
+	if (mate != NULL) {
+		mate->chipset = ide_unknown;
+		mate->selectproc = NULL;
+		mate->serialized = 0;
+		mate->drives[0].io_32bit = 0;
+		mate->drives[1].io_32bit = 0;
+		mate->drives[0].keep_settings = 0;
+		mate->drives[1].keep_settings = 0;
+		mate->drives[0].noprobe = 0;
+		mate->drives[1].noprobe = 0;
+	}
+}
+
+#ifndef MODULE
+/*
+ * init_pdc4030:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_pdc4030(void)
+{
+	enable_promise_support = 1;
+}
+
+#else
+
+MODULE_AUTHOR("Peter Denison");
+MODULE_DESCRIPTION("Support of Promise 4030 VLB series IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init pdc4030_mod_init(void)
+{
+	if (enable_promise_support == 0)
+		enable_promise_support = 1;
+
+	if (!ide_probe_for_pdc4030())
+		return -ENODEV;
+        return 0;
+}
+module_init(pdc4030_mod_init);
+
+void __init pdc4030_mod_exit(void)
+{
+	unsigned int    index;
+	ide_hwif_t      *hwif;
+
+	if (enable_promise_support == 0)
+		return;
+ 
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_pdc4030) {
+			ide_hwif_t *mate = &ide_hwifs[hwif->index+1];
+			if (mate->chipset == ide_pdc4030)
+				release_pdc4030(hwif, mate);
+			else
+				release_pdc4030(hwif, NULL);
+                }
+        }
+	enable_promise_support = 0;
+}
+module_exit(pdc4030_mod_exit);
+#endif
+
+/*
+ * promise_read_intr() is the handler for disk read/multread interrupts
+ */
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
+{
+	int total_remaining;
+	unsigned int sectors_left, sectors_avail, nsect;
+	struct request *rq;
+	ata_status_t status;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	unsigned long flags;
+	char *to;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	if (!OK_STAT(status.all, DATA_READY, BAD_R_STAT))
+		return DRIVER(drive)->error(drive,
+			"promise_read_intr", status.all);
+
+read_again:
+	do {
+		sectors_left = HWIF(drive)->INB(IDE_NSECTOR_REG);
+		HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (HWIF(drive)->INB(IDE_NSECTOR_REG) != sectors_left);
+	rq = HWGROUP(drive)->rq;
+	sectors_avail = rq->nr_sectors - sectors_left;
+	if (!sectors_avail)
+		goto read_again;
+
+read_next:
+	rq = HWGROUP(drive)->rq;
+	nsect = rq->current_nr_sectors;
+	if (nsect > sectors_avail)
+		nsect = sectors_avail;
+	sectors_avail -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	to = ide_map_buffer(rq, &flags);
+	HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef DEBUG_READ
+	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+	       rq->sector+nsect-1,
+#ifdef CONFIG_IDE_TASKFILE_IO
+		(unsigned long) to,
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		(unsigned long) rq->buffer,
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	       rq->nr_sectors-nsect);
+#endif /* DEBUG_READ */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	ide_unmap_buffer(to, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	rq->buffer += nsect<<9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	rq->sector += nsect;
+	rq->errors = 0;
+	rq->nr_sectors -= nsect;
+	total_remaining = rq->nr_sectors;
+	if ((rq->current_nr_sectors -= nsect) <= 0) {
+		DRIVER(drive)->end_request(drive, 1);
+	}
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
+	if (total_remaining > 0) {
+		if (sectors_avail)
+			goto read_next;
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		if (status.b.drq)
+			goto read_again;
+		if (status.b.bsy) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_read_intr,
+					WAIT_CMD,
+					NULL);
+#ifdef DEBUG_READ
+			printk(KERN_DEBUG "%s: promise_read: waiting for"
+			       "interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+			return ide_started;
+		}
+		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+		       "!DRQ !BUSY\n", drive->name);
+		return DRIVER(drive)->error(drive,
+				"promise read intr", status.all);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
+ */
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	int i;
+
+	if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_complete_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: completion timeout - still busy!\n",
+		       drive->name);
+		return DRIVER(drive)->error(drive, "busy timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	hwgroup->poll_timeout = 0;
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+#endif /* DEBUG_WRITE */
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		DRIVER(drive)->end_request(drive, 1);
+	}
+	return ide_stopped;
+}
+
+/*
+ * 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;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		unsigned long flags;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		buffer = rq->buffer;
+
+		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct buffer_head *bh = rq->bh->b_reqnext;
+
+			/* end early early we ran out of requests */
+			if (!bh) {
+				mcount = 0;
+			} else {
+				rq->bh			= bh;
+				rq->current_nr_sectors	= bh->b_size >> 9;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer		= bh->b_data;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+#ifdef CONFIG_IDE_TASKFILE_IO
+		ide_unmap_buffer(buffer, &flags);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	} 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)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_write_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+		return DRIVER(drive)->error(drive, "write timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	/*
+	 * Now write out last 4 sectors and poll for not BUSY
+	 */
+	promise_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (hwgroup->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
+		drive->name, HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+	return ide_started;
+}
+
+/*
+ * promise_write() transfers a block of one or more sectors of data to a
+ * drive as part of a disk write operation. All but 4 sectors are transferred
+ * in the first attempt, then the interface is polled (nicely!) for completion
+ * before the final 4 sectors are transferred. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
+ */
+static ide_startstop_t promise_write (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
+
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+	       "buffer=%p\n", drive->name, rq->sector,
+	       rq->sector + rq->nr_sectors - 1, rq->buffer);
+#endif /* DEBUG_WRITE */
+
+	/*
+	 * If there are more than 4 sectors to transfer, do n-4 then go into
+	 * the polling strategy as defined above.
+	 */
+	if (rq->nr_sectors > 4) {
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
+	} else {
+	/*
+	 * There are 4 or fewer sectors to transfer, do them all in one go
+	 * and wait for NOT BUSY.
+	 */
+		if (promise_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&promise_complete_pollfunc,
+				HZ/100,
+				NULL);
+
+#ifdef DEBUG_WRITE
+		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
+			"status = %02x\n", drive->name,
+			HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+		return ide_started;
+	}
+}
+
+/*
+ * do_pdc4030_io() is called from promise_rw_disk, having had the block number
+ * 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.
+ */
+#ifndef CONFIG_IDE_TASKFILE_IO
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+{
+#else /* CONFIG_IDE_TASKFILE_IO */
+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;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	ide_startstop_t startstop;
+	unsigned long timeout;
+	u8 stat = 0;
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	if (IDE_CONTROL_REG)
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive, 0);
+	HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+	HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	switch(rq->cmd) {
+	case READ:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
+		timeout = jiffies + HZ/20; /* 50ms wait */
+		do {
+			stat = HWIF(drive)->INB(IDE_STATUS_REG);
+			if (stat & DRQ_STAT) {
+				udelay(1);
+				return promise_read_intr(drive);
+			}
+			if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {
+#ifdef DEBUG_READ
+				printk(KERN_DEBUG "%s: read: waiting for "
+						"interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+				ide_set_handler(drive,
+						&promise_read_intr,
+						WAIT_CMD,
+						NULL);
+				return ide_started;
+			}
+			udelay(1);
+		} while (time_before(jiffies, timeout));
+
+		printk(KERN_ERR "%s: reading: No DRQ and not "
+				"waiting - Odd!\n", drive->name);
+		return ide_stopped;
+	case WRITE:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing "
+				"PROMISE_WRITE\n", drive->name);
+			return startstop;
+	    	}
+		if (!drive->unmask)
+			local_irq_disable();
+		HWGROUP(drive)->wrq = *rq; /* scratchpad */
+		return promise_write(drive);
+	default:
+		printk("KERN_WARNING %s: bad command: %d\n",
+			drive->name, rq->cmd);
+		DRIVER(drive)->end_request(drive, 0);
+		return ide_stopped;
+	}
+}
+
+static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	/* The four drives on the two logical (one physical) interfaces
+	   are distinguished by writing the drive number (0-3) to the
+	   Feature register.
+	   FIXME: Is promise_selectproc now redundant??
+	*/
+	int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+#ifndef CONFIG_IDE_TASKFILE_IO
+	ide_hwif_t *hwif = HWIF(drive);
+
+	BUG_ON(rq->nr_sectors > 127);
+
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+#ifdef DEBUG
+	printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+		"buffer=0x%08lx\n", drive->name,
+		(rq->cmd==READ)?"read":"writ", block,
+		rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+	hwif->OUTB(drive_number, IDE_FEATURE_REG);
+	hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG);
+	hwif->OUTB(block,IDE_SECTOR_REG);
+	hwif->OUTB(block>>=8,IDE_LCYL_REG);
+	hwif->OUTB(block>>=8,IDE_HCYL_REG);
+	hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+
+	return do_pdc4030_io(drive, rq);
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+	struct hd_drive_task_hdr	taskfile;
+	ide_task_t			args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.feature	= drive_number;
+	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->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));
+	/* We can't call ide_cmd_type_parser here, since it won't understand
+	   our command, but that doesn't matter, since we don't use the
+	   generic interrupt handlers either. Setup the bits of args that we
+	   do need.
+	*/
+	args.handler		= NULL;
+	args.rq			= (struct request *) rq;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.h linux-2.4.21-rc3/drivers/ide/legacy/pdc4030.h
--- linux-2.4.20/drivers/ide/legacy/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/pdc4030.h	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/legacy/pdc4030.h
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & authors
+ */
+
+/*
+ * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
+ */
+
+#ifndef IDE_PROMISE_H
+#define IDE_PROMISE_H
+
+#include <linux/config.h>
+
+#ifndef CONFIG_BLK_DEV_PDC4030
+# ifdef _IDE_DISK
+
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ide_startstop_t promise_rw_disk(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+        return ide_stopped;
+}
+# endif /* _IDE_DISK */
+#else /* CONFIG_BLK_DEV_PDC4030 */
+# ifdef _IDE_DISK
+#  define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+# endif /* _IDE_DISK */
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+#ifdef __PROMISE_4030
+#define	PROMISE_EXTENDED_COMMAND	0xF0
+#define	PROMISE_READ			0xF2
+#define	PROMISE_WRITE			0xF3
+/* Extended commands - main command code = 0xf0 */
+#define	PROMISE_GET_CONFIG		0x10
+#define	PROMISE_IDENTIFY		0x20
+
+struct translation_mode {
+	u16	cyl;
+	u8	head;
+	u8	sect;
+};
+
+struct dc_ident {
+	u8	type;
+	u8	unknown1;
+	u8	hw_revision;
+	u8	firmware_major;
+	u8	firmware_minor;
+	u8	bios_address;
+	u8	irq;
+	u8	unknown2;
+	u16	cache_mem;
+	u16	unknown3;
+	u8	id[2];
+	u16	info;
+	struct translation_mode current_tm[4];
+	u8	pad[SECTOR_WORDS*4 - 32];
+};
+
+#endif /* __PROMISE_4030 */
+
+#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/q40ide.c linux-2.4.21-rc3/drivers/ide/legacy/q40ide.c
--- linux-2.4.20/drivers/ide/legacy/q40ide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/q40ide.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,150 @@
+/*
+ *  linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ *     (c) Richard Zidlicky
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/ide.h>
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define Q40IDE_NUM_HWIFS	2
+
+#define PCIDE_BASE1	0x1f0
+#define PCIDE_BASE2	0x170
+#define PCIDE_BASE3	0x1e8
+#define PCIDE_BASE4	0x168
+#define PCIDE_BASE5	0x1e0
+#define PCIDE_BASE6	0x160
+
+static const ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
+    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
+    PCIDE_BASE6 */
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+/* used to do addr translation here but it is easier to do in setup ports */
+/*#define IDE_OFF_B(x)	((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/
+
+#define IDE_OFF_B(x)	((ide_ioreg_t)((IDE_##x##_OFFSET)))
+#define IDE_OFF_W(x)	((ide_ioreg_t)((IDE_##x##_OFFSET)))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+    IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR),
+    IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS),
+    518/*IDE_OFF(CMD)*/
+};
+
+static int q40ide_default_irq(ide_ioreg_t base)
+{
+           switch (base) {
+	            case 0x1f0: return 14;
+		    case 0x170: return 15;
+		    case 0x1e8: return 11;
+		    default:
+			return 0;
+	   }
+}
+
+
+/*
+ * This is very similar to ide_setup_ports except that addresses
+ * are pretranslated for q40 ISA access
+ */
+void q40_ide_setup_ports ( hw_regs_t *hw,
+			ide_ioreg_t base, int *offsets,
+			ide_ioreg_t ctrl, ide_ioreg_t intr,
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
+{
+	int i;
+
+	for (i = 0; i < IDE_NR_PORTS; i++) {
+		/* BIG FAT WARNING: 
+		   assumption: only DATA port is ever used in 16 bit mode */
+		if ( i==0 )
+			hw->io_ports[i] = Q40_ISA_IO_W(base + offsets[i]);
+		else
+			hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]);
+	}
+	
+	hw->irq = irq;
+	hw->dma = NO_DMA;
+	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
+}
+
+
+
+/* 
+ * the static array is needed to have the name reported in /proc/ioports,
+ * hwif->name unfortunately isn´t available yet
+ */
+static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
+	"ide0", "ide1"
+};
+
+/*
+ *  Probe for Q40 IDE interfaces
+ */
+
+void q40ide_init(void)
+{
+    int i;
+    ide_hwif_t *hwif;
+    int index;
+    const char *name;
+
+    if (!MACH_IS_Q40)
+      return ;
+
+    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+	hw_regs_t hw;
+
+	name = q40_ide_names[i];
+	if (!request_region(pcide_bases[i], 8, name)) {
+		printk("could not reserve ports %lx-%lx for %s\n",
+		       pcide_bases[i],pcide_bases[i]+8,name);
+		continue;
+	}
+	if (!request_region(pcide_bases[i]+0x206, 1, name)) {
+		printk("could not reserve port %lx for %s\n",
+		       pcide_bases[i]+0x206,name);
+		release_region(pcide_bases[i], 8);
+		continue;
+	}
+	q40_ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i],
+			(int *)pcide_offsets,
+			(ide_ioreg_t)pcide_bases[i]+0x206, 0, NULL,
+//			m68kide_iops,
+			q40ide_default_irq(pcide_bases[i]));
+	index = ide_register_hw(&hw, &hwif);
+	// **FIXME**
+	if (index != -1)
+		hwif->mmio = 2;
+    }
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.c linux-2.4.21-rc3/drivers/ide/legacy/qd65xx.c
--- linux-2.4.20/drivers/ide/legacy/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/qd65xx.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/ide/legacy/qd65xx.c		Version 0.07	Sep 30, 2001
+ *
+ *  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.07	Second channel bug fix 
+ *
+ * QDI QD6500/QD6580 EIDE controller fast support
+ *
+ * Please set local bus speed using kernel parameter idebus
+ * 	for example, "idebus=33" stands for 33Mhz VLbus
+ * To activate controller support, use "ide0=qd65xx"
+ * To enable tuning, use "ide0=autotune"
+ * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_QD65XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_QD65XX_MODULE */
+
+#include "qd65xx.h"
+
+/*
+ * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
+ *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
+ *	-- qd6500 is a single IDE interface
+ *	-- qd6580 is a dual IDE interface
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ * More Information given by Petr Soucek (petr@ryston.cz)
+ * http://www.ryston.cz/petr/vlb
+ */
+
+/*
+ * base: Timer1
+ *
+ *
+ * base+0x01: Config (R/O)
+ *
+ * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
+ * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
+ * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
+ * bit 3: qd6500: 1 = disabled, 0 = enabled
+ *        qd6580: 1
+ * upper nibble:
+ *        qd6500: 1100
+ *        qd6580: either 1010 or 0101
+ *
+ *
+ * base+0x02: Timer2 (qd6580 only)
+ *
+ *
+ * base+0x03: Control (qd6580 only)
+ *
+ * bits 0-3 must always be set 1
+ * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
+ * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
+ *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
+ *                                                   channel 1 for hdc & hdd
+ * bit 1 : 1 = only disks on primary port
+ *         0 = disks & ATAPI devices on primary port
+ * bit 2-4 : always 0
+ * bit 5 : status, but of what ?
+ * bit 6 : always set 1 by dos driver
+ * bit 7 : set 1 for non-ATAPI devices on primary port
+ *	(maybe read-ahead and post-write buffer ?)
+ */
+
+static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
+
+static void qd_write_reg (u8 content, u8 reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb(content,reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+u8 __init qd_read_reg (u8 reg)
+{
+	unsigned long flags;
+	u8 read;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	read = inb(reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return read;
+}
+
+/*
+ * qd_select:
+ *
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+
+static void qd_select (ide_drive_t *drive)
+{
+	u8 index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
+			(QD_TIMREG(drive) & 0x02);
+
+	if (timings[index] != QD_TIMING(drive))
+		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+}
+
+/*
+ * qd6500_compute_timing
+ *
+ * computes the timing value where
+ *	lower nibble represents active time,   in count of VLB clocks
+ *	upper nibble represents recovery time, in count of VLB clocks
+ */
+
+static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+{
+	u8 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);
+	} 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);
+	}
+
+	return((recovery_cycle<<4) | 0x08 | active_cycle);
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+	u8 active_cycle   = 17 - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
+	u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+
+	return((recovery_cycle<<4) | active_cycle);
+}
+
+/*
+ * qd_find_disk_type
+ *
+ * tries to find timing from dos driver's table
+ */
+
+static int qd_find_disk_type (ide_drive_t *drive,
+		int *active_time, int *recovery_time)
+{
+	struct qd65xx_timing_s *p;
+	char model[40];
+
+	if (!*drive->id->model) return 0;
+
+	strncpy(model,drive->id->model,40);
+	ide_fixstring(model,40,1); /* byte-swap */
+
+	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
+		if (!strncmp(p->model, model+p->offset, 4)) {
+			printk(KERN_DEBUG "%s: listed !\n", drive->name);
+			*active_time = p->active;
+			*recovery_time = p->recovery;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * qd_timing_ok:
+ *
+ * check whether timings don't conflict
+ */
+
+static int qd_timing_ok (ide_drive_t drives[])
+{
+	return (IDE_IMPLY(drives[0].present && drives[1].present,
+			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
+			          QD_TIMING(drives) == QD_TIMING(drives+1))));
+	/* if same timing register, must be same timing */
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing, and enables selectproc as needed
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	if (qd_timing_ok(hwif->drives)) {
+		qd_select(drive); /* selects once */
+		hwif->selectproc = NULL;
+	} else
+		hwif->selectproc = &qd_select;
+
+	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
+		&& drive->id->eide_pio >= 240) {
+
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+				drive->id->tPIO);
+		active_time = 110;
+		recovery_time = drive->id->eide_pio - 120;
+	}
+
+	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	int base = HWIF(drive)->select_data;
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+		pio = IDE_MIN(pio,4);
+
+		switch (pio) {
+			case 0: break;
+			case 3:
+				if (d.cycle_time >= 110) {
+					active_time = 86;
+					recovery_time = d.cycle_time - 102;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			case 4:
+				if (d.cycle_time >= 69) {
+					active_time = 70;
+					recovery_time = d.cycle_time - 61;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			default:
+				if (d.cycle_time >= 180) {
+					active_time = 110;
+					recovery_time = d.cycle_time - 120;
+				} else {
+					active_time = ide_pio_timings[pio].active_time;
+					recovery_time = d.cycle_time
+							-active_time;
+				}
+		}
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+	}
+
+	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+		qd_write_reg(0x5f, QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
+			"and post-write buffer on %s.\n",
+			drive->name, HWIF(drive)->name);
+	}
+
+	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+}
+
+/*
+ * qd_testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init qd_testreg(int port)
+{
+	u8 savereg;
+	u8 readreg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	savereg = inb_p(port);
+	outb_p(QD_TESTVAL, port);	/* safe value */
+	readreg = inb_p(port);
+	outb(savereg, port);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	if (savereg == QD_TESTVAL) {
+		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
+		printk(KERN_ERR "Assuming qd65xx is not present.\n");
+		return 1;
+	}
+
+	return (readreg != QD_TESTVAL);
+}
+
+/*
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+void __init qd_setup (int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (ide_drive_t *, u8 pio))
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+
+	hwif->chipset = ide_qd65xx;
+	hwif->channel = unit;
+	hwif->select_data = base;
+	hwif->config_data = config;
+	hwif->drives[0].drive_data = data0;
+	hwif->drives[1].drive_data = data1;
+	hwif->drives[0].io_32bit =
+	hwif->drives[1].io_32bit = 1;
+	hwif->tuneproc = tuneproc;
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+void __init qd_unsetup (int unit)
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+	u8 config = hwif->config_data;
+	int base = hwif->select_data;
+	void *tuneproc = (void *) hwif->tuneproc;
+
+	if (!(hwif->chipset == ide_qd65xx)) return;
+
+	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+	hwif->selectproc = NULL;
+	hwif->tuneproc = NULL;
+
+	if (tuneproc == (void *) qd6500_tune_drive) {
+		// will do it for both
+		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+	} else if (tuneproc == (void *) qd6580_tune_drive) {
+		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+		} else {
+			qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+		}
+	} else {
+		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+		printk(KERN_WARNING "keeping settings !\n");
+	}
+}
+
+/*
+ * qd_probe:
+ *
+ * looks at the specified baseport, and if qd found, registers & initialises it
+ * return 1 if another qd may be probed
+ */
+
+int __init qd_probe (int base)
+{
+	u8 config;
+	u8 unit;
+
+	config = qd_read_reg(QD_CONFIG_PORT);
+
+	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+		return 1;
+
+	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+	if ((config & 0xf0) == QD_CONFIG_QD6500) {
+
+		if (qd_testreg(base)) return 1;		/* bad register */
+
+		/* qd6500 found */
+
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+			ide_hwifs[unit].name, base);
+		
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+			config, QD_ID3);
+		
+		if (config & QD_CONFIG_DISABLED) {
+			printk(KERN_WARNING "qd6500 is disabled !\n");
+			return 1;
+		}
+
+		qd_setup(unit, base, config, QD6500_DEF_DATA,
+			QD6500_DEF_DATA, &qd6500_tune_drive);
+		return 1;
+	}
+
+	if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
+	    ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
+
+		u8 control;
+
+		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
+			/* bad registers */
+
+		/* qd6580 found */
+
+		control = qd_read_reg(QD_CONTROL_PORT);
+
+		printk(KERN_NOTICE "qd6580 at %#x\n", base);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+			config, control, QD_ID3);
+
+		if (control & QD_CONTR_SEC_DISABLED) {
+			/* secondary disabled */
+			printk(KERN_INFO "%s: qd6580: single IDE board\n",
+					ide_hwifs[unit].name);
+			qd_setup(unit, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 1;
+		} else {
+			/* secondary enabled */
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+					ide_hwifs[0].name,ide_hwifs[1].name);
+
+			qd_setup(0, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA,
+				&qd6580_tune_drive);
+			qd_setup(1, base, config | (control << 8),
+				QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 0; /* no other qd65xx possible */
+		}
+	}
+	/* no qd65xx found */
+	return 1;
+}
+
+#ifndef MODULE
+/*
+ * init_qd65xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_qd65xx (void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+}
+
+#else
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
+
+int __init qd65xx_mod_init(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+	if (ide_hwifs[0].chipset != ide_qd65xx &&
+	    ide_hwifs[1].chipset != ide_qd65xx)
+		return -ENODEV;
+	return 0;
+}
+module_init(qd65xx_mod_init);
+
+void __init qd65xx_mod_exit(void)
+{
+	qd_unsetup(0);
+	qd_unsetup(1);
+}
+module_exit(qd65xx_mod_exit);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.h linux-2.4.21-rc3/drivers/ide/legacy/qd65xx.h
--- linux-2.4.20/drivers/ide/legacy/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/qd65xx.h	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/legacy/qd65xx.h
+ *
+ * Copyright (c) 2000	Linus Torvalds & authors
+ */
+
+/*
+ * Authors:	Petr Soucek <petr@ryston.cz>
+ * 		Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+#define IDE_IMPLY(a,b)	((!(a)) || (b))
+
+#define QD_TIM1_PORT		(base)
+#define QD_CONFIG_PORT		(base+0x01)
+#define QD_TIM2_PORT		(base+0x02)
+#define QD_CONTROL_PORT		(base+0x03)
+
+#define QD_CONFIG_IDE_BASEPORT	0x01
+#define QD_CONFIG_BASEPORT	0x02
+#define QD_CONFIG_ID3		0x04
+#define QD_CONFIG_DISABLED	0x08
+#define QD_CONFIG_QD6500	0xc0
+#define QD_CONFIG_QD6580_A	0xa0
+#define QD_CONFIG_QD6580_B	0x50
+
+#define QD_CONTR_SEC_DISABLED	0x01
+
+#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)
+
+#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
+
+#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 */
+
+/* Drive specific timing taken from DOS driver v3.7 */
+
+struct qd65xx_timing_s {
+	char	offset;   /* ofset from the beginning of Model Number" */
+	char	model[4];    /* 4 chars from Model number, no conversion */
+	short	active;   /* active time */
+	short	recovery; /* recovery time */
+} qd65xx_timing [] = {
+	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
+	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
+	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
+	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
+	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
+	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
+	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
+	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
+	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
+	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
+	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
+	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
+	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
+	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
+	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
+	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
+	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
+	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
+	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
+	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
+	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
+	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
+	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
+	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
+	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
+	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
+	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
+	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
+	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
+	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
+	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
+	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
+	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
+	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
+	{  6, "61 0", 135, 285 },  /* WD AC160				*/
+	{  6, "1107", 135, 235 },  /* WD AC1170				*/
+	{  6, "2101", 110, 220 },  /* WD AC1210				*/
+	{  6, "4202", 135, 245 },  /* WD AC2420				*/
+	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
+	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
+	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
+	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
+	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
+	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
+	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
+	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
+	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
+	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
+	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
+	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
+	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
+	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
+	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
+	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
+	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
+	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
+	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
+	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
+	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
+	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
+	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
+	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
+	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
+	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
+	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
+	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
+	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
+	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
+	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
+	{  2, "2309", 175, 295 },  /* ST3290A				*/
+	{  2, "3358", 180, 310 },  /* ST3385A				*/
+	{  2, "6355", 180, 310 },  /* ST3655A				*/
+	{  2, "1900", 175, 270 },  /* ST9100A				*/
+	{  2, "1954", 175, 270 },  /* ST9145A				*/
+	{  2, "1909", 175, 270 },  /* ST9190AG				*/
+	{  2, "2953", 175, 270 },  /* ST9235A				*/
+	{  2, "1359", 175, 270 },  /* ST3195A				*/
+	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
+	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
+	{  4, "2253", 175, 300 },  /* HP C2235A				*/
+	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
+	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
+	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
+	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
+	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/umc8672.c linux-2.4.21-rc3/drivers/ide/legacy/umc8672.c
--- linux-2.4.20/drivers/ide/legacy/umc8672.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/legacy/umc8672.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,237 @@
+/*
+ *  linux/drivers/ide/legacy/umc8672.c		Version 0.05	Jul 31, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ *  This file provides support for the advanced features
+ *  of the UMC 8672 IDE interface.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	now configs/compiles separate from ide.c  -ml
+ *  Version 0.03	enhanced auto-tune, fix display bug
+ *  Version 0.05	replace sti() with restore_flags()  -ml
+ *			add detection of possible race condition  -ml
+ */
+
+/*
+ * VLB Controller Support from 
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="ide0=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test program supplied from UMC. 11 is the 
+ * highest speed (about PIO mode 3)
+ */
+#define REALLY_SLOW_IO		/* some systems can safely undef this */
+
+#include <linux/module.h>
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_UMC8672_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_UMC8672_MODULE */
+
+/*
+ * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
+ */
+#define UMC_DRIVE0      1              /* DOS measured drive speeds */
+#define UMC_DRIVE1      1              /* 0 to 11 allowed */
+#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
+#define UMC_DRIVE3      1              /* In case of crash reduce speed */
+
+static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const u8 pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
+
+/*       0    1    2    3    4    5    6    7    8    9    10   11      */
+static const u8 speedtab [3][12] = {
+	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+
+static void out_umc (char port,char wert)
+{
+	outb_p(port,0x108);
+	outb_p(wert,0x109);
+}
+
+static inline u8 in_umc (char port)
+{
+	outb_p(port,0x108);
+	return inb_p(0x109);
+}
+
+static void umc_set_speeds (u8 speeds[])
+{
+	int i, tmp;
+
+	outb_p(0x5A,0x108); /* enable umc */
+
+	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+	tmp = 0;
+	for (i = 3; i >= 0; i--) {
+		tmp = (tmp << 2) | speedtab[1][speeds[i]];
+	}
+	out_umc (0xdc,tmp);
+	for (i = 0;i < 4; i++) {
+		out_umc (0xd0+i,speedtab[2][speeds[i]]);
+		out_umc (0xd8+i,speedtab[2][speeds[i]]);
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+		speeds[0], speeds[1], speeds[2], speeds[3]);
+}
+
+static void tune_umc (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+		drive->name, pio, pio_to_umc[pio]);
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+int __init probe_umc8672 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!request_region(0x108, 2, "umc8672")) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+		return 1;
+	}
+	outb_p(0x5A,0x108); /* enable umc */
+	if (in_umc (0xd5) != 0xa0) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: not found\n");
+		release_region(0x108, 2);
+		return 1;  
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	umc_set_speeds (current_speeds);
+	local_irq_restore(flags);
+
+	ide_hwifs[0].chipset = ide_umc8672;
+	ide_hwifs[1].chipset = ide_umc8672;
+	ide_hwifs[0].tuneproc = &tune_umc;
+	ide_hwifs[1].tuneproc = &tune_umc;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init umc8672_release (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		local_irq_restore(flags);
+		return;
+	}
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;	
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+	ide_hwifs[0].channel = 0;
+	ide_hwifs[1].channel = 0;
+
+	outb_p(0xa5,0x108); /* disable umc */
+
+	release_region(0x108, 2);
+	local_irq_restore(flags);
+}
+
+#ifndef MODULE
+/*
+ * init_umc8672:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_umc8672 (void)
+{
+	if (probe_umc8672())
+		printk(KERN_ERR "init_umc8672: umc8672 controller not found.\n");
+}
+
+#else
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
+
+int __init umc8672_mod_init(void)
+{
+	if (probe_umc8672())
+		return -ENODEV;
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		umc8672_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(umc8672_mod_init);
+
+void __init umc8672_mod_exit(void)
+{
+        umc8672_release();
+}
+module_exit(umc8672_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/macide.c linux-2.4.21-rc3/drivers/ide/macide.c
--- linux-2.4.20/drivers/ide/macide.c	2001-01-04 23:25:55.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/macide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
- *
- *     Copyright (C) 1998 by Michael Schmitz
- *
- *  This driver was written based on information obtained from the MacOS IDE
- *  driver binary by Mikael Forselius
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/machw.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_baboon.h>
-
-#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_DATA	0x00
-#define IDE_ERROR	0x04	/* see err-bits */
-#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
-#define IDE_SECTOR	0x0c	/* starting sector */
-#define IDE_LCYL	0x10	/* starting cylinder */
-#define IDE_HCYL	0x14	/* high byte of starting cyl */
-#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS	0x1c	/* see status-bits */
-#define IDE_CONTROL	0x38	/* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
-				 *
-				 * Bit 0+1: some interrupt flags
-				 * Bit 2+3: some interrupt enable
-				 * Bit 4:   ??
-				 * Bit 5:   IDE interrupt flag (any hwif)
-				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
-				 * Bit 7:   Any interrupt condition
-				 */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-static int macide_offsets[IDE_NR_PORTS] = {
-    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
-    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
-};
-
-int macide_ack_intr(ide_hwif_t* hwif)
-{
-	if (*ide_ifr & 0x20) {
-		*ide_ifr &= ~0x20;
-		return 1;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int state = baboon->mb_status & 0x04;
-
-	printk("macide: media bay %s detected\n", state? "removal":"insertion");
-}
-#endif
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-void macide_init(void)
-{
-	hw_regs_t hw;
-	int index = -1;
-
-	switch (macintosh_config->ide_type) {
-	case MAC_IDE_QUADRA:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_PB:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_BABOON:
-		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
-				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
-
-			/* Fix breakage in ide-disk.c: drive capacity	*/
-			/* is not initialized for drives without a 	*/
-			/* hardware ID, and we cna't get that without	*/
-			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
-        		drive->capacity = drive->cyl*drive->head*drive->sect;
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
-					IRQ_FLG_FAST, "mediabay",
-					macide_mediabay_interrupt);
-#endif
-		}
-		break;
-
-	default:
-	    return;
-	}
-
-        if (index != -1) {
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk("ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk("ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk("ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk("ide%d: Unknown Macintosh IDE interface\n", index);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ns87415.c linux-2.4.21-rc3/drivers/ide/ns87415.c
--- linux-2.4.20/drivers/ide/ns87415.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ns87415.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,193 +0,0 @@
-/*
- * linux/drivers/ide/ns87415.c		Version 1.01  Mar. 18, 2000
- *
- * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	new = *old;
-
-	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->channel);
-	new = drive->present ? (new & ~bit) : (new | bit);
-
-	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
-	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
-	if (new != *old) {
-		unsigned char stat;
-
-		/*
-		 * Don't change DMA engine settings while Write Buffers
-		 * are busy.
-		 */
-		(void) pci_read_config_byte(dev, 0x43, &stat);
-		while (stat & 0x03) {
-			udelay(1);
-			(void) pci_read_config_byte(dev, 0x43, &stat);
-		}
-
-		*old = new;
-		(void) pci_write_config_dword(dev, 0x40, new);
-
-		/*
-		 * And let things settle...
-		 */
-		udelay(10);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void ns87415_selectproc (ide_drive_t *drive)
-{
-	ns87415_prepare_drive (drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	byte		dma_stat;
-
-	switch (func) {
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(hwif->dma_base+2);
-			outb(inb(hwif->dma_base)&~1, hwif->dma_base);	/* stop DMA */
-			outb(inb(hwif->dma_base)|6, hwif->dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);			/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_write:
-		case ide_dma_read:
-			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
-				return 0;
-			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
-			return 1;
-		case ide_dma_check:
-			if (drive->media != ide_disk)
-				return ide_dmaproc(ide_dma_off_quietly, drive);
-			/* Fallthrough... */
-		default:
-			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned int ctrl, using_inta;
-	byte progif;
-#ifdef __sparc_v9__
-	int timeout;
-	byte stat;
-#endif
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-	/*
-	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
-	 * Also, leave IRQ masked during drive probing, to prevent infinite
-	 * interrupts from a potentially floating INTA..
-	 *
-	 * IRQs get unmasked in selectproc when drive is first used.
-	 */
-	(void) pci_read_config_dword(dev, 0x40, &ctrl);
-	(void) pci_read_config_byte(dev, 0x09, &progif);
-	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->channel << 1));
-	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->channel));
-	if (hwif->mate) {
-		hwif->select_data = hwif->mate->select_data;
-	} else {
-		hwif->select_data = (unsigned long)
-					&ns87415_control[ns87415_count++];
-		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
-		if (using_inta)
-			ctrl &= ~(1 << 6);	/* unmask INTA */
-		*((unsigned int *)hwif->select_data) = ctrl;
-		(void) pci_write_config_dword(dev, 0x40, ctrl);
-
-		/*
-		 * Set prefetch size to 512 bytes for both ports,
-		 * but don't turn on/off prefetching here.
-		 */
-		pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
-		/*
-		 * XXX: Reset the device, if we don't it will not respond
-		 *      to SELECT_DRIVE() properly during first probe_hwif().
-		 */
-		timeout = 10000;
-		outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			udelay(50);
-			stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
-#endif
-	}
-
-	if (hwif->dma_base)
-		outb(0x60, hwif->dma_base + 2);
-
-	if (!using_inta)
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &ns87415_selectproc;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/opti621.c linux-2.4.21-rc3/drivers/ide/opti621.c
--- linux-2.4.20/drivers/ide/opti621.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/opti621.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,316 +0,0 @@
-/*
- *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
- *
- *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- *
- * OPTi is trademark of OPTi, Octek is trademark of Octek.
- *
- * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
- * and disassembled/traced setupvic.exe (DOS program).
- * It increases kernel code about 2 kB.
- * I don't have this card no more, but I hope I can get some in case
- * of needed development.
- * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
- * It has a place for a secondary connector in circuit, but nothing
- * is there. Also BIOS says no address for
- * secondary controller (see bellow in ide_init_opti621).
- * I've only tested this on my system, which only has one disk.
- * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
- * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
- * lockups). I tried the OCTEK double speed CD-ROM and
- * it does not work! But I can't boot DOS also, so it's probably
- * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
- * problems) and Seagate 1GB (as slave, WD as master). My experiences
- * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
- * it slows to about 100kB/s! I don't know why and I have
- * not this drive now, so I can't try it again.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe changes
- * in hdparm test).
- * After release of 0.1, I got some successful reports, so it might work.
- *
- * The main problem with OPTi is that some timings for master
- * and slave must be the same. For example, if you have master
- * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
- * got only one drive to set, but have to set both drives.
- * This is solved in compute_pios. If you don't set
- * the second drive, compute_pios use ide_get_best_pio_mode
- * for autoselect mode (you can change it to PIO 0, if you want).
- * If you then set the second drive to another PIO, the old value
- * (automatically selected) will be overrided by yours.
- * There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency which get
- * (use idebus=xx to select PCI bus speed).
- * Use ide0=autotune for automatical tune of the PIO modes.
- * If you get strange results, do not use this and set PIO manually
- * by hdparm.
- *
- * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8. 
- * Initial version of driver.
- * 
- * Version 0.2
- * Number 0.2 skipped.
- *
- * Version 0.3, Nov 29, 1997
- * by Mark Lord (probably), for 2.1.68
- * Updates for use with new IDE block driver.
- *
- * Version 0.4, Dec 14, 1997
- * by Jan Harkes
- * Fixed some errors and cleaned the code.
- *
- * Version 0.5, Jan 2, 1998
- * by Jaromir Koutek
- * Updates for use with (again) new IDE block driver.
- * Update of documentation.
- * 
- * Version 0.6, Jan 2, 1999
- * by Jaromir Koutek
- * Reversed to version 0.3 of the driver, because
- * 0.5 doesn't work.
- */
-
-#undef REALLY_SLOW_IO	/* most systems can safely undef this */
-#define OPTI621_DEBUG		/* define for debug messages */
-
-#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/ide.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define OPTI621_MAX_PIO 3
-/* In fact, I do not have any PIO 4 drive
- * (address: 25 ns, data: 70 ns, recovery: 35 ns),
- * but OPTi 82C621 is programmable and it can do (minimal values):
- * on 40MHz PCI bus (pulse 25 ns):
- *  address: 25 ns, data: 25 ns, recovery: 50 ns;
- * on 20MHz PCI bus (pulse 50 ns):
- *  address: 50 ns, data: 50 ns, recovery: 100 ns.
- */
-
-/* #define READ_PREFETCH 0 */
-/* Uncommnent for disable read prefetch.
- * There is some readprefetch capatibility in hdparm,
- * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inaccessible.
- * This (hw) read prefetch is safe on my drive.
- */
-
-#ifndef READ_PREFETCH
-#define READ_PREFETCH 0x40 /* read prefetch is enabled */
-#endif /* else read prefetch is disabled */
-
-#define READ_REG 0	/* index of Read cycle timing register */
-#define WRITE_REG 1	/* index of Write cycle timing register */
-#define CNTRL_REG 3	/* index of Control register */
-#define STRAP_REG 5	/* index of Strap register */
-#define MISC_REG 6	/* index of Miscellaneous register */
-
-int reg_base;
-
-#define PIO_NOT_EXIST 254
-#define PIO_DONT_KNOW 255
-
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-
-static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->drive_data
- *	second_contr - 0 for primary controller, 1 for secondary
- *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
- *	pio - PIO mode for selected drive (for other we don't know)
- */
-{
-	int d;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
-	for (d = 0; d < 2; ++d) {
-		drive = &hwif->drives[d];
-		if (drive->present) {
-			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
-#ifdef OPTI621_DEBUG
-			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
-#endif
-		} else {
-			drive->drive_data = PIO_NOT_EXIST;
-		}
-	}
-}
-
-int cmpt_clk(int time, int bus_speed)
-/* Returns (rounded up) time in clocks for time in ns,
- * with bus_speed in MHz.
- * Example: bus_speed = 40 MHz, time = 80 ns
- * 1000/40 = 25 ns (clk value),
- * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
- * Use idebus=xx to select right frequency.
- */
-{
-	return ((time*bus_speed+999)/1000);
-}
-
-static void write_reg(byte value, int reg)
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	outb(value, reg_base+reg);
-	outb(0x83, reg_base+2);
-}
-
-static byte read_reg(int reg)
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	byte ret;
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	ret=inb(reg_base+reg);
-	outb(0x83, reg_base+2);
-	return ret;
-}
-
-typedef struct pio_clocks_s {
-	int	address_time;	/* Address setup (clocks) */
-	int	data_time;	/* Active/data pulse (clocks) */
-	int	recovery_time;	/* Recovery time (clocks) */
-} pio_clocks_t;
-
-static void compute_clocks(int pio, pio_clocks_t *clks)
-{
-        if (pio != PIO_NOT_EXIST) {
-        	int adr_setup, data_pls;
-		int bus_speed = system_bus_clock();
-
- 	       	adr_setup = ide_pio_timings[pio].setup_time;
-  	      	data_pls = ide_pio_timings[pio].active_time;
-	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
-	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
-     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			- adr_setup-data_pls, bus_speed);
-     		if (clks->address_time<1) clks->address_time = 1;
-     		if (clks->address_time>4) clks->address_time = 4;
-     		if (clks->data_time<1) clks->data_time = 1;
-     		if (clks->data_time>16) clks->data_time = 16;
-     		if (clks->recovery_time<2) clks->recovery_time = 2;
-     		if (clks->recovery_time>17) clks->recovery_time = 17;
-	} else {
-		clks->address_time = 1;
-		clks->data_time = 1;
-		clks->recovery_time = 2;
-		/* minimal values */
-	}
- 
-}
-
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, byte pio)
-{
-	/* primary and secondary drives share some registers,
-	 * so we have to program both drives
-	 */
-	unsigned long flags;
-	byte pio1, pio2;
-	pio_clocks_t first, second;
-	int ax, drdy;
-	byte cycle1, cycle2, misc;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	/* sets drive->drive_data for both drives */
-	compute_pios(drive, pio);
- 	pio1 = hwif->drives[0].drive_data;
- 	pio2 = hwif->drives[1].drive_data;
-
-	compute_clocks(pio1, &first);
-	compute_clocks(pio2, &second);
-
-	/* ax = max(a1,a2) */
-	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
-
-	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
-
-	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
-	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
-	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
-
-#ifdef OPTI621_DEBUG
-	printk("%s: master: address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, first.data_time, first.recovery_time, drdy);
-	printk("%s: slave:  address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, second.data_time, second.recovery_time, drdy);
-#endif
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-
-     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	outb(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	outb(0xff, reg_base+5);		/* hmm, setupvic.exe does this ;-) */
-	inb(reg_base+CNTRL_REG); 	/* if reads 0xff, adapter not exist? */
-	read_reg(CNTRL_REG);		/* if reads 0xc0, no interface exist? */
-	read_reg(STRAP_REG);		/* read version, probably 0 */
-
-	/* program primary drive */
-	write_reg(0,      MISC_REG);	/* select Index-0 for Register-A */
-	write_reg(cycle1, READ_REG);	/* set read cycle timings */
-	write_reg(cycle1, WRITE_REG);	/* set write cycle timings */
-
-	/* program secondary drive */
-	write_reg(1,      MISC_REG);	/* select Index-1 for Register-B */
-	write_reg(cycle2, READ_REG);	/* set read cycle timings */
-	write_reg(cycle2, WRITE_REG);	/* set write cycle timings */
-
-	write_reg(0x85, CNTRL_REG);	/* use Register-A for drive 0 */
-					/* use Register-B for drive 1 */
-
- 	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
- 					/*  and read prefetch for both drives */
-
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * ide_init_opti621() is called once for each hwif found at boot.
- */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
-{
-	hwif->drives[0].drive_data = PIO_DONT_KNOW;
-	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/Makefile linux-2.4.21-rc3/drivers/ide/pci/Makefile
--- linux-2.4.20/drivers/ide/pci/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/Makefile	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,41 @@
+
+O_TARGET := idedriver-pci.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma100.o
+obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX)		+= amd74xx.o
+obj-$(CONFIG_BLK_DEV_CMD640)		+= cmd640.o
+obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
+obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
+obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
+#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.o
+obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
+obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)	+= pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000)		+= rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
+obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
+obj-$(CONFIG_BLK_DEV_TRIFLEX)		+= triflex.o
+
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC)		+= generic.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.c linux-2.4.21-rc3/drivers/ide/pci/adma100.c
--- linux-2.4.20/drivers/ide/pci/adma100.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/adma100.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,80 @@
+/*
+ *  linux/drivers/ide/pci/adma100.c -- basic support for Pacific Digital ADMA-100 boards
+ *
+ *     Created 09 Apr 2002 by Mark Lord
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "adma100.h"
+
+void __init init_hwif_adma100 (ide_hwif_t *hwif)
+{
+	unsigned long  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	void *v_admctl;
+
+	hwif->autodma  = 0;		// not compatible with normal IDE DMA transfers
+	hwif->dma_base = 0;		// disable DMA completely
+	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
+	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
+	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
+	iounmap(v_admctl);				// all done; unmap config regs
+	printk("ADMA100: initialized %s for basic PIO-only operation\n", hwif->name);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit adma100_init_one (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &adma100_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id adma100_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_ADMA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "ADMA100 IDE",
+	.id_table	= adma100_pci_tbl,
+	.probe		= adma100_init_one,
+};
+
+static int adma100_ide_init (void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void adma100_ide_exit (void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(adma100_ide_init);
+module_exit(adma100_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic PIO support for ADMA100 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.h linux-2.4.21-rc3/drivers/ide/pci/adma100.h
--- linux-2.4.20/drivers/ide/pci/adma100.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/adma100.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef ADMA_100_H
+#define ADMA_100_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_hwif_adma100(ide_hwif_t *);
+
+static ide_pci_device_t adma100_chipsets[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_ADMA100,
+		.name		= "ADMA100",
+		.init_setup	= NULL,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_adma100,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ADMA_100_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.c linux-2.4.21-rc3/drivers/ide/pci/aec62xx.c
--- linux-2.4.20/drivers/ide/pci/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/aec62xx.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,568 @@
+/*
+ * linux/drivers/ide/pci/aec62xx.c		Version 0.11	March 27, 2002
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "aec62xx.h"
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc = 0;
+
+#define AEC_MAX_DEVS		5
+
+static struct pci_dev *aec_devs[AEC_MAX_DEVS];
+static int n_aec_devs;
+
+#undef DEBUG_AEC_REGS
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	char *chipset_nums[] = {"error", "error", "error", "error",
+				"error", "error", "850UF",   "860",
+				 "860R",   "865",  "865R", "error"  };
+	int len;
+	int i;
+
+	for (i = 0; i < n_aec_devs; i++) {
+		struct pci_dev *dev	= aec_devs[i];
+		unsigned long iobase = pci_resource_start(dev, 4);
+		u8 c0 = 0, c1 = 0, art	= 0;
+#ifdef DEBUG_AEC_REGS
+		u8 uart			= 0;
+#endif /* DEBUG_AEC_REGS */
+
+		c0 = inb(iobase + 0x02);
+		c1 = inb(iobase + 0x0a);
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		(void) pci_read_config_byte(dev, 0x4a, &art);
+		p += sprintf(p, "                %sabled ",
+			(art&0x02)?" en":"dis");
+		p += sprintf(p, "                        %sabled\n",
+			(art&0x04)?" en":"dis");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s ",
+			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
+		p += sprintf(p, "            %s               %s\n",
+			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+			(void) pci_read_config_byte(dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0");
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+#endif /* DEBUG_AEC_REGS */
+		} else {
+			/*
+			 * case PCI_DEVICE_ID_ARTOP_ATP860:
+			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
+			 */
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+#endif /* DEBUG_AEC_REGS */
+		}
+	}
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return chipset_table->chipset_settings;
+}
+
+static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return chipset_table->ultra_settings;
+}
+
+static u8 aec62xx_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+#if 0
+			mode = (hwif->INB(hwif->dma_master) & 0x10) ? 4 : 3;
+#else
+			mode = (hwif->INB(((hwif->channel) ?
+					hwif->mate->dma_status :
+					hwif->dma_status)) & 0x10) ? 4 : 3;
+#endif
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		default:
+			return 1;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 d_conf		= 0;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 ultra = 0, ultra_conf = 0;
+	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+	tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 unit		= (drive->select.b.unit & 0x01);
+	u8 tmp1 = 0, tmp2 = 0;
+	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+	pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	switch (HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return ((int) aec6260_tune_chipset(drive, speed));
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return ((int) aec6210_tune_chipset(drive, speed));
+		default:
+			return -1;
+	}
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));	
+
+	if (!(speed))
+		return 0;
+
+	(void) aec62xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+	u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) aec62xx_tune_chipset(drive, speed);
+}
+
+static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int aec62xx_irq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+			printk(" AEC62XX time out ");
+#if 0
+			{
+				int i = 0;
+				u8 reg49h = 0;
+				pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+				for (i=0;i<256;i++)
+					pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+			}
+			return 0;
+#endif
+		default:
+			break;
+	}
+#if 0
+	{
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u8 tmp1 = 0, tmp2 = 0, mode6 = 0;
+
+		pci_read_config_byte(dev, 0x44, &tmp1);
+		pci_read_config_byte(dev, 0x45, &tmp2);
+		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+		mode6 = HWIF(drive)->INB(((hwif->channel) ?
+					   hwif->mate->dma_status :
+					   hwif->dma_status));
+		printk(" AEC6280 133=%x ", (mode6 & 0x10));
+	}
+#endif
+	return 0;
+}
+
+static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name)
+{
+	int bus_speed = system_bus_clock();
+
+	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(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	aec_devs[n_aec_devs++] = dev;
+
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		ide_pci_register_host_proc(&aec62xx_procs[0]);
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	if (bus_speed <= 33)
+		pci_set_drvdata(dev, (void *) aec6xxx_33_base);
+	else
+		pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+
+	return dev->irq;
+}
+
+static void __init init_hwif_aec62xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->speedproc = &aec62xx_tune_chipset;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		hwif->serialized = hwif->channel;
+		hwif->no_dsc = 1;
+	}
+
+	if (hwif->mate)
+		hwif->mate->serialized = hwif->serialized;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq	= &aec62xx_irq_timeout;
+	hwif->ide_dma_timeout	= &aec62xx_irq_timeout;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		u8 reg54h = 0;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ide_lock, flags);
+		pci_read_config_byte(dev, 0x54, &reg54h);
+		pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+		spin_unlock_irqrestore(&ide_lock, flags);
+	} else {
+		u8 ata66	= 0;
+		pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+	        if (!(hwif->udma_four))
+			hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+	}
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_aec62xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	unsigned long bar4reg = pci_resource_start(dev, 4);
+
+	if (inb(bar4reg+2) & 0x10) {
+		strcpy(d->name, "AEC6880");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6880R");
+	} else {
+		strcpy(d->name, "AEC6280");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6280R");
+	}
+
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	aec62xx_init_one	-	called when a AEC is found
+ *	@dev: the aec62xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id aec62xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AEC62xx IDE",
+	.id_table	= aec62xx_pci_tbl,
+	.probe		= aec62xx_init_one,
+};
+
+static int aec62xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void aec62xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(aec62xx_ide_init);
+module_exit(aec62xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.h linux-2.4.21-rc3/drivers/ide/pci/aec62xx.h
--- linux-2.4.20/drivers/ide/pci/aec62xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/aec62xx.h	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,171 @@
+#ifndef AEC62XX_H
+#define AEC62XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AEC62XX_TIMINGS
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	byte		chipset_settings;
+	byte		ultra_settings;
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+	{	XFER_UDMA_6,	0x31,	0x07	},
+	{	XFER_UDMA_5,	0x31,	0x06	},
+	{	XFER_UDMA_4,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x0a,	0x00	},
+	{	XFER_PIO_4,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+	{	XFER_UDMA_6,	0x41,	0x06	},
+	{	XFER_UDMA_5,	0x41,	0x05	},
+	{	XFER_UDMA_4,	0x41,	0x04	},
+	{	XFER_UDMA_3,	0x41,	0x03	},
+	{	XFER_UDMA_2,	0x41,	0x02	},
+	{	XFER_UDMA_1,	0x41,	0x01	},
+	{	XFER_UDMA_0,	0x41,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00	},
+	{	XFER_PIO_4,	0x41,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
+
+#define BUSCLOCK(D)	\
+	((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D)))
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc;
+
+static int aec62xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t aec62xx_procs[] __initdata = {
+	{
+		.name		= "aec62xx",
+		.set		= 1,
+		.get_info	= aec62xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_aec6x80(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_aec62xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_aec62xx(struct pci_dev *, const char *);
+static void init_hwif_aec62xx(ide_hwif_t *);
+static void init_dma_aec62xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP850UF,
+		.name		= "AEC6210",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860,
+		.name		= "AEC6260",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860R,
+		.name		= "AEC6260R",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865,
+		.name		= "AEC6X80",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865R,
+		.name		= "AEC6X80R",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	}
+};
+
+#endif /* AEC62XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.c linux-2.4.21-rc3/drivers/ide/pci/alim15x3.c
--- linux-2.4.20/drivers/ide/pci/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/alim15x3.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,916 @@
+/*
+ * linux/drivers/ide/pci/alim15x3.c		Version 0.17	2003/03/05
+ *
+ *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ *
+ *  Changes for ALi 156x ported from RH 8.0 driver changes by
+ *			Clear Zang
+ *
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
+ *
+ **********************************************************************
+ *  9/7/99 --Parts from the above author are included and need to be
+ *  converted into standard interface, once I finish the thought.
+ *
+ *  Recent changes
+ *	Don't use LBA48 mode on ALi <= 0xC4
+ *	Don't poke 0x79 with a non ALi northbridge
+ *	Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ *
+ *  Documentation
+ *	Chipset documentation available under NDA only
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "alim15x3.h"
+
+/*
+ *	ALi devices are not plug in. Otherwise these static values would
+ *	need to go. They ought to go away anyway
+ */
+ 
+static u8 m5229_revision;
+static u8 chip_is_1543c_e;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+static char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+static char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+
+/**
+ *	ali_get_info		-	generate proc file for ALi IDE
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the Ali devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	unsigned long bibma;
+	u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
+	char *q, *p = buffer;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	
+	bibma = pci_resource_start(bmide_dev, 4);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = inb(bibma + 0x02);
+	c1 = inb(bibma + 0x0a);
+
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel"
+		"-------------------secondary channel"
+		"---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s"
+		"                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s"
+		"                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT"
+		"                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT"
+		"                                %dT\n"
+		"Command Rec. Count:   %dT"
+		"                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n\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 " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) &&
+		    (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+		p += sprintf(p, q, t1, t2, t3, t4);
+	}
+
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings"
+		"--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s"
+		"                %s               %s\n"
+		"UDMA timings:     %s             %s"
+		"              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	ali15x3_tune_drive	-	set up a drive
+ *	@drive: drive to tune
+ *	@pio: unused
+ *
+ *	Select the best PIO timing for the drive in question. Then
+ *	program the controller for this drive set up
+ */
+ 
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	u8 s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = system_bus_clock();
+	int port = hwif->channel ? 0x5c : 0x58;
+	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	u8 cd_dma_fifo = 0;
+	int unit = drive->select.b.unit & 1;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+			r_clc = 0;
+	}
+	local_irq_save(flags);
+	
+	/* 
+	 * PIO mode => ATA FIFO on, ATAPI FIFO off
+	 */
+	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+	if (drive->media==ide_disk) {
+		if (unit) {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
+		} else {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
+		}
+	} else {
+		if (unit) {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+		} else {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+		}
+	}
+	
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	local_irq_restore(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+/**
+ *	ali15x3_can_ultra	-	check for ultra DMA support
+ *	@drive: drive to do the check
+ *
+ *	Check the drive and controller revisions. Return 0 if UDMA is
+ *	not available, or 1 if UDMA can be used. The actual rules for
+ *	the ALi are
+ *		No UDMA on revisions <= 0xC1
+ *		Disk only for revisions < 0xC2
+ *		Not WDC drives for revisions < 0xC2
+ *
+ *	FIXME: WDC ifdef needs to die
+ */
+ 
+static u8 ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+	if (m5229_revision < 0xC1) {	/* According to ALi */
+		return 0;
+	} else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+		    (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+		   (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ *	ali15x3_ratemask	-	generate DMA mode list
+ *	@drive: drive to compute against
+ *
+ *	Generate a list of the available DMA modes for the drive. 
+ *	FIXME: this function contains lots of bogus masking we can dump
+ *
+ *	Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
+ */
+ 
+static u8 ali15x3_ratemask (ide_drive_t *drive)
+{
+	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
+
+	if (m5229_revision >= 0xC4 && can_ultra) {
+		mode = 4;
+	} else if (m5229_revision >= 0xC2 && can_ultra) {
+		mode = 2;
+	} else if (can_ultra) {
+		return 1;
+	} else {
+		return 0;
+	}
+
+	/*
+	 *	If the drive sees no suitable cable then UDMA 33
+	 *	is the highest permitted mode
+	 */
+	 
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	ali15x3_tune_chipset	-	set up chiset for new speed
+ *	@drive: drive to configure for
+ *	@xferspeed: desired speed
+ *
+ *	Configure the hardware for the desired IDE transfer mode.
+ *	We also do the needed drive configuration through helpers
+ */
+ 
+static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 speed1		= speed;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 tmpbyte		= 0x00;
+	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
+
+	if (speed == XFER_UDMA_6)
+	{
+		speed1 = 0x47;
+		if(m5229_revision == 0xC4)
+			speed1 --;
+	}
+	if (speed < XFER_UDMA_0) {
+		u8 ultra_enable	= (unit) ? 0x7f : 0xf7;
+		/*
+		 * clear "ultra enable" bit
+		 */
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= ultra_enable;
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+
+		if (speed < XFER_SW_DMA_0)
+			ali15x3_tune_drive(drive, speed);
+	} else {
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= (0x0f << ((1-unit) << 2));
+		/*
+		 * enable ultra dma and set timing
+		 */
+		tmpbyte |= ((0x08 | ((4-speed1)&0x07)) << (unit << 2));
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+		if (speed >= XFER_UDMA_3) {
+			pci_read_config_byte(dev, 0x4b, &tmpbyte);
+			tmpbyte |= 1;
+			pci_write_config_byte(dev, 0x4b, tmpbyte);
+		}
+	}
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/**
+ *	config_chipset_for_dma	-	set up DMA mode
+ *	@drive: drive to configure for
+ *
+ *	Place a drive into DMA mode and tune the chipset for
+ *	the selected speed.
+ *
+ *	Returns true if DMA mode can be used
+ */
+ 
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) ali15x3_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	ali15x3_config_drive_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Configure a drive for DMA operation. If DMA is not possible we
+ *	drop the drive into PIO mode instead.
+ *
+ *	FIXME: exactly what are we trying to return here
+ */
+ 
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->ide_dma_off_quietly(drive);
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) != 0 && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto ata_pio;
+		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto ata_pio;
+		}
+	} else {
+ata_pio:
+		hwif->tuneproc(drive, 255);
+no_dma_set:
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	ali15x3_dma_write	-	do a DMA IDE write
+ *	@drive:	drive to issue write for
+ *
+ *	Returns 1 if the DMA write cannot be performed, zero on 
+ *	success.
+ */
+ 
+static int ali15x3_dma_write (ide_drive_t *drive)
+{
+	if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+		return 1;	/* try PIO instead of DMA */
+	return __ide_dma_write(drive);
+}
+
+/**
+ *	init_chipset_ali15x3	-	Initialise an ALi IDE controller
+ *	@dev: PCI device
+ *	@name: Name of the controller
+ *
+ *	This function initializes the ALI IDE controller and where 
+ *	appropriate also sets up the 1533 southbridge.
+ */
+  
+static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	unsigned long flags;
+	u8 tmpbyte;
+	struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!ali_proc) {
+		ali_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&ali_procs[0]);
+	}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+	local_irq_save(flags);
+
+	if (m5229_revision < 0xC2) {
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	/*
+	 * 1543C-B?, 1535, 1535D, 1553
+	 * Note 1: not all "motherboard" support this detection
+	 * Note 2: if no udma 66 device, the detection may "error".
+	 *         but in this case, we will not set the device to
+	 *         ultra 66, the detection result is not important
+	 */
+
+	/*
+	 * enable "Cable Detection", m5229, 0x4b, bit3
+	 */
+	pci_read_config_byte(dev, 0x4b, &tmpbyte);
+	pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+	/*
+	 * We should only tune the 1533 enable if we are using an ALi
+	 * North bridge. We might have no north found on some zany
+	 * box without a device at 0:0.0. The ALi bridge will be at
+	 * 0:0.0 so if we didn't find one we know what is cooking.
+	 */
+	if (north && north->vendor != PCI_VENDOR_ID_AL) {
+		local_irq_restore(flags);
+	        return 0;
+	}
+
+	if (m5229_revision < 0xC5 && isa_dev)
+	{	
+		/*
+		 * set south-bridge's enable bit, m1533, 0x79
+		 */
+
+		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+		if (m5229_revision == 0xC2) {
+			/*
+			 * 1543C-B0 (m1533, 0x79, bit 2)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+		} else if (m5229_revision >= 0xC3) {
+			/*
+			 * 1553/1535 (m1533, 0x79, bit 1)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+		}
+	}
+	local_irq_restore(flags);
+	return 0;
+}
+
+/**
+ *	ata66_ali15x3	-	check for UDMA 66 support
+ *	@hwif: IDE interface
+ *
+ *	This checks if the controller and the cable are capable
+ *	of UDMA66 transfers. It doesn't check the drives.
+ */
+
+static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int ata66	= 0;
+	u8 cable_80_pin[2]	= { 0, 0 };
+
+	unsigned long flags;
+	u8 tmpbyte;
+
+	/* Revision C5 and higher we must rely on drive side */
+	if (m5229_revision >= 0xC5)
+		return 1;
+		
+	local_irq_save(flags);
+	
+	if (m5229_revision >= 0xC2) {
+		/*
+		 * Ultra66 cable detection (from Host View)
+		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+		 */
+		pci_read_config_byte(dev, 0x4a, &tmpbyte);
+		/*
+		 * 0x4a, bit0 is 0 => primary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
+		/*
+		 * 0x4a, bit1 is 0 => secondary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
+		/*
+		 * Allow ata66 if cable of current channel has 80 pins
+		 */
+		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+	} else {
+		/*
+		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+		 */
+		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+	}
+
+	/*
+	 * CD_ROM DMA on (m5229, 0x53, bit0)
+	 *      Enable this bit even if we want to use PIO
+	 * PIO FIFO off (m5229, 0x53, bit1)
+	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
+	 *	(Not on later devices it seems)
+	 *
+	 *	0x53 changes meaning on later revs - we must no touch
+	 *	bit 1 on them. Need to check if 0x20 is the right break
+	 */
+	 
+	pci_read_config_byte(dev, 0x53, &tmpbyte);
+	
+	if(m5229_revision <= 0x20)
+		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+	else
+		tmpbyte |= 0x01;
+
+	pci_write_config_byte(dev, 0x53, tmpbyte);
+
+	local_irq_restore(flags);
+
+	return(ata66);
+}
+
+/**
+ *	init_hwif_common_ali15x3	-	Set up ALI IDE hardware
+ *	@hwif: IDE interface
+ *
+ *	Initialize the IDE structure side of the ALi 15x3 driver.
+ */
+ 
+static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &ali15x3_tune_drive;
+	hwif->speedproc = &ali15x3_tune_chipset;
+
+	/* Don't use LBA48 on ALi devices before rev 0xC5 */
+	hwif->addressing = (m5229_revision <= 0xC4) ? 1 : 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+
+	if (m5229_revision > 0x20)
+		hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+        if (m5229_revision >= 0x20) {
+                /*
+                 * M1543C or newer for DMAing
+                 */
+                hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+                hwif->ide_dma_write = &ali15x3_dma_write;
+		if (!noautodma)
+			hwif->autodma = 1;
+		if (!(hwif->udma_four))
+			hwif->udma_four = ata66_ali15x3(hwif);
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_hwif_ali15x3	-	Initialize the ALI IDE x86 stuff
+ *	@hwif: interface to configure
+ *
+ *	Obtain the IRQ tables for an ALi based IDE solution on the PC
+ *	class platforms. This part of the code isn't applicable to the
+ *	Sparc systems
+ */
+
+static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+	u8 ideic, inmir;
+	s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+				      1, 11, 0, 12, 0, 14, 0, 15 };
+	int irq = -1;
+	
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (isa_dev) {
+		/*
+		 * read IDE interface control
+		 */
+		pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+		/* bit0, bit1 */
+		ideic = ideic & 0x03;
+
+		/* get IRQ for IDE Controller */
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
+			/*
+			 * get SIRQ1 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x44, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		} else if (hwif->channel && !(ideic & 0x01)) {
+			/*
+			 * get SIRQ2 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x75, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		}
+		if(irq >= 0)
+			hwif->irq = irq;
+	}
+
+	init_hwif_common_ali15x3(hwif);
+}
+
+/**
+ *	init_dma_ali15x3	-	set up DMA on ALi15x3
+ *	@hwif: IDE interface
+ *	@dmabase: DMA interface base PCI address
+ *
+ *	Set up the DMA functionality on the ALi 15x3. For the ALi
+ *	controllers this is generic so we can let the generic code do
+ *	the actual work.
+ */
+
+static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (m5229_revision < 0x20)
+		return;
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+/**
+ *	alim15x3_init_one	-	set up an ALi15x3 IDE controller
+ *	@dev: PCI device to set up
+ *
+ *	Perform the actual set up for an ALi15x3 that has been found by the
+ *	hot plug layer.
+ */
+ 
+static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data];
+	
+	if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, NULL))
+		printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+
+#if defined(CONFIG_SPARC64)
+	d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+static struct pci_device_id alim15x3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "ALI15x3 IDE",
+	.id_table	= alim15x3_pci_tbl,
+	.probe		= alim15x3_init_one,
+};
+
+static int ali15x3_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ali15x3_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ali15x3_ide_init);
+module_exit(ali15x3_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.h linux-2.4.21-rc3/drivers/ide/pci/alim15x3.h
--- linux-2.4.20/drivers/ide/pci/alim15x3.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/alim15x3.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,55 @@
+#ifndef ALI15X3_H
+#define ALI15X3_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc;
+
+static int ali_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t ali_procs[] __initdata = {
+	{
+		.name		= "ali",
+		.set		= 1,
+		.get_info	= ali_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_ALI_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_ali15x3(struct pci_dev *, const char *);
+static void init_hwif_common_ali15x3(ide_hwif_t *);
+static void init_hwif_ali15x3(ide_hwif_t *);
+static void init_dma_ali15x3(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ali15x3_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_AL,
+		.device		= PCI_DEVICE_ID_AL_M5229,
+		.name		= "ALI15X3",
+		.init_chipset	= init_chipset_ali15x3,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ali15x3,
+		.init_dma	= init_dma_ali15x3,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ALI15X3 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.c linux-2.4.21-rc3/drivers/ide/pci/amd74xx.c
--- linux-2.4.20/drivers/ide/pci/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/amd74xx.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,483 @@
+/*
+ * Version 2.10
+ *
+ * AMD 755/756/766/8111 and nVidia nForce IDE driver for Linux.
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *      Andre Hedrick
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "amd74xx.h"
+
+#define AMD_IDE_ENABLE		(0x00 + amd_config->base)
+#define AMD_IDE_CONFIG		(0x01 + amd_config->base)
+#define AMD_CABLE_DETECT	(0x02 + amd_config->base)
+#define AMD_DRIVE_TIMING	(0x08 + amd_config->base)
+#define AMD_8BIT_TIMING		(0x0e + amd_config->base)
+#define AMD_ADDRESS_SETUP	(0x0c + amd_config->base)
+#define AMD_UDMA_TIMING		(0x10 + amd_config->base)
+
+#define AMD_UDMA		0x07
+#define AMD_UDMA_33		0x01
+#define AMD_UDMA_66		0x02
+#define AMD_UDMA_100		0x03
+#define AMD_CHECK_SWDMA		0x08
+#define AMD_BAD_SWDMA		0x10
+#define AMD_BAD_FIFO		0x20
+
+/*
+ * AMD SouthBridge chips.
+ */
+
+static struct amd_ide_chip {
+	unsigned short id;
+	unsigned char rev;
+	unsigned long base;
+	unsigned char flags;
+} amd_ide_chips[] = {
+	{ PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },	/* AMD-755 Cobra */
+	{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },	/* AMD-756 Viper */
+	{ PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO },	/* AMD-766 Viper */
+	{ PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 },			/* AMD-768 Opus */
+	{ PCI_DEVICE_ID_AMD_8111_IDE,  0x00, 0x40, AMD_UDMA_100 },			/* AMD-8111 */
+        { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 },                  /* nVidia nForce */
+        { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x00, 0x50, AMD_UDMA_100 },                  /* nVidia nForce */
+
+	{ 0 }
+};
+
+static struct amd_ide_chip *amd_config;
+static unsigned char amd_enabled;
+static unsigned int amd_80w;
+static unsigned int amd_clock;
+
+static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3 };
+static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 1 };
+static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
+
+/*
+ * AMD /proc entry.
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static unsigned long amd_base;
+static struct pci_dev *bmide_dev;
+extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define amd_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	unsigned short c, w;
+	unsigned char t;
+	char *p = buffer;
+	int len;
+
+	amd_print("----------AMD BusMastering IDE Configuration----------------");
+
+	amd_print("Driver Version:                     2.10");
+	amd_print("South Bridge:                       %s", bmide_dev->name);
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+	amd_print("Revision:                           IDE %#x", t);
+	amd_print("Highest DMA rate:                   %s", amd_dma[amd_config->flags & AMD_UDMA]);
+
+	amd_print("BM-DMA base:                        %#lx", amd_base);
+	amd_print("PCI clock:                          %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10);
+	
+	amd_print("-----------------------Primary IDE-------Secondary IDE------");
+
+	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+	amd_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	amd_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, AMD_IDE_ENABLE, &t);
+	amd_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8);
+	amd_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	amd_print("Cable Type:            %10s%20s", (amd_80w & 1) ? "80w" : "40w", (amd_80w & 2) ? "80w" : "40w");
+
+	if (!amd_clock)
+                return p - buffer;
+
+	amd_print("-------------------drive0----drive1----drive2----drive3-----");
+
+	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, AMD_8BIT_TIMING, &w);
+	pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+
+	for (i = 0; i < 4; i++) {
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+
+		udma[i] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)];
+		uen[i]  = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0;
+		den[i]  = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		if (den[i] && uen[i] && udma[i] == 1) {
+			speed[i] = amd_clock * 3;
+			cycle[i] = 666666 / amd_clock;
+			continue;
+		}
+
+		speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2);
+		cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2;
+	}
+
+	amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock);
+	amd_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / amd_clock);
+	amd_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / amd_clock);
+	amd_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / amd_clock);
+	amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock);
+	amd_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
+	amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
+
+	/* hoping p - buffer is less than 4K... */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+
+#endif
+
+/*
+ * amd_set_speed() writes timing values to the chipset registers
+ */
+
+static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
+{
+	unsigned char t;
+
+	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+	pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
+
+	pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (amd_config->flags & AMD_UDMA) {
+		case AMD_UDMA_33:  t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case AMD_UDMA_66:  t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
+		case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
+}
+
+/*
+ * amd_set_drive() computes timing values configures the drive and
+ * the chipset to a desired transfer mode. It also can be called
+ * by upper layers.
+ */
+
+static int amd_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / amd_clock;
+	UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
+
+	amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)	
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/*
+ * amd74xx_tune_drive() is a callback from upper layers for
+ * PIO-only tuning.
+ */
+
+static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
+}
+
+/*
+ * amd74xx_dmaproc() is a callback from upper layers that can do
+ * a lot, but we use it for DMA/PIO tuning only, delegating everything
+ * else to the default ide_dmaproc().
+ */
+
+static int amd74xx_ide_dma_check(ide_drive_t *drive)
+{
+	int w80 = HWIF(drive)->udma_four;
+
+	u8 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
+		((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
+		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0));
+
+	amd_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/*
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name)
+{
+	unsigned char t;
+	unsigned int u;
+	int i;
+
+/*
+ * Check for bad SWDMA.
+ */
+
+	if (amd_config->flags & AMD_CHECK_SWDMA) {
+		pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+		if (t <= 7)
+			amd_config->flags |= AMD_BAD_SWDMA;
+	}
+
+/*
+ * Check 80-wire cable presence.
+ */
+
+	switch (amd_config->flags & AMD_UDMA) {
+
+		case AMD_UDMA_100:
+			pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
+			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+			amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
+					printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n");
+					amd_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case AMD_UDMA_66:
+			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if ((u >> i) & 4)
+					amd_80w |= (1 << (1 - (i >> 4)));
+			break;
+	}
+
+	pci_read_config_dword(dev, AMD_IDE_ENABLE, &u);
+	amd_enabled = ((u & 1) ? 2 : 0) | ((u & 2) ? 1 : 0);
+
+/*
+ * Take care of prefetch & postwrite.
+ */
+
+	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+	pci_write_config_byte(dev, AMD_IDE_CONFIG,
+		(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
+
+/*
+ * Determine the system bus clock.
+ */
+
+	amd_clock = system_bus_clock() * 1000;
+
+	switch (amd_clock) {
+		case 33000: amd_clock = 33333; break;
+		case 37000: amd_clock = 37500; break;
+		case 41000: amd_clock = 41666; break;
+	}
+
+	if (amd_clock < 20000 || amd_clock > 50000) {
+		printk(KERN_WARNING "AMD_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", amd_clock);
+		printk(KERN_WARNING "AMD_IDE: Use ide0=ata66 if you want to assume 80-wire cable\n");
+		amd_clock = 33333;
+	}
+
+/*
+ * Print the boot message.
+ */
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n",
+		dev->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name);
+
+/*
+ * Register /proc/ide/amd74xx entry
+ */
+
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+        if (!amd74xx_proc) {
+                amd_base = pci_resource_start(dev, 4);
+                bmide_dev = dev;
+                ide_pci_register_host_proc(&amd74xx_procs[0]);
+                amd74xx_proc = 1;
+        }
+#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
+
+
+	return 0;
+}
+
+static unsigned int __init ata66_amd74xx(ide_hwif_t *hwif)
+{
+	return ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+}
+
+static void __init init_hwif_amd74xx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &amd74xx_tune_drive;
+	hwif->speedproc = &amd_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+        hwif->atapi_dma = 1;
+        hwif->ultra_mask = 0x7f;
+        hwif->mwdma_mask = 0x07;
+        hwif->swdma_mask = 0x07;
+
+        if (!(hwif->udma_four))
+                hwif->udma_four = ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+        hwif->ide_dma_check = &amd74xx_ide_dma_check;
+        if (!noautodma)
+                hwif->autodma = 1;
+        hwif->drives[0].autodma = hwif->autodma;
+        hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver only work on enabled interfaces.
+ */
+
+static void __init init_dma_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((amd_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = amd74xx_chipsets + id->driver_data;
+	amd_config = amd_ide_chips + id->driver_data;
+	if (dev->device != d->device) BUG();
+	if (dev->device != amd_config->id) BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id amd74xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, 	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AMD IDE",
+	.id_table	= amd74xx_pci_tbl,
+	.probe		= amd74xx_probe,
+};
+
+static int amd74xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void amd74xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(amd74xx_ide_init);
+module_exit(amd74xx_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_DESCRIPTION("AMD PCI IDE driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.h linux-2.4.21-rc3/drivers/ide/pci/amd74xx.h
--- linux-2.4.20/drivers/ide/pci/amd74xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/amd74xx.h	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,135 @@
+#ifndef AMD74XX_H
+#define AMD74XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AMD_TIMINGS
+
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc;
+
+static int amd74xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t amd74xx_procs[] __initdata = {
+	{
+		.name		= "amd74xx",
+		.set		= 1,
+		.get_info	= amd74xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *);
+static void init_hwif_amd74xx(ide_hwif_t *);
+static void init_dma_amd74xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_COBRA_7401,
+		.name		= "AMD7401",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_VIPER_7409,
+		.name		= "AMD7409",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_VIPER_7411,
+		.name		= "AMD7411",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_OPUS_7441,
+		.name		= "AMD7441",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_8111_IDE,
+		.name		= "AMD8111",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.autodma	= AUTODMA,
+		.channels	= 2,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},
+	{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_NVIDIA,
+		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		.name		= "NFORCE",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},
+	{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_NVIDIA,
+		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,
+		.name		= "NFORCE2",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},
+	{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* AMD74XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.c linux-2.4.21-rc3/drivers/ide/pci/cmd640.c
--- linux-2.4.20/drivers/ide/pci/cmd640.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cmd640.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,879 @@
+/*
+ *  linux/drivers/ide/pci/cmd640.c		Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
+ *  			mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for the advanced features and bugs
+ *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ *  These chips are basically fucked by design, and getting this driver
+ *  to work on every motherboard design that uses this screwed chip seems
+ *  bloody well impossible.  However, we're still trying.
+ *
+ *  Version 0.97 worked for everybody.
+ *
+ *  User feedback is essential.  Many thanks to the beta test team:
+ *
+ *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ *  liug@mama.indstate.edu, and others.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	Fixes for vlb initialization code, enable prefetch
+ *			for versions 'B' and 'C' of chip by default,
+ *			some code cleanup.
+ *
+ *  Version 0.03	Added reset of secondary interface,
+ *			and black list for devices which are not compatible
+ *			with prefetch mode. Separate function for setting
+ *			prefetch is added, possibly it will be called some
+ *			day from ioctl processing code.
+ *
+ *  Version 0.04	Now configs/compiles separate from ide.c
+ *
+ *  Version 0.05	Major rewrite of interface timing code.
+ *			Added new function cmd640_set_mode to set PIO mode
+ *			from ioctl call. New drives added to black list.
+ *
+ *  Version 0.06	More code cleanup. Prefetch is enabled only for
+ *			detected hard drives, not included in prefetch
+ *			black list.
+ *
+ *  Version 0.07	Changed to more conservative drive tuning policy.
+ *			Unknown drives, which report PIO < 4 are set to
+ *			(reported_PIO - 1) if it is supported, or to PIO0.
+ *			List of known drives extended by info provided by
+ *			CMD at their ftp site.
+ *
+ *  Version 0.08	Added autotune/noautotune support.
+ *
+ *  Version 0.09	Try to be smarter about 2nd port enabling.
+ *  Version 0.10	Be nice and don't reset 2nd port.
+ *  Version 0.11	Try to handle more weird situations.
+ *
+ *  Version 0.12	Lots of bug fixes from Laszlo Peter
+ *			irq unmasking disabled for reliability.
+ *			try to be even smarter about the second port.
+ *			tidy up source code formatting.
+ *  Version 0.13	permit irq unmasking again.
+ *  Version 0.90	massive code cleanup, some bugs fixed.
+ *			defaults all drives to PIO mode0, prefetch off.
+ *			autotune is OFF by default, with compile time flag.
+ *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ *			 (requires hdparm-3.1 or newer)
+ *  Version 0.91	first release to linux-kernel list.
+ *  Version 0.92	move initial reg dump to separate callable function
+ *			change "readahead" to "prefetch" to avoid confusion
+ *  Version 0.95	respect original BIOS timings unless autotuning.
+ *			tons of code cleanup and rearrangement.
+ *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ *			prevent use of unmask when prefetch is on
+ *  Version 0.96	prevent use of io_32bit when prefetch is off
+ *  Version 0.97	fix VLB secondary interface for sjd@slip.net
+ *			other minor tune-ups:  0.96 was very good.
+ *  Version 0.98	ignore PCI version when disabled by BIOS
+ *  Version 0.99	display setup/active/recovery clocks with PIO mode
+ *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
+ *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
+ *			 ("fast" is necessary for 32bit I/O in some systems)
+ *  Version 1.02	fix bug that resulted in slow "setup times"
+ *			 (patch courtesy of Zoltan Hidvegi)
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+#define CMD640_PREFETCH_MASKS 1
+
+#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/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+/*
+ * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
+ */
+int cmd640_vlb = 0;
+
+/*
+ * CMD640 specific registers definition.
+ */
+
+#define VID		0x00
+#define DID		0x02
+#define PCMD		0x04
+#define   PCMD_ENA	0x01
+#define PSTTS		0x06
+#define REVID		0x08
+#define PROGIF		0x09
+#define SUBCL		0x0a
+#define BASCL		0x0b
+#define BaseA0		0x10
+#define BaseA1		0x14
+#define BaseA2		0x18
+#define BaseA3		0x1c
+#define INTLINE		0x3c
+#define INPINE		0x3d
+
+#define	CFR		0x50
+#define   CFR_DEVREV		0x03
+#define   CFR_IDE01INTR		0x04
+#define	  CFR_DEVID		0x18
+#define	  CFR_AT_VESA_078h	0x20
+#define	  CFR_DSA1		0x40
+#define	  CFR_DSA0		0x80
+
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define DRWTIM23	0x58
+#define BRST		0x59
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*__put_cmd640_reg)(u16 reg, u8 val);
+static u8 (*__get_cmd640_reg)(u16 reg);
+
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
+
+/*
+ * The CMD640x chip does not support DWORD config write cycles, but some
+ * of the BIOSes use them to implement the config services.
+ * Therefore, we must use direct IO instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1 (u16 reg, u8 val)
+{
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
+}
+
+static u8 get_cmd640_reg_pci1 (u16 reg)
+{
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	return inb_p((reg & 3) | 0xcfc);
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2 (u16 reg, u8 val)
+{
+	outb_p(0x10, 0xcf8);
+	outb_p(val, cmd640_key + reg);
+	outb_p(0, 0xcf8);
+}
+
+static u8 get_cmd640_reg_pci2 (u16 reg)
+{
+	u8 b;
+
+	outb_p(0x10, 0xcf8);
+	b = inb_p(cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb (u16 reg, u8 val)
+{
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
+}
+
+static u8 get_cmd640_reg_vlb (u16 reg)
+{
+	outb_p(reg, cmd640_key);
+	return inb_p(cmd640_key + 4);
+}
+
+static u8 get_cmd640_reg(u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	b = __get_cmd640_reg(reg);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+static void put_cmd640_reg(u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	__put_cmd640_reg(reg,val);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int __init match_pci_cmd640_device (void)
+{
+	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	unsigned int i;
+	for (i = 0; i < 4; i++) {
+		if (get_cmd640_reg(i) != ven_dev[i])
+			return 0;
+	}
+#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
+	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
+		printk("ide: cmd640 on PCI disabled by BIOS\n");
+		return 0;
+	}
+#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
+	return 1; /* success */
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+static int __init probe_for_cmd640_pci1 (void)
+{
+	__get_cmd640_reg = get_cmd640_reg_pci1;
+	__put_cmd640_reg = put_cmd640_reg_pci1;
+	for (cmd640_key = 0x80000000;
+	     cmd640_key <= 0x8000f800;
+	     cmd640_key += 0x800) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+static int __init probe_for_cmd640_pci2 (void)
+{
+	__get_cmd640_reg = get_cmd640_reg_pci2;
+	__put_cmd640_reg = put_cmd640_reg_pci2;
+	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+static int __init probe_for_cmd640_vlb (void)
+{
+	u8 b;
+
+	__get_cmd640_reg = get_cmd640_reg_vlb;
+	__put_cmd640_reg = put_cmd640_reg_vlb;
+	cmd640_key = 0x178;
+	b = get_cmd640_reg(CFR);
+	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+		cmd640_key = 0x78;
+		b = get_cmd640_reg(CFR);
+		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
+			return 0;
+	}
+	return 1; /* success */
+}
+
+/*
+ *  Returns 1 if an IDE interface/drive exists at 0x170,
+ *  Returns 0 otherwise.
+ */
+static int __init secondary_port_responding (void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
+	udelay(100);
+	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+		udelay(100);
+		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 0; /* nothing responded */
+		}
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 1; /* success */
+}
+
+#ifdef CMD640_DUMP_REGS
+/*
+ * Dump out all cmd640 registers.  May be called from ide.c
+ */
+static void cmd640_dump_regs (void)
+{
+	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
+
+	/* Dump current state of chip registers */
+	printk("ide: cmd640 internal register dump:");
+	for (; reg <= 0x59; reg++) {
+		if (!(reg & 0x0f))
+			printk("\n%04x:", reg);
+		printk(" %02x", get_cmd640_reg(reg));
+	}
+	printk("\n");
+}
+#endif
+
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch (unsigned int index)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+	if (b & prefetch_masks[index]) {	/* is prefetch off? */
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+	} else {
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+	}
+}
+
+/*
+ * Figure out which devices we control
+ */
+static void __init setup_device_ptrs (void)
+{
+	unsigned int i;
+
+	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		ide_hwif_t *hwif = &ide_hwifs[i];
+		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
+			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
+				cmd_hwif0 = hwif;
+			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+				cmd_hwif1 = hwif;
+		}
+	}
+	cmd_drives[0] = &cmd_hwif0->drives[0];
+	cmd_drives[1] = &cmd_hwif0->drives[1];
+	cmd_drives[2] = &cmd_hwif1->drives[0];
+	cmd_drives[3] = &cmd_hwif1->drives[1];
+}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode (unsigned int index, int mode)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	int reg = prefetch_regs[index];
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	b = __get_cmd640_reg(reg);
+	if (mode) {	/* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+		b &= ~prefetch_masks[index];	/* enable prefetch */
+	} else {
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+		b |= prefetch_masks[index];	/* disable prefetch */
+	}
+	__put_cmd640_reg(reg, b);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Dump out current drive clocks settings
+ */
+static void display_clocks (unsigned int index)
+{
+	u8 active_count, recovery_count;
+
+	active_count = active_counts[index];
+	if (active_count == 1)
+		++active_count;
+	recovery_count = recovery_counts[index];
+	if (active_count > 3 && recovery_count == 1)
+		++recovery_count;
+	if (cmd640_chip_version > 1)
+		recovery_count += 1;  /* cmd640b uses (count + 1)*/
+	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
+inline static u8 pack_nibbles (u8 upper, u8 lower)
+{
+	return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine retrieves the initial drive timings from the chipset.
+ */
+static void __init retrieve_drive_counts (unsigned int index)
+{
+	u8 b;
+
+	/*
+	 * Get the internal setup timing, and convert to clock count
+	 */
+	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+	switch (b) {
+		case 0x00: b = 4; break;
+		case 0x80: b = 3; break;
+		case 0x40: b = 2; break;
+		default:   b = 5; break;
+	}
+	setup_counts[index] = b;
+
+	/*
+	 * Get the active/recovery counts
+	 */
+	b = get_cmd640_reg(drwtim_regs[index]);
+	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
+	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
+}
+
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
+ */
+static void program_drive_counts (unsigned int index)
+{
+	unsigned long flags;
+	u8 setup_count    = setup_counts[index];
+	u8 active_count   = active_counts[index];
+	u8 recovery_count = recovery_counts[index];
+
+	/*
+	 * Set up address setup count and drive read/write timing registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * so we merge the timings, using the slowest value for each timing.
+	 */
+	if (index > 1) {
+		unsigned int mate;
+		if (cmd_drives[mate = index ^ 1]->present) {
+			if (setup_count < setup_counts[mate])
+				setup_count = setup_counts[mate];
+			if (active_count < active_counts[mate])
+				active_count = active_counts[mate];
+			if (recovery_count < recovery_counts[mate])
+				recovery_count = recovery_counts[mate];
+		}
+	}
+
+	/*
+	 * Convert setup_count to internal chipset representation
+	 */
+	switch (setup_count) {
+		case 4:	 setup_count = 0x00; break;
+		case 3:	 setup_count = 0x80; break;
+		case 1:
+		case 2:	 setup_count = 0x40; break;
+		default: setup_count = 0xc0; /* case 5 */
+	}
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 * (this converts counts of 16 into counts of zero -- okay).
+	 */
+	setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
+	__put_cmd640_reg(arttim_regs[index], setup_count);
+	__put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+{
+	int setup_time, active_time, recovery_time, clock_time;
+	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = system_bus_clock();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+	if (active_count < 2)
+		active_count = 2; /* minimum allowed by cmd640 */
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count < 2)
+		recovery_count = 2; /* minimum allowed by cmd640 */
+	if (recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd640 */
+	if (cmd640_chip_version > 1)
+		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
+	if (recovery_count > 16)
+		recovery_count = 16; /* maximum allowed by cmd640 */
+
+	setup_counts[index]    = setup_count;
+	active_counts[index]   = active_count;
+	recovery_counts[index] = recovery_count;
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (index);
+}
+
+/*
+ * Drive PIO mode selection:
+ */
+static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+{
+	u8 b;
+	ide_pio_data_t  d;
+	unsigned int index = 0;
+
+	while (drive != cmd_drives[index]) {
+		if (++index > 3) {
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
+		}
+	}
+	switch (mode_wanted) {
+		case 6: /* set fast-devsel off */
+		case 7: /* set fast-devsel on */
+			mode_wanted &= 1;
+			b = get_cmd640_reg(CNTRL) & ~0x27;
+			if (mode_wanted)
+				b |= 0x27;
+			put_cmd640_reg(CNTRL, b);
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			set_prefetch_mode(index, mode_wanted);
+			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+
+	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "");
+	display_clocks(index);
+	return;
+}
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static int pci_conf1(void)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x01, 0xCFB);
+	tmp = inl(0xCF8);
+	outl(0x80000000, 0xCF8);
+	if (inl(0xCF8) == 0x80000000) {
+		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	outl(tmp, 0xCF8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+static int pci_conf2(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x00, 0xCFB);
+	outb(0x00, 0xCF8);
+	outb(0x00, 0xCFA);
+	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ */
+int __init ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	int second_port_cmd640 = 0;
+	const char *bus_type, *port2;
+	unsigned int index;
+	u8 b, cfr;
+
+	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+		bus_type = "VLB";
+	} else {
+		cmd640_vlb = 0;
+		/* Find out what kind of PCI probing is supported otherwise
+		   Justin Gibbs will sulk.. */
+		if (pci_conf1() && probe_for_cmd640_pci1())
+			bus_type = "PCI (type1)";
+		else if (pci_conf2() && probe_for_cmd640_pci2())
+			bus_type = "PCI (type2)";
+		else
+			return 0;
+	}
+	/*
+	 * Undocumented magic (there is no 0x5b reg in specs)
+	 */
+	put_cmd640_reg(0x5b, 0xbd);
+	if (get_cmd640_reg(0x5b) != 0xbd) {
+		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		return 0;
+	}
+	put_cmd640_reg(0x5b, 0);
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+
+	/*
+	 * Documented magic begins here
+	 */
+	cfr = get_cmd640_reg(CFR);
+	cmd640_chip_version = cfr & CFR_DEVREV;
+	if (cmd640_chip_version == 0) {
+		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+		return 0;
+	}
+
+	/*
+	 * Initialize data for primary port
+	 */
+	setup_device_ptrs ();
+	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+	cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+	/*
+	 * Ensure compatibility by always using the slowest timings
+	 * for access to the drive's command register block,
+	 * and reset the prefetch burstsize to default (512 bytes).
+	 *
+	 * Maybe we need a way to NOT do these on *some* systems?
+	 */
+	put_cmd640_reg(CMDTIM, 0);
+	put_cmd640_reg(BRST, 0x40);
+
+	/*
+	 * Try to enable the secondary interface, if not already enabled
+	 */
+	if (cmd_hwif1->noprobe) {
+		port2 = "not probed";
+	} else {
+		b = get_cmd640_reg(CNTRL);
+		if (secondary_port_responding()) {
+			if ((b & CNTRL_ENA_2ND)) {
+				second_port_cmd640 = 1;
+				port2 = "okay";
+			} else if (cmd640_vlb) {
+				second_port_cmd640 = 1;
+				port2 = "alive";
+			} else
+				port2 = "not cmd640";
+		} else {
+			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+			if (secondary_port_responding()) {
+				second_port_cmd640 = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+				second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+				port2 = "enabled";
+			} else {
+				put_cmd640_reg(CNTRL, b); /* restore original setting */
+				port2 = "not responding";
+			}
+		}
+	}
+
+	/*
+	 * Initialize data for secondary cmd640 port, if enabled
+	 */
+	if (second_port_cmd640) {
+		cmd_hwif0->serialized = 1;
+		cmd_hwif1->serialized = 1;
+		cmd_hwif1->chipset = ide_cmd640;
+		cmd_hwif0->mate = cmd_hwif1;
+		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+		cmd_hwif0->serialized ? "" : "not ", port2);
+
+	/*
+	 * Establish initial timings/prefetch for all drives.
+	 * Do not unnecessarily disturb any prior BIOS setup of these.
+	 */
+	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+		ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		if (drive->autotune || ((index > 1) && second_port_toggled)) {
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
+			 * This way, the drive identify code has a better chance.
+			 */
+			setup_counts    [index] = 4;	/* max possible */
+			active_counts   [index] = 16;	/* max possible */
+			recovery_counts [index] = 16;	/* max possible */
+			program_drive_counts (index);
+			set_prefetch_mode (index, 0);
+			printk("cmd640: drive%d timings/prefetch cleared\n", index);
+		} else {
+			/*
+			 * Record timings/prefetch without changing them.
+			 * This preserves any prior BIOS setup.
+			 */
+			retrieve_drive_counts (index);
+			check_prefetch (index);
+			printk("cmd640: drive%d timings/prefetch(%s) preserved",
+				index, drive->no_io_32bit ? "off" : "on");
+			display_clocks(index);
+		}
+#else
+		/*
+		 * Set the drive unmask flags to match the prefetch setting
+		 */
+		check_prefetch (index);
+		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+	return 1;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.h linux-2.4.21-rc3/drivers/ide/pci/cmd640.h
--- linux-2.4.20/drivers/ide/pci/cmd640.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cmd640.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef CMD640_H
+#define CMD640_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define IDE_IGNORE      ((void *)-1)
+
+static ide_pci_device_t cmd640_chipsets[] __initdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_640,
+		.name		= "CMD640",
+		.init_setup	= NULL,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= IDE_IGNORE,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.bootable	= EOL,
+	}
+}
+
+#endif /* CMD640_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.c linux-2.4.21-rc3/drivers/ide/pci/cmd64x.c
--- linux-2.4.20/drivers/ide/pci/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cmd64x.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,798 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.30	Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ *           Note, this driver is not used at all on other systems because
+ *           there the "BIOS" has done all of the following already.
+ *           Due to massive hardware bugs, UltraDMA is only supported
+ *           on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998		David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cmd64x.h"
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS		5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+#undef DEBUG_CMD_REGS
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
+	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
+	u8 reg72 = 0, reg73 = 0;			/* primary */
+	u8 reg7a = 0, reg7b = 0;			/* secondary */
+	u8 reg50 = 0, reg71 = 0;			/* extra */
+#ifdef DEBUG_CMD_REGS
+	u8 hi_byte = 0, lo_byte = 0;
+#endif /* DEBUG_CMD_REGS */
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	(void) pci_read_config_byte(dev, CFR,       &reg50);
+	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
+	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
+	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
+	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
+	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
+	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
+	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled           "
+			"              %sabled\n",
+		(reg72&0x80)?"dis":" en",
+		(reg7a&0x80)?"dis":" en");
+	p += sprintf(p, "--------------- drive0 "
+		"--------- drive1 -------- drive0 "
+		"---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s"
+			"             %s               %s\n",
+		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+		(reg72&0x20)?(
+			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+		(reg72&0x40)?(
+			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+			"X"):"?");
+	p += sprintf(p, "         %s(%s)           %s(%s)\n",
+		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x20)?(
+			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x40)?(
+			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+			"X"):"?" );
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	p += sprintf(p, "                %s                     %s\n",
+		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
+		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+#ifdef DEBUG_CMD_REGS
+	SPLIT_BYTE(reg50, hi_byte, lo_byte);
+	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
+	SPLIT_BYTE(reg57, hi_byte, lo_byte);
+	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+	SPLIT_BYTE(reg71, hi_byte, lo_byte);
+	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
+#endif /* DEBUG_CMD_REGS */
+
+	return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_cmd_devs; i++) {
+		struct pci_dev *dev	= cmd_devs[i];
+		p = print_cmd64x_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+	unsigned long flags;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	ide_drive_t *drives = HWIF(drive)->drives;
+	u8 temp_b;
+	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 recovery_counts[] =
+		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+	static const u8 arttim_regs[2][2] = {
+			{ ARTTIM0, ARTTIM1 },
+			{ ARTTIM23, ARTTIM23 }
+		};
+	static const u8 drwtim_regs[2][2] = {
+			{ DRWTIM0, DRWTIM1 },
+			{ DRWTIM2, DRWTIM3 }
+		};
+	int channel = (int) HWIF(drive)->channel;
+	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
+
+	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
+		setup_count, active_count, recovery_count, drive->present);
+	/*
+	 * Set up address setup count registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * for address setup so we merge these timings, using the slowest
+	 * value.
+	 */
+	if (channel) {
+		drive->drive_data = setup_count;
+		setup_count = IDE_MAX(drives[0].drive_data,
+					drives[1].drive_data);
+		cmdprintk("Secondary interface, setup_count = %d\n",
+					setup_count);
+	}
+
+	/*
+	 * Convert values to internal chipset representation
+	 */
+	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+	active_count &= 0xf; /* Remember, max value is 16 */
+	recovery_count = (int) recovery_counts[recovery_count];
+
+	cmdprintk("Final values = %d,%d,%d\n",
+		setup_count, active_count, recovery_count);
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	local_irq_save(flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 */
+	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+		((u8) setup_count) | (temp_b & 0x3f));
+	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+		(u8) ((active_count << 4) | recovery_count));
+	cmdprintk ("Write %x to %x\n",
+		((u8) setup_count) | (temp_b & 0x3f),
+		arttim_regs[channel][slave]);
+	cmdprintk ("Write %x to %x\n",
+		(u8) ((active_count << 4) | recovery_count),
+		drwtim_regs[channel][slave]);
+	local_irq_restore(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is 
+ * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+
+static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+{
+	int setup_time, active_time, recovery_time;
+	int clock_time, pio_mode, cycle_time;
+	u8 recovery_count2, cycle_count;
+	int setup_count, active_count, recovery_count;
+	int bus_speed = system_bus_clock();
+	/*byte b;*/
+	ide_pio_data_t  d;
+
+	switch (mode_wanted) {
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			/*set_prefetch_mode(index, mode_wanted);*/
+			cmdprintk("%s: %sabled cmd640 prefetch\n",
+				drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	pio_mode = d.pio_mode;
+	cycle_time = d.cycle_time;
+
+	/*
+	 * I copied all this complicated stuff from cmd640.c and made a few
+	 * minor changes.  For now I am just going to pray that it is correct.
+	 */
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd646 */
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it
+	 *		(proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (drive, setup_count, active_count, recovery_count);
+
+	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+		"clocks=%d/%d/%d\n",
+		drive->name, pio_mode, mode_wanted, cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "",
+		setup_count, active_count, recovery_count);
+}
+
+static u8 cmd64x_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode = 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_649:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_CMD_648:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_CMD_643:
+			return 0;
+
+		case PCI_DEVICE_ID_CMD_646:
+		{
+			unsigned int class_rev	= 0;
+			pci_read_config_dword(dev,
+				PCI_CLASS_REVISION, &class_rev);
+			class_rev &= 0xff;
+		/*
+		 * UltraDMA only supported on PCI646U and PCI646U2, which
+		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+		 * Actually, although the CMD tech support people won't
+		 * tell me the details, the 0x03 revision cannot support
+		 * UDMA correctly without hardware modifications, and even
+		 * then it only works with Quantum disks due to some
+		 * hold time assumptions in the 646U part which are fixed
+		 * in the 646U2.
+		 *
+		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+		 */
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					return 1;
+				case 0x03:
+				case 0x01:
+				default:
+					return 0;
+			}
+		}
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	u8 speed	= 0x00;
+	u8 set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	cmd64x_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	config_cmd64x_chipset_for_pio(drive, set_speed);
+}
+
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 regU = 0, pciU	= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+	u8 regD = 0, pciD	= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+
+	u8 speed	= ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+		regD &= ~(unit ? 0x40 : 0x20);
+		regU &= ~(unit ? 0xCA : 0x35);
+		(void) pci_write_config_byte(dev, pciD, regD);
+		(void) pci_write_config_byte(dev, pciU, regU);
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+	}
+
+	switch(speed) {
+		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
+		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
+		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
+		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
+		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
+		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
+		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
+
+		default:
+			return 1;
+	}
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_write_config_byte(dev, pciU, regU);
+		regD |= (unit ? 0x40 : 0x20);
+		(void) pci_write_config_byte(dev, pciD, regD);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, cmd64x_ratemask(drive));
+
+	config_chipset_for_pio(drive, !speed);
+
+	if (!speed)
+		return 0;
+
+	if(ide_set_xfer_rate(drive, speed))
+		return 0; 
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id->capability & 1) != 0 && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+
+static int cmd64x_ide_dma_end (ide_drive_t *drive)
+{
+	u8 dma_stat = 0, dma_cmd = 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	drive->waiting_for_dma = 0;
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	if (cmd64x_alt_dma_status(dev)) {
+		u8 dma_intr	= 0;
+		u8 dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 :
+						    CFR_INTR_CH0;
+		u8 dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
+		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+		/* clear the INTR bit */
+		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+	}
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+	struct pci_dev *dev		= hwif->pci_dev;
+        u8 dma_alt_stat = 0, mask	= (hwif->channel) ? MRDMODE_INTR_CH1 :
+							    MRDMODE_INTR_CH0;
+	u8 dma_stat = hwif->INB(hwif->dma_status);
+
+	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+#ifdef DEBUG
+	printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+		"0x%02x mask: 0x%02x\n", drive->name,
+		dma_stat, dma_alt_stat, mask);
+#endif
+	if (!(dma_alt_stat & mask))
+		return 0;
+
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev = 0;
+	u8 mrdmode = 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+#ifdef __i386__
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+#endif
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+			break;
+		case PCI_DEVICE_ID_CMD_646:
+			printk(KERN_INFO "%s: chipset revision 0x%02X, ", name, class_rev);
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					printk("UltraDMA Capable");
+					break;
+				case 0x03:
+					printk("MultiWord DMA Force Limited");
+					break;
+				case 0x01:
+				default:
+					printk("MultiWord DMA Limited, IRQ workaround enabled");
+					break;
+				}
+			printk("\n");
+                        break;
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			break;
+		default:
+			break;
+	}
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+
+	/* Setup interrupts. */
+	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
+	mrdmode &= ~(0x30);
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
+
+	/* Use MEMORY READ LINE for reads.
+	 * NOTE: Although not mentioned in the PCI0646U specs,
+	 *       these bits are write only and won't be read
+	 *       back as set or not.  The PCI0646U2 specs clarify
+	 *       this point.
+	 */
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+
+	/* Set reasonable active/recovery/address-setup values. */
+	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
+	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
+#ifdef __i386__
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
+	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
+#ifdef CONFIG_PPC
+	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+
+	cmd_devs[n_cmd_devs++] = dev;
+
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		ide_pci_register_host_proc(&cmd64x_procs[0]);
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+		case PCI_DEVICE_ID_CMD_646:
+			return ata66;
+		default:
+			break;
+	}
+	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
+	return (ata66 & mask) ? 1 : 0;
+}
+
+static void __init init_hwif_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int class_rev;
+
+	hwif->autodma = 0;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->tuneproc  = &cmd64x_tuneproc;
+	hwif->speedproc = &cmd64x_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (dev->device == PCI_DEVICE_ID_CMD_643)
+		hwif->ultra_mask = 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_646)
+		hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_648)
+		hwif->ultra_mask = 0x1f;
+
+	hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_cmd64x(hwif);
+
+	if (dev->device == PCI_DEVICE_ID_CMD_646) {
+		hwif->chipset = ide_cmd646;
+		if (class_rev == 0x01) {
+			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
+		} else {
+			hwif->ide_dma_end = &cmd64x_ide_dma_end;
+			hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+		}
+	} else {
+		hwif->ide_dma_end = &cmd64x_ide_dma_end;
+		hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+	}
+
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cmd64x_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cmd64x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CMD64x IDE",
+	.id_table	= cmd64x_pci_tbl,
+	.probe		= cmd64x_init_one,
+};
+
+static int cmd64x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cmd64x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cmd64x_ide_init);
+module_exit(cmd64x_ide_exit);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.h linux-2.4.21-rc3/drivers/ide/pci/cmd64x.h
--- linux-2.4.20/drivers/ide/pci/cmd64x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cmd64x.h	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,147 @@
+#ifndef CMD64X_H
+#define CMD64X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...)	printk(x)
+#else
+#define cmdprintk(x...)
+#endif
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+/*
+ * CMD64x specific registers definition.
+ */
+#define CFR		0x50
+#define   CFR_INTR_CH0		0x02
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define   ARTTIM23_INTR_CH1	0x10
+#define ARTTIM2		0x57
+#define ARTTIM3		0x57
+#define DRWTIM23	0x58
+#define DRWTIM2		0x58
+#define BRST		0x59
+#define DRWTIM3		0x5b
+
+#define BMIDECR0	0x70
+#define MRDMODE		0x71
+#define   MRDMODE_INTR_CH0	0x04
+#define   MRDMODE_INTR_CH1	0x08
+#define   MRDMODE_BLK_CH0	0x10
+#define   MRDMODE_BLK_CH1	0x20
+#define BMIDESR0	0x72
+#define UDIDETCR0	0x73
+#define DTPR0		0x74
+#define BMIDECR1	0x78
+#define BMIDECSR	0x79
+#define BMIDESR1	0x7A
+#define UDIDETCR1	0x7B
+#define DTPR1		0x7C
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc;
+
+static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
+static int cmd64x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cmd64x_procs[] __initdata = {
+	{
+		.name		= "cmd64x",
+		.set		= 1,
+		.get_info	= cmd64x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_cmd64x(struct pci_dev *, const char *);
+static void init_hwif_cmd64x(ide_hwif_t *);
+static void init_dma_cmd64x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_643,
+		.name		= "CMD643",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_646,
+		.name		= "CMD646",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device	= PCI_DEVICE_ID_CMD_648,
+		.name		= "CMD648",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_649,
+		.name		= "CMD649",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 2,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CMD64X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.c linux-2.4.21-rc3/drivers/ide/pci/cs5530.c
--- linux-2.4.20/drivers/ide/pci/cs5530.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cs5530.c	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,463 @@
+/*
+ * linux/drivers/ide/pci/cs5530.c		Version 0.7	Sept 10, 2002
+ *
+ * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
+ * Ditto of GNU General Public License.
+ *
+ * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ *	CS5530 documentation available from National Semiconductor.
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "cs5530.h"
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p((u16)bibma + 0x02);
+	c1 = inb_p((u16)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"Cyrix 5530 Chipset.\n");
+	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");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	cs5530_xfer_set_mode	-	set a new transfer mode at the drive
+ *	@drive: drive to tune
+ *	@mode: new mode
+ *
+ *	Logging wrapper to the IDE driver speed configuration. This can
+ *	probably go away now.
+ */
+ 
+static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
+{
+	printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
+		drive->name, ide_xfer_verbose(mode));
+	return (ide_config_drive_speed(drive, mode));
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static unsigned int cs5530_pio_timings[2][5] = {
+	{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+	{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+};
+
+/*
+ * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
+ */
+#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+
+/**
+ *	cs5530_tuneproc		-	select/set PIO modes
+ *
+ *	cs5530_tuneproc() handles selection/setting of PIO modes
+ *	for both the chipset and drive.
+ *
+ *	The ide_init_cs5530() routine guarantees that all drives
+ *	will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	unsigned long basereg = CS5530_BASEREG(hwif);
+	static u8	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+		format = (hwif->INL(basereg+4) >> 31) & 1;
+		hwif->OUTL(cs5530_pio_timings[format][pio],
+			basereg+(drive->select.b.unit<<3));
+	}
+}
+
+/**
+ *	cs5530_config_dma	-	select/set DMA and UDMA modes
+ *	@drive: drive to tune
+ *
+ *	cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ *	for both the chipset and drive. The CS5530 has limitations about
+ *	mixing DMA/UDMA on the same cable.
+ */
+ 
+static int cs5530_config_dma (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+	unsigned int		reg, timings;
+	unsigned long		basereg;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);
+	/* turn off DMA while we fiddle */
+	hwif->ide_dma_host_off(drive);
+	/* clear DMA_capable bit */
+
+	/*
+	 * The CS5530 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 *
+	 * Note: This relies on the fact we never fail from UDMA to MWDMA_2
+	 * but instead drop to PIO
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if ((mateid->capability & 1) &&
+		    !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) &&
+			    (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) &&
+				 (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if ((id->capability & 1) && drive->autodma &&
+	    !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || cs5530_set_xfer_mode(drive, mode))
+		return 1;	/* failure */
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 */
+	switch (mode) {
+		case XFER_UDMA_0:	timings = 0x00921250; break;
+		case XFER_UDMA_1:	timings = 0x00911140; break;
+		case XFER_UDMA_2:	timings = 0x00911030; break;
+		case XFER_MW_DMA_0:	timings = 0x00077771; break;
+		case XFER_MW_DMA_1:	timings = 0x00012121; break;
+		case XFER_MW_DMA_2:	timings = 0x00002020; break;
+		default:
+			printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
+				drive->name, mode);
+			return 1;	/* failure */
+	}
+	basereg = CS5530_BASEREG(hwif);
+	reg = hwif->INL(basereg+4);		/* get drive0 config register */
+	timings |= reg & 0x80000000;		/* preserve PIO format bit */
+	if (unit == 0) {			/* are we configuring drive0? */
+		hwif->OUTL(timings, basereg+4);	/* write drive0 config register */
+	} else {
+		if (timings & 0x00100000)
+			reg |=  0x00100000;	/* enable UDMA timings for both drives */
+		else
+			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
+		hwif->OUTL(reg,     basereg+4);	/* write drive0 config register */
+		hwif->OUTL(timings, basereg+12);	/* write drive1 config register */
+	}
+	(void) hwif->ide_dma_host_on(drive);
+	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/**
+ *	init_chipset_5530	-	set up 5530 bridge
+ *	@dev: PCI device
+ *	@name: device name
+ *
+ *	Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+	unsigned long flags;
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cs5530_proc) {
+		cs5530_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&cs5530_procs[0]);
+	}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+	pci_for_each_dev (dev) {
+		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
+			switch (dev->device) {
+				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+					master_0 = dev;
+					break;
+				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+					cs5530_0 = dev;
+					break;
+			}
+		}
+	}
+	if (!master_0) {
+		printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+		return 0;
+	}
+	if (!cs5530_0) {
+		printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&ide_lock, flags);
+		/* all CPUs (there should only be one CPU with this chipset) */
+
+	/*
+	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
+	 */
+
+	pci_set_master(cs5530_0);
+	pci_set_mwi(cs5530_0);
+
+	/*
+	 * Set PCI CacheLineSize to 16-bytes:
+	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+	 */
+
+	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+	/*
+	 * Disable trapping of UDMA register accesses (Win98 hack):
+	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+	 */
+
+	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+	/*
+	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+	 * The other settings are what is necessary to get the register
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x40, 0x1e);
+
+	/* 
+	 * Set max PCI burst size (16-bytes seems to work best):
+	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
+	 *	all others: clear bit-1 at 0x41, and do:
+	 *	  128bytes: OR 0x00 at 0x41
+	 *	  256bytes: OR 0x04 at 0x41
+	 *	  512bytes: OR 0x08 at 0x41
+	 *	 1024bytes: OR 0x0c at 0x41
+	 */
+
+	pci_write_config_byte(master_0, 0x41, 0x14);
+
+	/*
+	 * These settings are necessary to get the chip
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x42, 0x00);
+	pci_write_config_byte(master_0, 0x43, 0xc1);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return 0;
+}
+
+/**
+ *	init_hwif_cs5530	-	initialise an IDE channel
+ *	@hwif: IDE to initialize
+ *
+ *	This gets invoked by the IDE driver once for each channel. It
+ *	performs channel-specific pre-initialization before drive probing.
+ */
+
+static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+	unsigned long basereg;
+	u32 d0_timings;
+	hwif->autodma = 0;
+
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+
+	hwif->tuneproc = &cs5530_tuneproc;
+	basereg = CS5530_BASEREG(hwif);
+	d0_timings = hwif->INL(basereg+0);
+	if (CS5530_BAD_PIO(d0_timings)) {
+		/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+		if (!hwif->drives[0].autotune)
+			hwif->drives[0].autotune = 1;
+			/* needs autotuning later */
+	}
+	if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
+	/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+		if (!hwif->drives[1].autotune)
+			hwif->drives[1].autotune = 1;
+			/* needs autotuning later */
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &cs5530_config_dma;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_cs5530		-	set up for DMA
+ *	@hwif: interface
+ *	@dmabase: DMA base address
+ *
+ *	FIXME: this can go away
+ */
+ 
+static void __init init_dma_cs5530 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cs5530_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cs5530_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CS5530 IDE",
+	.id_table	= cs5530_pci_tbl,
+	.probe		= cs5530_init_one,
+};
+
+static int cs5530_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cs5530_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cs5530_ide_init);
+module_exit(cs5530_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.h linux-2.4.21-rc3/drivers/ide/pci/cs5530.h
--- linux-2.4.20/drivers/ide/pci/cs5530.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cs5530.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef CS5530_H
+#define CS5530_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc;
+
+static int cs5530_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cs5530_procs[] __initdata = {
+	{
+		.name		= "cs5530",
+		.set		= 1,
+		.get_info	= cs5530_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_cs5530(struct pci_dev *, const char *);
+static void init_hwif_cs5530(ide_hwif_t *);
+static void init_dma_cs5530(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cs5530_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CYRIX,
+		.device		= PCI_DEVICE_ID_CYRIX_5530_IDE,
+		.name		= "CS5530",
+		.init_chipset	= init_chipset_cs5530,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cs5530,
+		.init_dma	= init_dma_cs5530,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CS5530_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.c linux-2.4.21-rc3/drivers/ide/pci/cy82c693.c
--- linux-2.4.20/drivers/ide/pci/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cy82c693.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,468 @@
+/*
+ * linux/drivers/ide/pci/cy82c693.c		Version 0.40	Sep. 10, 2002
+ *
+ *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writing the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support. 
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ *   a large and fast disk - the results look great, so I'd say the
+ *   driver is working fine :-)
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
+ *   for optimizations and bug fixing, so feel free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ *   (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ *   problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ * Ancient History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ *                       removed DMA clock speed setting by default
+ *                       added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ *                       added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
+ *                       on some drives.
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cy82c693.h"
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk (int time, int bus_speed)
+{
+	int clocks;
+
+	clocks = (time*bus_speed+999)/1000 -1;
+
+	if (clocks < 0)
+		clocks = 0;
+
+	if (clocks > 0x0F)
+		clocks = 0x0F;
+
+	return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ *       for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */ 
+static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+{
+	int clk1, clk2;
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
+
+	/* we don't check against CY82C693's min and max speed,
+	 * so you can play with the idebus=xx parameter
+	 */
+
+	if (pio > CY82C693_MAX_PIO)
+		pio = CY82C693_MAX_PIO;
+
+	/* let's calc the address setup time clocks */
+	p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+	/* let's calc the active and recovery time clocks */
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+	/* calc recovery timing */
+	clk2 =	ide_pio_timings[pio].cycle_time -
+		ide_pio_timings[pio].active_time -
+		ide_pio_timings[pio].setup_time;
+
+	clk2 = calc_clk(clk2, bus_speed);
+
+	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
+
+	/* note: we use the same values for 16bit IOR and IOW
+         *	those are all the same, since I don't have other
+	 *	timings than those from ide_modes.h
+	 */
+
+	p_pclk->time_16r = (u8)clk1;
+	p_pclk->time_16w = (u8)clk1;
+
+	/* what are good values for 8bit ?? */
+	p_pclk->time_8 = (u8)clk1;
+}
+
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+	u8 index = 0, data = 0;
+
+	if (mode>2)	/* make sure we set a valid mode */
+		mode = 2;
+			   
+	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+		mode = drive->id->tDMA;
+	
+	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the previous values */
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	data = HWIF(drive)->INB(CY82_DATA_PORT);
+
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		(data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+	data = (u8)mode|(u8)(single<<2);
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		mode, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* 
+	 * note: below we set the value for Bus Master IDE TimeOut Register
+	 * I'm not absolutly sure what this does, but it solved my problem
+	 * with IDE DMA and sound, so I now can play sound and work with
+	 * my IDE driver at the same time :-)
+	 *
+	 * If you know the correct (best) value for this register please
+	 * let me know - ASK
+	 */
+
+	data = BUSMASTER_TIMEOUT;
+	HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO	
+	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+		drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/* 
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+int cy82c693_ide_dma_on (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* Enable DMA on any drive that has DMA
+	 * (multi or single) enabled
+	 */
+	if (id->field_valid & 2) {	/* regular DMA */
+		int mmode, smode;
+
+		mmode = id->dma_mword & (id->dma_mword >> 8);
+		smode = id->dma_1word & (id->dma_1word >> 8);
+			       		      
+		if (mmode != 0) {
+			/* enable multi */
+			cy82c693_dma_enable(drive, (mmode >> 1), 0);
+		} else if (smode != 0) {
+			/* enable single */
+			cy82c693_dma_enable(drive, (smode >> 1), 1);
+		}
+	}
+        return __ide_dma_on(drive);
+}
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	pio_clocks_t pclk;
+	unsigned int addrCtrl;
+
+	/* select primary or secondary channel */
+	if (hwif->index > 0) {  /* drive is on the secondary channel */
+		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
+		if (!dev) {
+			printk(KERN_ERR "%s: tune_drive: "
+				"Cannot find secondary interface!\n",
+				drive->name);
+			return;
+		}
+	}
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the register values */
+	
+       	if (drive->select.b.unit == 0) {
+		/*
+		 * get master drive registers               	
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+		addrCtrl &= 0x0F;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+	} else {
+		/*
+		 * set slave drive registers
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= 0xF0;
+		addrCtrl >>= 4;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+	}
+
+	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+	/* first let's calc the pio modes */
+	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* let's calc the values for this PIO mode */
+	compute_clocks(pio, &pclk);
+
+	/* now let's write  the clocks registers */
+	if (drive->select.b.unit == 0) {
+		/*
+		 * set master drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		
+		addrCtrl &= (~0xF);
+		addrCtrl |= (unsigned int)pclk.address_time;
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+		
+		addrCtrl &= 0xF;
+	} else {
+		/*
+		 * set slave drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= (~0xF0);
+		addrCtrl |= ((unsigned int)pclk.address_time<<4);
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+		addrCtrl >>= 4;
+		addrCtrl &= 0xF;
+	}	
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+{
+	if (PCI_FUNC(dev->devfn) != 1)
+		return 0;
+
+#ifdef CY82C693_SETDMA_CLOCK
+	u8 data = 0;
+#endif /* CY82C693_SETDMA_CLOCK */ 
+
+	/* write info about this verion of the driver */
+	printk(KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+       /* okay let's set the DMA clock speed */
+        
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        data = inb(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+        /*
+	 * for some reason sometimes the DMA controller
+	 * speed is set to ATCLK/2 ???? - we fix this here
+	 * 
+	 * note: i don't know what causes this strange behaviour,
+	 *       but even changing the dma speed doesn't solve it :-(
+	 *       the ide performance is still only half the normal speed 
+	 * 
+	 *       if anybody knows what goes wrong with my machine, please
+	 *       let me know - ASK
+         */
+
+	data |= 0x03;
+
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */
+	return 0;
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+static void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->chipset = ide_cy82c693;
+	hwif->tuneproc = &cy82c693_tune_drive;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x04;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static __initdata ide_hwif_t *primary;
+
+void __init init_iops_cy82c693(ide_hwif_t *hwif)
+{
+	if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
+		primary = hwif;
+	else {
+		hwif->mate = primary;
+		hwif->channel = 1;
+	}
+}
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
+	struct pci_dev *dev2;
+
+	/* CY82C693 is more than only a IDE controller.
+	   Function 1 is primary IDE channel, function 2 - secondary. */
+        if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	    PCI_FUNC(dev->devfn) == 1) {
+		dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1);
+		ide_setup_pci_devices(dev, dev2, d);
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cy82c693_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Cypress IDE",
+	.id_table	= cy82c693_pci_tbl,
+	.probe		= cy82c693_init_one,
+};
+
+static int cy82c693_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cy82c693_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cy82c693_ide_init);
+module_exit(cy82c693_ide_exit);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.h linux-2.4.21-rc3/drivers/ide/pci/cy82c693.h
--- linux-2.4.20/drivers/ide/pci/cy82c693.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/cy82c693.h	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,93 @@
+#ifndef CY82C693_H
+#define CY82C693_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+/* the current version */
+#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ *	The following are used to debug the driver.
+ */
+#define	CY82C693_DEBUG_LOGS	0
+#define	CY82C693_DEBUG_INFO	0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ *	NOTE: the value for busmaster timeout is tricky and I got it by
+ *	 trial and error!  By using a to low value will cause DMA timeouts
+ *	 and drop IDE performance, and by using a to high value will cause
+ *	 audio playback to scatter.
+ *	 If you know a better value or how to calc it, please let me know.
+ */
+
+/* twice the value written in cy82c693ub datasheet */
+#define BUSMASTER_TIMEOUT	0x50
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG		0x04
+#define CY82_IDE_ADDRSETUP	0x48
+#define CY82_IDE_MASTER_IOR	0x4C	
+#define CY82_IDE_MASTER_IOW	0x4D	
+#define CY82_IDE_SLAVE_IOR	0x4E	
+#define CY82_IDE_SLAVE_IOW	0x4F
+#define CY82_IDE_MASTER_8BIT	0x50	
+#define CY82_IDE_SLAVE_8BIT	0x51	
+
+#define CY82_INDEX_PORT		0x22
+#define CY82_DATA_PORT		0x23
+
+#define CY82_INDEX_CTRLREG1	0x01
+#define CY82_INDEX_CHANNEL0	0x30
+#define CY82_INDEX_CHANNEL1	0x31
+#define CY82_INDEX_TIMEOUT	0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO	4
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED	25
+#define CY82C963_MAX_BUS_SPEED	33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+        u8	address_time;	/* Address setup (clocks) */
+	u8	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+static unsigned int init_chipset_cy82c693(struct pci_dev *, const char *);
+static void init_hwif_cy82c693(ide_hwif_t *);
+static void init_iops_cy82c693(ide_hwif_t *);
+
+static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CONTAQ,
+		.device		= PCI_DEVICE_ID_CONTAQ_82C693,
+		.name		= "CY82C693",
+		.init_chipset	= init_chipset_cy82c693,
+		.init_iops	= init_iops_cy82c693,
+		.init_hwif	= init_hwif_cy82c693,
+		.init_dma	= NULL,
+		.channels	= 1,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CY82C693_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.c linux-2.4.21-rc3/drivers/ide/pci/generic.c
--- linux-2.4.20/drivers/ide/pci/generic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/generic.c	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,169 @@
+/*
+ *  linux/drivers/ide/pci/generic.c	Version 0.11	December 30, 2002
+ *
+ *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Portions (C) Copyright 2002  Red Hat Inc <alan@redhat.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 the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "generic.h"
+
+static unsigned int __init init_chipset_generic (struct pci_dev *dev, const char *name)
+{
+	return 0;
+}
+
+static void __init init_hwif_generic (ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_UMC_UM8673F:
+		case PCI_DEVICE_ID_UMC_UM8886A:
+		case PCI_DEVICE_ID_UMC_UM8886BF:
+			hwif->irq = hwif->channel ? 15 : 14;
+			break;
+		default:
+			break;
+	}
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+#if 0
+
+	/* Logic to add back later on */
+	
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		ide_pci_device_t *unknown = unknown_chipset;
+//		unknown->vendor = dev->vendor;
+//		unknown->device = dev->device;
+		init_setup_unknown(dev, unknown);
+		return 1;
+	}
+	return 0;
+#endif	
+
+/**
+ *	generic_init_one	-	called when a PIIX is found
+ *	@dev: the generic device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+	u16 command;
+
+	if (dev->device != d->device)
+		BUG();
+	if ((d->vendor == PCI_VENDOR_ID_UMC) &&
+	    (d->device == PCI_DEVICE_ID_UMC_UM8886A) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1; /* UM8886A/BF pair */
+
+	if ((d->vendor == PCI_VENDOR_ID_OPTI) &&
+	    (d->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1;
+
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	if(!(command & PCI_COMMAND_IO))
+	{
+		printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+		return 1; 
+	}
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id generic_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PCI IDE",
+	.id_table	= generic_pci_tbl,
+	.probe		= generic_init_one,
+};
+
+static int generic_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void generic_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(generic_ide_init);
+module_exit(generic_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.h linux-2.4.21-rc3/drivers/ide/pci/generic.h
--- linux-2.4.20/drivers/ide/pci/generic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/generic.h	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,161 @@
+#ifndef IDE_GENERIC_H
+#define IDE_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_generic(struct pci_dev *, const char *);
+static void init_hwif_generic(ide_hwif_t *);
+static void init_dma_generic(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t generic_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87410,
+		.name		= "NS87410",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+        },{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		.name		= "SAMURAI",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_HOLTEK,
+		.device		= PCI_DEVICE_ID_HOLTEK_6565,
+		.name		= "HT6565",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8673F,
+		.name		= "UM8673F",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886A,
+		.name		= "UM8886A",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886BF,
+		.name		= "UM8886BF",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_HINT,
+		.device		= PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		.name		= "HINT_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C561,
+		.name		= "VIA_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C558,
+		.name		= "OPTI621V",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+static ide_pci_device_t unknown_chipset[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= 0,
+		.device		= 0,
+		.name		= "PCI_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+
+};
+
+#endif /* IDE_GENERIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.c linux-2.4.21-rc3/drivers/ide/pci/hpt34x.c
--- linux-2.4.20/drivers/ide/pci/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/hpt34x.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,370 @@
+/*
+ * linux/drivers/ide/pci/hpt34x.c		Version 0.40	Sept 10, 2002
+ *
+ * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt34x.h"
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc = 0;
+
+#define HPT34X_MAX_DEVS		8
+static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
+static int n_hpt34x_devs;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i, len;
+
+	p += sprintf(p, "\n                             "
+			"HPT34X Chipset.\n");
+	for (i = 0; i < n_hpt34x_devs; i++) {
+		struct pci_dev *dev = hpt34x_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u8  c0 = 0, c1 = 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((u16)bibma + 0x02);
+		c1 = inb_p((u16)bibma + 0x0a);
+		p += sprintf(p, "\nController: %d\n", i);
+		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");
+	}
+	p += sprintf(p, "\n");
+
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 hpt34x_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = (reg2 & ~(0x11 << drive->dn));
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+	u8			hi_speed, lo_speed;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = ((hi_speed << drive->dn) | reg2);
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x)\n",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, reg1, tmp1, reg2, tmp2,
+		hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initially for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt34x_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+#ifndef CONFIG_HPT34X_AUTODMA
+	return hwif->ide_dma_off_quietly(drive);
+#endif /* CONFIG_HPT34X_AUTODMA */
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define	HPT34X_PCI_INIT_REG		0x80
+
+static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char *name)
+{
+	int i = 0;
+	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+	unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
+	u16 cmd;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & PCI_COMMAND_MEMORY) {
+		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+			pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+				dev->resource[PCI_ROM_RESOURCE].start);
+		}
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+	} else {
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+	}
+
+	/*
+	 * Since 20-23 can be assigned and are R/W, we correct them.
+	 */
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for(i=0; i<4; i++) {
+		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+		dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
+		dev->resource[i].flags = IORESOURCE_IO;
+		pci_write_config_dword(dev,
+				(PCI_BASE_ADDRESS_0 + (i * 4)),
+				dev->resource[i].start);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	local_irq_restore(flags);
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt34x_devs[n_hpt34x_devs++] = dev;
+
+	if (!hpt34x_proc) {
+		hpt34x_proc = 1;
+		ide_pci_register_host_proc(&hpt34x_procs[0]);
+	}
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt34x (ide_hwif_t *hwif)
+{
+	u16 pcicmd = 0;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->no_dsc = 1;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt34x_chipsets[id->driver_data];
+	static char *chipset_names[] = {"HPT343", "HPT345"};
+	u16 pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
+	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt34x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT34x IDE",
+	.id_table	= hpt34x_pci_tbl,
+	.probe		= hpt34x_init_one,
+};
+
+static int hpt34x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt34x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt34x_ide_init);
+module_exit(hpt34x_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.h linux-2.4.21-rc3/drivers/ide/pci/hpt34x.h
--- linux-2.4.20/drivers/ide/pci/hpt34x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/hpt34x.h	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,60 @@
+#ifndef HPT34X_H
+#define HPT34X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define HPT343_DEBUG_DRIVE_INFO		0
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#undef DISPLAY_HPT34X_TIMINGS
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc;
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt34x_procs[] __initdata = {
+	{
+		.name		= "hpt34x",
+		.set		= 1,
+		.get_info	= hpt34x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *);
+static void init_hwif_hpt34x(ide_hwif_t *);
+static void init_dma_hpt34x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt34x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT343,
+		.name		= "HPT34X",
+		.init_chipset	= init_chipset_hpt34x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt34x,
+		.init_dma	= init_dma_hpt34x,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 16
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT34X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.c linux-2.4.21-rc3/drivers/ide/pci/hpt366.c
--- linux-2.4.20/drivers/ide/pci/hpt366.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/hpt366.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,1438 @@
+/*
+ * linux/drivers/ide/pci/hpt366.c		Version 0.36	April 25, 2003
+ *
+ * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003		Red Hat Inc
+ *
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
+ *
+ * Highpoint have their own driver (source except for the raid part)
+ * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
+ * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ *
+ * 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>
+ *
+ * Added support for 372N clocking and clock switching. The 372N needs
+ * different clocks on read/write. This requires overloading rw_disk and
+ * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for
+ * keeping me sane. 
+ *		Alan Cox <alan@redhat.com>
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt366.h"
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+
+static u8 hpt366_proc = 0;
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"302", "371",  "374" };
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370/372/374\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev = hpt_revision(dev);
+		u8 c0, c1;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		if(class_rev < 9)
+			p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		else
+			p += sprintf(p, "Chipset: HPT revision %d\n", class_rev);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb(iobase + 0x2);
+		c1 = inb(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (hpt_minimum_revision(dev, 3)) {
+			u8 cbl;
+			cbl = inb(iobase + 0x7b);
+			outb(cbl | 1, iobase + 0x7b);
+			outb(cbl & ~1, iobase + 0x7b);
+			cbl = inb(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) */
+
+/*
+ *	This wants fixing so that we do everything not by classrev
+ *	(which breaks on the newest chips) but by creating an
+ *	enumeration of chip variants and using that
+ */
+ 
+
+static u32 hpt_revision (struct pci_dev *dev)
+{
+	u32 class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	switch(dev->device) {
+		/* Remap new 372N onto 372 */
+		case PCI_DEVICE_ID_TTI_HPT372N:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		case PCI_DEVICE_ID_TTI_HPT374:
+			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+		case PCI_DEVICE_ID_TTI_HPT372:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		default:
+			break;
+	}
+	return class_rev;
+}
+
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= 0;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+	} else {				/* HPT366 and HPT368 */
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+	}
+	if (!eighty_ninty_three(drive) && (mode))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ *	Note for the future; the SATA hpt37x we must set
+ *	either PIO or UDMA modes 0,4,5
+ */
+ 
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= hpt3xx_ratemask(drive);
+
+	if (drive->media != ide_disk)
+		return min(speed, (u8)XFER_PIO_4);
+
+	switch(mode) {
+		case 0x04:
+			speed = min(speed, (u8)XFER_UDMA_6);
+			break;
+		case 0x03:
+			speed = min(speed, (u8)XFER_UDMA_5);
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				speed = min(speed, (u8)XFER_UDMA_4);
+			break;
+		case 0x02:
+			speed = min(speed, (u8)XFER_UDMA_4);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				speed = min(speed, (u8)XFER_UDMA_3);
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				speed = min(speed, (u8)XFER_UDMA_2);
+			break;
+		case 0x01:
+			speed = min(speed, (u8)XFER_UDMA_2);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+		case 0x00:
+		default:
+			speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+	}
+	return speed;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (quirk_drives == list) {
+		while (*list)
+			if (strstr(id->model, *list++))
+				return 1;
+	} else {
+		while (*list)
+			if (!strcmp(*list++,id->model))
+				return 1;
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed)
+			return chipset_table->chipset_settings;
+	return chipset_table->chipset_settings;
+}
+
+static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed		= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+	u8 regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast		= 0;
+	u32 reg1 = 0, reg2	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+	if (drive_fast & 0x02)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
+
+	reg2 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+	/*
+	 * Disable on-chip PIO FIFO/buffer
+	 *  (to avoid problems handling I/O errors later)
+	 */
+	pci_read_config_dword(dev, regtime, &reg1);
+	if (speed >= XFER_MW_DMA_0) {
+		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+	} else {
+		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+	}	
+	reg2 &= ~0x80000000;
+
+	pci_write_config_dword(dev, regtime, reg2);
+}
+
+static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_pci	= 0x40 + (drive->dn * 4);
+	u8 new_fast	= 0, drive_fast = 0;
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+	 */
+	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(dev, regfast, new_fast);
+
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       pci_get_drvdata(dev));
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
+
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					pci_get_drvdata(dev));
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
+static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
+		hpt372_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 3))
+		hpt370_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
+                hpt366_tune_chipset(drive, speed);
+
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) hpt3xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt3xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, quirk_drives));
+}
+
+static void hpt3xx_intrproc (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (drive->quirk_list)
+		return;
+	/* drives in the quirk_list may not like intr setups/cleanups */
+	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+	if (drive->quirk_list) {
+		if (hpt_minimum_revision(dev,3)) {
+			u8 reg5a = 0;
+			pci_read_config_byte(dev, 0x5a, &reg5a);
+			if (((reg5a & 0x10) >> 4) != mask)
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		} else {
+			if (mask) {
+				disable_irq(HWIF(drive)->irq);
+			} else {
+				enable_irq(HWIF(drive)->irq);
+			}
+		}
+	} else {
+		if (IDE_CONTROL_REG)
+			HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+						 (drive->ctl & ~2),
+						 IDE_CONTROL_REG);
+	}
+}
+
+static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if (id->dma_mword & hwif->mwdma_mask) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt3xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+
+	pci_read_config_byte(dev, 0x50, &reg50h);
+	pci_read_config_byte(dev, 0x52, &reg52h);
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
+	if (reg5ah & 0x10)
+		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+	/* how about we flush and reset, mmmkay? */
+	pci_write_config_byte(dev, 0x51, 0x1F);
+	/* fall through to a reset */
+	case ide_dma_begin:
+	case ide_dma_end:
+	/* reset the chips state over and over.. */
+	pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+	return __ide_dma_lostirq(drive);
+}
+
+static void hpt370_clear_engine (ide_drive_t *drive)
+{
+	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
+	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	udelay(10);
+}
+
+static int hpt370_ide_dma_begin (ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+	hpt370_clear_engine(drive);
+#endif
+	return __ide_dma_begin(drive);
+}
+
+static int hpt370_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if (dma_stat & 0x01) {
+		/* wait a little */
+		udelay(20);
+		dma_stat = hwif->INB(hwif->dma_status);
+	}
+	if ((dma_stat & 0x01) != 0) 
+		/* fallthrough */
+		(void) HWIF(drive)->ide_dma_timeout(drive);
+
+	return __ide_dma_end(drive);
+}
+
+static void hpt370_lostirq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
+	printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+	hpt370_clear_engine(drive);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop dma */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear errors */
+	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
+}
+
+static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int hpt374_ide_dma_end (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
+	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+	pci_read_config_byte(dev, mscreg, &msc_stat);
+	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	return __ide_dma_end(drive);
+}
+
+/**
+ *	hpt372n_set_clock	-	perform clock switching dance
+ *	@drive: Drive to switch
+ *	@mode: Switching mode (0x21 for write, 0x23 otherwise)
+ *
+ *	Switch the DPLL clock on the HPT372N devices. This is a
+ *	right mess.
+ */
+ 
+static void hpt372n_set_clock(ide_drive_t *drive, int mode)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	
+	/* FIXME: should we check for DMA active and BUG() */
+	/* Tristate the bus */
+	outb(0x80, hwif->dma_base+0x73);
+	outb(0x80, hwif->dma_base+0x77);
+	
+	/* Switch clock and reset channels */
+	outb(mode, hwif->dma_base+0x7B);
+	outb(0xC0, hwif->dma_base+0x79);
+	
+	/* Reset state machines */
+	outb(0x37, hwif->dma_base+0x70);
+	outb(0x37, hwif->dma_base+0x74);
+	
+	/* Complete reset */
+	outb(0x00, hwif->dma_base+0x79);
+	
+	/* Reconnect channels to bus */
+	outb(0x00, hwif->dma_base+0x73);
+	outb(0x00, hwif->dma_base+0x79);
+}
+
+/**
+ *	hpt372n_rw_disk		-	wrapper for I/O
+ *	@drive: drive for command
+ *	@rq: block request structure
+ *	@block: block number
+ *
+ *	This is called when a disk I/O is issued to the 372N instead
+ *	of the default functionality. We need it because of the clock
+ *	switching
+ *
+ */
+ 
+static ide_startstop_t hpt372n_rw_disk(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	int wantclock;
+	
+	if(rq_data_dir(rq) == READ)
+		wantclock = 0x21;
+	else
+		wantclock = 0x23;
+		
+	if(HWIF(drive)->config_data != wantclock)
+	{
+		hpt372n_set_clock(drive, wantclock);
+		HWIF(drive)->config_data = wantclock;
+	}
+	return __ide_do_rw_disk(drive, rq, block);
+}
+
+/*
+ * 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 void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	u8 reset	= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	u8 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
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 reg59h = 0, reset	= (hwif->channel) ? 0x80 : 0x40;
+	u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	switch(state)
+	{
+		case BUSSTATE_ON:
+			(void) ide_do_reset(drive);
+			pci_write_config_byte(dev, state_reg, regXXh|0x80);
+			pci_write_config_byte(dev, 0x59, reg59h|reset);
+			break;
+		case BUSSTATE_OFF:
+			pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+			pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+			(void) ide_do_reset(drive);
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* 
+ * 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);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 tristate = 0, resetmask = 0, bus_reg = 0;
+	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(dev, tristate, &tri_reg);
+	pci_read_config_byte(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;
+	default:
+		return -EINVAL;
+	}
+	pci_write_config_byte(dev, 0x59, bus_reg);
+	pci_write_config_word(dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static int __init init_hpt37x(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	u8 reg5bh;
+	u8 reg5ah;
+	unsigned long dmabase = pci_resource_start(dev, 4);
+	u8 did, rid;	
+	int is_372n = 0;
+#if 1
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
+
+	if(dmabase)
+	{
+		did = inb(dmabase + 0x22);
+		rid = inb(dmabase + 0x28);
+	
+		if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+			is_372n = 1;
+	}
+		
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables. Needed
+	 * for some drives such as IBM-DTLA which will not enter ready
+	 * state on reset when PDIAG is a input.
+	 *
+	 * ToDo: should we set 0x21 when using PLL mode ?
+	 */
+	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
+	 *
+	 * Todo. For non x86 should probably check the dword is
+	 * set to 0xABCDExxx indicating the BIOS saved f_CNT
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	
+	/*
+	 * The 372N uses different PCI clock information and has
+	 * some other complications
+	 *	On PCI33 timing we must clock switch
+	 *	On PCI66 timing we must NOT use the PCI clock
+	 *
+	 * Currently we always set up the PLL for the 372N
+	 */
+	 
+	if(is_372n)
+	{
+		printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
+		if(freq < 0x55)
+			pll = F_LOW_PCI_33;
+		else if(freq < 0x70)
+			pll = F_LOW_PCI_40;
+		else if(freq < 0x7F)
+			pll = F_LOW_PCI_50;
+		else
+			pll = F_LOW_PCI_66;
+			
+		printk(KERN_INFO "FREQ: %d PLL: %d\n", freq, pll);
+			
+		/* We always use the pll not the PCI clock on 372N */
+	}
+	else
+	{
+		if(freq < 0x9C)
+			pll = F_LOW_PCI_33;
+		else if(freq < 0xb0)
+			pll = F_LOW_PCI_40;
+		else if(freq <0xc8)
+			pll = F_LOW_PCI_50;
+		else
+			pll = F_LOW_PCI_66;
+	
+		if (pll == F_LOW_PCI_33) {
+			if (hpt_minimum_revision(dev,8))
+				pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+			else if (hpt_minimum_revision(dev,5))
+				pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+			else if (hpt_minimum_revision(dev,4))
+				pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+			else
+				pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+			printk("HPT37X: using 33MHz PCI clock\n");
+		} else if (pll == F_LOW_PCI_40) {
+		} else if (pll == F_LOW_PCI_50) {
+			if (hpt_minimum_revision(dev,8))
+				pci_set_drvdata(dev, NULL);
+			else if (hpt_minimum_revision(dev,5))
+				pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+			else if (hpt_minimum_revision(dev,4))
+				pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+			else
+				pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+			printk("HPT37X: using 50MHz PCI clock\n");
+		} else {
+			if (hpt_minimum_revision(dev,8))
+			{
+				printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+				pci_set_drvdata(dev, NULL);
+			}
+			else if (hpt_minimum_revision(dev,5))
+				pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+			else if (hpt_minimum_revision(dev,4))
+				pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+			else
+				pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+			printk("HPT37X: 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.
+	 *
+	 * ToDo: Use 66MHz PLL when ATA133 devices are present on a
+	 * 372 device so we can get ATA133 support
+	 */
+	if (pci_get_drvdata(dev)) 
+		goto init_hpt37X_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);
+				if (hpt_minimum_revision(dev,8))
+					return -EOPNOTSUPP;
+				else if (hpt_minimum_revision(dev,5))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+				else if (hpt_minimum_revision(dev,4))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				else
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt37X_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+	return 0;
+}
+
+static int __init init_hpt366 (struct pci_dev *dev)
+{
+	u32 reg1	= 0;
+	u8 drive_fast	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+									
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			pci_set_drvdata(dev, (void *) forty_base_hpt366);
+			break;
+		case 9:
+			pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+			break;
+		case 7:
+		default:
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+			break;
+	}
+
+	if (!pci_get_drvdata(dev))
+	{
+		printk(KERN_ERR "hpt366: unknown bus timing.\n");
+		pci_set_drvdata(dev, NULL);
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_hpt366 (struct pci_dev *dev, const char *name)
+{
+	int ret = 0;
+	u8 test = 0;
+
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		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 (test != (L1_CACHE_BYTES / 4))
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+			(L1_CACHE_BYTES / 4));
+
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+	if (test != 0x78)
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+	if (hpt_minimum_revision(dev, 3)) {
+		ret = init_hpt37x(dev);
+	} else {
+		ret =init_hpt366(dev);
+	}
+	if (ret)
+		return ret;
+	
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt_devs[n_hpt_devs++] = dev;
+
+	if (!hpt366_proc) {
+		hpt366_proc = 1;
+		ide_pci_register_host_proc(&hpt366_procs[0]);
+	}
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt366 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev		= hwif->pci_dev;
+	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+	u8 did, rid;
+	unsigned long dmabase		= hwif->dma_base;
+	int is_372n = 0;
+	
+	if(dmabase)
+	{
+		did = inb(dmabase + 0x22);
+		rid = inb(dmabase + 0x28);
+	
+		if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+			is_372n = 1;
+	}
+		
+	if(is_372n)
+		printk(KERN_ERR "HPT372N support is EXPERIMENTAL ONLY.\n");
+		
+	hwif->tuneproc			= &hpt3xx_tune_drive;
+	hwif->speedproc			= &hpt3xx_tune_chipset;
+	hwif->quirkproc			= &hpt3xx_quirkproc;
+	hwif->intrproc			= &hpt3xx_intrproc;
+	hwif->maskproc			= &hpt3xx_maskproc;
+	
+	if(is_372n)
+		hwif->rw_disk = &hpt372n_rw_disk;
+
+	/*
+	 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+	 * address lines to access an external eeprom.  To read valid
+	 * cable detect state the pins must be enabled as inputs.
+	 */
+	if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) {
+		/*
+		 * HPT374 PCI function 1
+		 * - set bit 15 of reg 0x52 to enable TCBLID as input
+		 * - set bit 15 of reg 0x56 to enable FCBLID as input
+		 */
+		u16 mcr3, mcr6;
+		pci_read_config_word(dev, 0x52, &mcr3);
+		pci_read_config_word(dev, 0x56, &mcr6);
+		pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
+		pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+		/* now read cable id register */
+		pci_read_config_byte(dev, 0x5a, &ata66);
+		pci_write_config_word(dev, 0x52, mcr3);
+		pci_write_config_word(dev, 0x56, mcr6);
+	} else if (hpt_minimum_revision(dev, 3)) {
+		/*
+		 * HPT370/372 and 374 pcifn 0
+		 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+		 */
+		u8 scr2;
+		pci_read_config_byte(dev, 0x5b, &scr2);
+		pci_write_config_byte(dev, 0x5b, scr2 & ~1);
+		/* now read cable id register */
+		pci_read_config_byte(dev, 0x5a, &ata66);
+		pci_write_config_byte(dev, 0x5b, scr2);
+	} else {
+		pci_read_config_byte(dev, 0x5a, &ata66);
+	}
+
+#ifdef DEBUG
+	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+		ata66, (ata66 & regmask) ? "33" : "66",
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	if (hpt_minimum_revision(dev,3)) {
+		u8 reg5ah = 0;
+			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+//		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+	} else if (hpt_minimum_revision(dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
+		hwif->resetproc = &hpt3xx_reset;
+		hwif->busproc   = &hpt3xx_tristate;
+	}
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
+	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+	if (hpt_minimum_revision(dev,8))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,5))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,3)) {
+		hwif->ide_dma_begin = &hpt370_ide_dma_begin;
+		hwif->ide_dma_end = &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
+	} else if (hpt_minimum_revision(dev,2))
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+	else
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 masterdma	= 0, slavedma = 0;
+	u8 dma_new	= 0, dma_old = 0;
+	u8 primary	= hwif->channel ? 0x4b : 0x43;
+	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	unsigned long flags;
+
+	if (!dmabase)
+		return;
+		
+	if(pci_get_drvdata(hwif->pci_dev) == NULL)
+	{
+		printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
+		return;
+	}
+
+	dma_old = hwif->INB(dmabase+2);
+
+	local_irq_save(flags);
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old)
+		hwif->OUTB(dma_new, dmabase+2);
+
+	local_irq_restore(flags);
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			u8 irq = 0, irq2 = 0;
+			pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+			pci_read_config_byte(findev, PCI_INTERRUPT_LINE, &irq2);
+			if (irq != irq2) {
+				pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				findev->irq = dev->irq;
+				printk("%s: pci-config space interrupt "
+					"fixed.\n", d->name);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt37x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+	u8 pin1 = 0, pin2 = 0;
+	unsigned int class_rev;
+	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
+				 "HPT370", "HPT370A", "HPT372"};
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	/* New ident 372N reports revision 1. We could do the 
+	   io port based type identification instead perhaps (DID, RID) */
+	   
+	if(d->device == PCI_DEVICE_ID_TTI_HPT372N)
+		class_rev = 5;
+		
+	strcpy(d->name, chipset_names[class_rev]);
+
+	switch(class_rev) {
+		case 5:
+		case 4:
+		case 3: ide_setup_pci_device(dev, d);
+			return;
+		default:	break;
+	}
+
+	d->channels = 1;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
+			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, "
+					"pin1=%d pin2=%d\n", d->name,
+					pin1, pin2);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	hpt366_init_one	-	called when an HPT366 is found
+ *	@dev: the hpt366 device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt366_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT366 IDE",
+	.id_table	= hpt366_pci_tbl,
+	.probe		= hpt366_init_one,
+};
+
+static int hpt366_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt366_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt366_ide_init);
+module_exit(hpt366_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.h linux-2.4.21-rc3/drivers/ide/pci/hpt366.h
--- linux-2.4.20/drivers/ide/pci/hpt366.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/hpt366.h	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,537 @@
+#ifndef HPT366_H
+#define HPT366_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_HPT366_TIMINGS
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+const char *quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP LM20.5",
+        NULL
+};
+
+const char *bad_ata100_5[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_4[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_3[] = {
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata33[] = {
+	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+	"Maxtor 90510D4",
+	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+	NULL
+};
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	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_hpt366[] = {
+	{	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_hpt366[] = {
+	{	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_hpt366[] = {
+
+	{	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	}
+};
+
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
+	{	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      }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+        {       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_hpt370a[] = {
+	{       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       }
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
+	{       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      }
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	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,		0x0a81f443	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	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,		0x06814e93	}
+};
+
+#if 0
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO		0
+#define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
+#define HPT372_ALLOW_ATA133_6		1
+#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
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt366_proc;
+
+static int hpt366_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt366_procs[] __initdata = {
+	{
+		.name		= "hpt366",
+		.set		= 1,
+		.get_info	= hpt366_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_hpt366(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt37x(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt374(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_hpt366(struct pci_dev *, const char *);
+static void init_hwif_hpt366(ide_hwif_t *);
+static void init_dma_hpt366(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT366,
+		.name		= "HPT366",
+		.init_setup	= init_setup_hpt366,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT372,
+		.name		= "HPT372A",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT302,
+		.name		= "HPT302",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT371,
+		.name		= "HPT371",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT374,
+		.name		= "HPT374",
+		.init_setup	= init_setup_hpt374,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,	/* 4 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT372N,
+		.name		= "HPT372N",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,	/* 4 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT366_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.c linux-2.4.21-rc3/drivers/ide/pci/it8172.c
--- linux-2.4.20/drivers/ide/pci/it8172.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/it8172.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,334 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *      IT8172 IDE controller support
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *              stevel@mvista.com or source@mvista.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 the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/it8172/it8172_int.h>
+
+#include "ide_modes.h"
+#include "it8172.h"
+
+/*
+ * Prototypes
+ */
+static u8 it8172_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (hwif->drives[1] == drive);
+	unsigned long flags;
+	u16 drive_enables;
+	u32 drive_timing;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, 0x40, &drive_enables);
+	pci_read_config_dword(dev, 0x44, &drive_timing);
+
+	/*
+	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+	 * are being left at the default values of 8 PCI clocks (242 nsec
+	 * for a 33 MHz clock). These can be safely shortened at higher
+	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
+	 * apply to PIO modes, not to the DMA modes.
+	 */
+
+	/*
+	 * Enable port 0x44. The IT8172G spec is confused; it calls
+	 * this register the "Slave IDE Timing Register", but in fact,
+	 * it controls timing for both master and slave drives.
+	 */
+	drive_enables |= 0x4000;
+
+	if (is_slave) {
+		drive_enables &= 0xc006;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0060;
+	} else {
+		drive_enables &= 0xc060;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0006;
+	}
+
+	pci_write_config_word(dev, 0x40, drive_enables);
+	spin_unlock_irqrestore(&ide_lock, flags)
+}
+
+static u8 it8172_dma_2_pio (u8 xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(it8172_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	u8 reg48, reg4a;
+
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x4a, &reg4a);
+
+    /*
+     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+     * transfers on some drives, even though both numbers meet the minimum
+     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+     * So the faster times are just commented out here. The good news is
+     * that the slower cycle time has very little affect on transfer
+     * performance.
+     */
+    
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		reg4a &= ~a_speed;
+		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+	} else {
+		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) it8172_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = it8172_config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!it8172_config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!it8172_config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		it8172_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+{
+	unsigned char progif;
+    
+	/*
+	 * Place both IDE interfaces into PCI "native" mode
+	 */
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+
+	return IT8172_IDE_IRQ;
+}
+
+
+static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+{
+	struct pci_dev* dev = hwif->pci_dev;
+	unsigned long cmdBase, ctrlBase;
+    
+	hwif->autodma = 0;
+	hwif->tuneproc = &it8172_tune_drive;
+	hwif->speedproc = &it8172_tune_chipset;
+
+	cmdBase = dev->resource[0].start;
+	ctrlBase = dev->resource[1].start;
+    
+	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->noprobe = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &it8172_chipsets[id->driver_data];
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return 1; /* IT8172 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id it8172_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "IT8172IDE",
+	.id_table	= it8172_pci_tbl,
+	.probe		= it8172_init_one,
+};
+
+static int it8172_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void it8172_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(it8172_ide_init);
+module_exit(it8172_ide_exit);
+
+MODULE_AUTHOR("SteveL@mvista.com");
+MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.h linux-2.4.21-rc3/drivers/ide/pci/it8172.h
--- linux-2.4.20/drivers/ide/pci/it8172.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/it8172.h	2003-05-22 22:06:37.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef ITE8172G_H
+#define ITE8172G_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static u8 it8172_ratemask(ide_drive_t *drive);
+static u8 it8172_ratefilter(ide_drive_t *drive, u8 speed);
+static void it8172_tune_drive(ide_drive_t *drive, u8 pio);
+static u8 it8172_dma_2_pio(u8 xfer_rate);
+static int it8172_tune_chipset(ide_drive_t *drive, u8 xferspeed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma(ide_drive_t *drive);
+#endif
+
+static void init_setup_it8172(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_it8172(struct pci_dev *, const char *);
+static void init_hwif_it8172(ide_hwif_t *);
+static void init_dma_it8172(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ITE,
+		.device		= PCI_DEVICE_ID_ITE_IT8172G,
+		.name		= "IT8172G",
+		.init_setup	= init_setup_it8172,
+		.init_chipset	= init_chipset_it8172,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_it8172,
+                .init_dma	= init_dma_it8172,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ITE8172G_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.c linux-2.4.21-rc3/drivers/ide/pci/ns87415.c
--- linux-2.4.20/drivers/ide/pci/ns87415.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/ns87415.c	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/ide/pci/ns87415.c		Version 2.00  Sep. 10, 2002
+ *
+ * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ *
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ns87415.h"
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	new = *old;
+
+	/* Adjust IRQ enable bit */
+	bit = 1 << (8 + hwif->channel);
+	new = drive->present ? (new & ~bit) : (new | bit);
+
+	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
+
+	if (new != *old) {
+		unsigned char stat;
+
+		/*
+		 * Don't change DMA engine settings while Write Buffers
+		 * are busy.
+		 */
+		(void) pci_read_config_byte(dev, 0x43, &stat);
+		while (stat & 0x03) {
+			udelay(1);
+			(void) pci_read_config_byte(dev, 0x43, &stat);
+		}
+
+		*old = new;
+		(void) pci_write_config_dword(dev, 0x40, new);
+
+		/*
+		 * And let things settle...
+		 */
+		udelay(10);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+	ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t      *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+	/* from ERRATA: clear the INTR & ERROR bits */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	hwif->OUTB(dma_cmd|6, hwif->dma_command);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int ns87415_ide_dma_read (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_read(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_write (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_write(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_check (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	return __ide_dma_check(drive);
+}
+
+static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int ctrl, using_inta;
+	u8 progif;
+#ifdef __sparc_v9__
+	int timeout;
+	u8 stat;
+#endif
+
+	hwif->autodma = 0;
+	hwif->selectproc = &ns87415_selectproc;
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+	/*
+	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
+	 * Also, leave IRQ masked during drive probing, to prevent infinite
+	 * interrupts from a potentially floating INTA..
+	 *
+	 * IRQs get unmasked in selectproc when drive is first used.
+	 */
+	(void) pci_read_config_dword(dev, 0x40, &ctrl);
+	(void) pci_read_config_byte(dev, 0x09, &progif);
+	/* is irq in "native" mode? */
+	using_inta = progif & (1 << (hwif->channel << 1));
+	if (!using_inta)
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
+	} else {
+		hwif->select_data = (unsigned long)
+					&ns87415_control[ns87415_count++];
+		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
+		if (using_inta)
+			ctrl &= ~(1 << 6);	/* unmask INTA */
+		*((unsigned int *)hwif->select_data) = ctrl;
+		(void) pci_write_config_dword(dev, 0x40, ctrl);
+
+		/*
+		 * Set prefetch size to 512 bytes for both ports,
+		 * but don't turn on/off prefetching here.
+		 */
+		pci_write_config_byte(dev, 0x55, 0xee);
+
+#ifdef __sparc_v9__
+		/*
+		 * XXX: Reset the device, if we don't it will not respond
+		 *      to SELECT_DRIVE() properly during first probe_hwif().
+		 */
+		timeout = 10000;
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			udelay(50);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+                	if (stat == 0xff)
+                        	break;
+        	} while ((stat & BUSY_STAT) && --timeout);
+#endif
+	}
+
+	if (!using_inta)
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->OUTB(0x60, hwif->dma_status);
+	hwif->ide_dma_read = &ns87415_ide_dma_read;
+	hwif->ide_dma_write = &ns87415_ide_dma_write;
+	hwif->ide_dma_check = &ns87415_ide_dma_check;
+	hwif->ide_dma_end = &ns87415_ide_dma_end;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ns87415_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id ns87415_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "NS87415IDE",
+	.id_table	= ns87415_pci_tbl,
+	.probe		= ns87415_init_one,
+};
+
+static int ns87415_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ns87415_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ns87415_ide_init);
+module_exit(ns87415_ide_exit);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.h linux-2.4.21-rc3/drivers/ide/pci/ns87415.h
--- linux-2.4.20/drivers/ide/pci/ns87415.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/ns87415.h	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef NS87415_H
+#define NS87415_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_ns87415(ide_hwif_t *);
+static void init_dma_ns87415(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ns87415_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87415,
+		.name		= "NS87415",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ns87415,
+                .init_dma	= init_dma_ns87415,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* NS87415_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.c linux-2.4.21-rc3/drivers/ide/pci/opti621.c
--- linux-2.4.20/drivers/ide/pci/opti621.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/opti621.c	2003-05-22 22:06:27.000000000 +0000
@@ -0,0 +1,403 @@
+/*
+ *  linux/drivers/ide/pci/opti621.c		Version 0.7	Sept 10, 2002
+ *
+ *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
+ * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
+ * and disassembled/traced setupvic.exe (DOS program).
+ * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
+ * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
+ * It has a place for a secondary connector in circuit, but nothing
+ * is there. Also BIOS says no address for
+ * secondary controller (see bellow in ide_init_opti621).
+ * I've only tested this on my system, which only has one disk.
+ * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
+ * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
+ * lockups). I tried the OCTEK double speed CD-ROM and
+ * it does not work! But I can't boot DOS also, so it's probably
+ * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
+ * problems) and Seagate 1GB (as slave, WD as master). My experiences
+ * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
+ * it slows to about 100kB/s! I don't know why and I have
+ * not this drive now, so I can't try it again.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
+ * The main problem with OPTi is that some timings for master
+ * and slave must be the same. For example, if you have master
+ * PIO 3 and slave PIO 0, driver have to set some timings of
+ * master for PIO 0. Second problem is that opti621_tune_drive
+ * got only one drive to set, but have to set both drives.
+ * This is solved in compute_pios. If you don't set
+ * the second drive, compute_pios use ide_get_best_pio_mode
+ * for autoselect mode (you can change it to PIO 0, if you want).
+ * If you then set the second drive to another PIO, the old value
+ * (automatically selected) will be overrided by yours.
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency which get
+ * (use idebus=xx to select PCI bus speed).
+ * Use ide0=autotune for automatical tune of the PIO modes.
+ * If you get strange results, do not use this and set PIO manually
+ * by hdparm.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8. 
+ * Initial version of driver.
+ * 
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ * 
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
+ */
+
+#undef REALLY_SLOW_IO	/* most systems can safely undef this */
+#define OPTI621_DEBUG		/* define for debug messages */
+
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "opti621.h"
+
+#define OPTI621_MAX_PIO 3
+/* In fact, I do not have any PIO 4 drive
+ * (address: 25 ns, data: 70 ns, recovery: 35 ns),
+ * but OPTi 82C621 is programmable and it can do (minimal values):
+ * on 40MHz PCI bus (pulse 25 ns):
+ *  address: 25 ns, data: 25 ns, recovery: 50 ns;
+ * on 20MHz PCI bus (pulse 50 ns):
+ *  address: 50 ns, data: 50 ns, recovery: 100 ns.
+ */
+
+/* #define READ_PREFETCH 0 */
+/* Uncomment for disable read prefetch.
+ * There is some readprefetch capatibility in hdparm,
+ * but when I type hdparm -P 1 /dev/hda, I got errors
+ * and till reset drive is inaccessible.
+ * This (hw) read prefetch is safe on my drive.
+ */
+
+#ifndef READ_PREFETCH
+#define READ_PREFETCH 0x40 /* read prefetch is enabled */
+#endif /* else read prefetch is disabled */
+
+#define READ_REG 0	/* index of Read cycle timing register */
+#define WRITE_REG 1	/* index of Write cycle timing register */
+#define CNTRL_REG 3	/* index of Control register */
+#define STRAP_REG 5	/* index of Strap register */
+#define MISC_REG 6	/* index of Miscellaneous register */
+
+static int reg_base;
+
+#define PIO_NOT_EXIST 254
+#define PIO_DONT_KNOW 255
+
+/* there are stored pio numbers from other calls of opti621_tune_drive */
+static void compute_pios(ide_drive_t *drive, u8 pio)
+/* Store values into drive->drive_data
+ *	second_contr - 0 for primary controller, 1 for secondary
+ *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
+ *	pio - PIO mode for selected drive (for other we don't know)
+ */
+{
+	int d;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	for (d = 0; d < 2; ++d) {
+		drive = &hwif->drives[d];
+		if (drive->present) {
+			if (drive->drive_data == PIO_DONT_KNOW)
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+#ifdef OPTI621_DEBUG
+			printk("%s: Selected PIO mode %d\n",
+				drive->name, drive->drive_data);
+#endif
+		} else {
+			drive->drive_data = PIO_NOT_EXIST;
+		}
+	}
+}
+
+static int cmpt_clk(int time, int bus_speed)
+/* Returns (rounded up) time in clocks for time in ns,
+ * with bus_speed in MHz.
+ * Example: bus_speed = 40 MHz, time = 80 ns
+ * 1000/40 = 25 ns (clk value),
+ * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
+ * Use idebus=xx to select right frequency.
+ */
+{
+	return ((time*bus_speed+999)/1000);
+}
+
+static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
+/* Write value to register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	hwif->OUTB(value, reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+}
+
+static u8 read_reg(ide_hwif_t *hwif, int reg)
+/* Read value from register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	u8 ret = 0;
+
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	ret = hwif->INB(reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+	return ret;
+}
+
+typedef struct pio_clocks_s {
+	int	address_time;	/* Address setup (clocks) */
+	int	data_time;	/* Active/data pulse (clocks) */
+	int	recovery_time;	/* Recovery time (clocks) */
+} pio_clocks_t;
+
+static void compute_clocks(int pio, pio_clocks_t *clks)
+{
+        if (pio != PIO_NOT_EXIST) {
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
+ 	       	adr_setup = ide_pio_timings[pio].setup_time;
+  	      	data_pls = ide_pio_timings[pio].active_time;
+	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+     			- adr_setup-data_pls, bus_speed);
+     		if (clks->address_time<1) clks->address_time = 1;
+     		if (clks->address_time>4) clks->address_time = 4;
+     		if (clks->data_time<1) clks->data_time = 1;
+     		if (clks->data_time>16) clks->data_time = 16;
+     		if (clks->recovery_time<2) clks->recovery_time = 2;
+     		if (clks->recovery_time>17) clks->recovery_time = 17;
+	} else {
+		clks->address_time = 1;
+		clks->data_time = 1;
+		clks->recovery_time = 2;
+		/* minimal values */
+	}
+ 
+}
+
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	/* primary and secondary drives share some registers,
+	 * so we have to program both drives
+	 */
+	unsigned long flags;
+	u8 pio1 = 0, pio2 = 0;
+	pio_clocks_t first, second;
+	int ax, drdy;
+	u8 cycle1, cycle2, misc;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	/* sets drive->drive_data for both drives */
+	compute_pios(drive, pio);
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
+
+	compute_clocks(pio1, &first);
+	compute_clocks(pio2, &second);
+
+	/* ax = max(a1,a2) */
+	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
+
+	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
+
+	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
+	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
+	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
+
+#ifdef OPTI621_DEBUG
+	printk("%s: master: address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, first.data_time,
+		first.recovery_time, drdy);
+	printk("%s: slave:  address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, second.data_time,
+		second.recovery_time, drdy);
+#endif
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+
+	/* allow Register-B */
+	hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+	/* hmm, setupvic.exe does this ;-) */
+	hwif->OUTB(0xff, reg_base+5);
+	/* if reads 0xff, adapter not exist? */
+	(void) hwif->INB(reg_base+CNTRL_REG);
+	/* if reads 0xc0, no interface exist? */
+	read_reg(hwif, CNTRL_REG);
+	/* read version, probably 0 */
+	read_reg(hwif, STRAP_REG);
+
+	/* program primary drive */
+		/* select Index-0 for Register-A */
+	write_reg(hwif, 0,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle1, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle1, WRITE_REG);
+
+	/* program secondary drive */
+		/* select Index-1 for Register-B */
+	write_reg(hwif, 1,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle2, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle2, WRITE_REG);
+
+	/* use Register-A for drive 0 */
+	/* use Register-B for drive 1 */
+	write_reg(hwif, 0x85, CNTRL_REG);
+
+	/* set address setup, DRDY timings,   */
+	/*  and read prefetch for both drives */
+ 	write_reg(hwif, misc, MISC_REG);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * init_hwif_opti621() is called once for each hwif found at boot.
+ */
+static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->drives[0].drive_data = PIO_DONT_KNOW;
+	hwif->drives[1].drive_data = PIO_DONT_KNOW;
+	hwif->tuneproc = &opti621_tune_drive;
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &opti621_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id opti621_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Opti621 IDE",
+	.id_table	= opti621_pci_tbl,
+	.probe		= opti621_init_one,
+};
+
+static int opti621_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void opti621_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(opti621_ide_init);
+module_exit(opti621_ide_exit);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.h linux-2.4.21-rc3/drivers/ide/pci/opti621.h
--- linux-2.4.20/drivers/ide/pci/opti621.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/opti621.h	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,49 @@
+#ifndef OPTI621_H
+#define OPTI621_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_opti621(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_opti621(ide_hwif_t *);
+static void init_dma_opti621(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C621,
+		.name		= "OPTI621",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+		.init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C825,
+		.name		= "OPTI621X",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+                .init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* OPTI621_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.c linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_new.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_new.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,680 @@
+/*
+ *  Promise TX2/TX4/TX2000/133 IDE driver
+ *
+ *  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.
+ *
+ *  Split from:
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_new.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdcnew_info(char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "SBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "MBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "MBUltra133"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "FastTrak TX2000"); break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+			p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "Ultra133 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "Ultra100 TX2"); break;
+		default:
+			p += sprintf(p, "Ultra series"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdcnew_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i, len;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdcnew_info(buffer, dev);
+	}
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdcnew_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			mode = 4;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdcnew_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	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);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long indexreg	= hwif->dma_vendor1;
+	unsigned long datareg	= hwif->dma_vendor3;
+	u8 thold		= 0x10;
+	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
+	u8 speed		= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	if (speed == XFER_UDMA_2) {
+		hwif->OUTB((thold + adj), indexreg);
+		hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+	}
+
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:	set_ultra(0x1a, 0x01, 0xcb); break;
+		case XFER_UDMA_5:	set_ultra(0x1a, 0x02, 0xcb); break;
+		case XFER_UDMA_4:	set_ultra(0x1a, 0x03, 0xcd); break;
+		case XFER_UDMA_3:	set_ultra(0x1a, 0x05, 0xcd); break;
+		case XFER_UDMA_2:	set_ultra(0x2a, 0x07, 0xcd); break;
+		case XFER_UDMA_1:	set_ultra(0x3a, 0x0a, 0xd0); break;
+		case XFER_UDMA_0:	set_ultra(0x4a, 0x0f, 0xd5); break;
+		case XFER_MW_DMA_2:	set_ata2(0x69, 0x25); break;
+		case XFER_MW_DMA_1:	set_ata2(0x6b, 0x27); break;
+		case XFER_MW_DMA_0:	set_ata2(0xdf, 0x5f); break;
+		case XFER_PIO_4:	set_pio(0x23, 0x09, 0x25); break;
+		case XFER_PIO_3:	set_pio(0x27, 0x0d, 0x35); break;
+		case XFER_PIO_2:	set_pio(0x23, 0x26, 0x64); break;
+		case XFER_PIO_1:	set_pio(0x46, 0x29, 0xa4); break;
+		case XFER_PIO_0:	set_pio(0xfb, 0x2b, 0xac); break;
+		default:
+			;
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdcnew_tune_chipset(drive, speed));
+}
+
+static void pdcnew_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+{
+	hwif->OUTB(0x0b, hwif->dma_vendor1);
+	return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= -1;
+	u8 cable		= 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			cable = pdcnew_new_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk(KERN_DEBUG "%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		default:
+			/* If it's not one we know we should never
+			   arrive here.. */
+			BUG();
+	}
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, separating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk(KERN_DEBUG "         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+	}
+
+	if (drive->media != ide_disk)
+		return 0;
+	if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+		hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+		hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+	}
+
+	speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+
+	if (!(speed)) {
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdcnew_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdcnew_new_reset (ide_drive_t *drive)
+{
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+static void pdcnew_reset_host (ide_hwif_t *hwif)
+{
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdcnew_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdcnew_reset_host(hwif);
+	pdcnew_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name)
+{
+	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(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdcnew_proc) {
+		pdcnew_proc = 1;
+		ide_pci_register_host_proc(&pdcnew_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->tuneproc  = &pdcnew_tune_drive;
+	hwif->quirkproc = &pdcnew_quirkproc;
+	hwif->speedproc = &pdcnew_new_tune_chipset;
+	hwif->resetproc = &pdcnew_new_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
+	if (!(hwif->udma_four))
+		hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk(KERN_DEBUG "%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev;
+
+	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)) {
+				u8 irq = 0, irq2 = 0;
+				pci_read_config_byte(dev,
+					PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(findev,
+					PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					findev->irq = dev->irq;
+					pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				}
+				ide_setup_pci_devices(dev, findev, d);
+				return;
+			}
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202new_init_one	-	called when a pdc202xx is found
+ *	@dev: the pdc202new device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202new_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise IDE",
+	.id_table	= pdc202new_pci_tbl,
+	.probe		= pdc202new_init_one,
+};
+
+static int pdc202new_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202new_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202new_ide_init);
+module_exit(pdc202new_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.h linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_new.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_new.h	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,308 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc;
+
+static int pdcnew_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcnew_procs[] __initdata = {
+	{
+		.name		= "pdcnew",
+		.set		= 1,
+		.get_info	= pdcnew_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdcnew(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+static unsigned int init_chipset_pdcnew(struct pci_dev *, const char *);
+static void init_hwif_pdc202new(ide_hwif_t *);
+static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20268,
+		.name		= "PDC20268",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20269,
+		.name		= "PDC20269",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20270,
+		.name		= "PDC20270",
+		.init_setup	= init_setup_pdc20270,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20271,
+		.name		= "PDC20271",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20275,
+		.name		= "PDC20275",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20276,
+		.name		= "PDC20276",
+		.init_setup	= init_setup_pdc20276,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20277,
+		.name		= "PDC20277",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.c linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_old.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_old.c	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,963 @@
+/*
+ *  linux/drivers/ide/pci/pdc202xx_old.c	Version 0.36	Sept 11, 2002
+ *
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  Promise Ultra100 cards.
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_old.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	unsigned long 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;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((u16)bibma + 0x02);
+	u8 c1	= inb_p((u16)bibma + 0x0a);
+
+	u8 sc11	= inb_p((u16)bibma + 0x11);
+	u8 sc1a	= inb_p((u16)bibma + 0x1a);
+	u8 sc1b	= inb_p((u16)bibma + 0x1b);
+	u8 sc1c	= inb_p((u16)bibma + 0x1c); 
+	u8 sc1d	= inb_p((u16)bibma + 0x1d);
+	u8 sc1e	= inb_p((u16)bibma + 0x1e);
+	u8 sc1f	= inb_p((u16)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "Ultra100"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "Ultra100 on M/B"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "FastTrak 66"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "Ultra66"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "Ultra33");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "Ultra Series"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	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 ");
+	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
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i, len;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdc202xx_info(buffer, dev);
+	}
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			return 1;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	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);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	pdc202xx_tune_chipset(drive, speed);
+}
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+	return ((u8)(CIS & mask));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 drive_conf		= 0;
+	u8 mask			= hwif->channel ? 0x08 : 0x02;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 test1 = 0, test2 = 0, speed = -1;
+	u8 AP = 0, CLKSPD = 0, cable = 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			cable = pdc202xx_old_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk(KERN_DEBUG "%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			ultra_66 = 0;
+			break;
+		default:
+			BUG();
+	}
+
+	CLKSPD = hwif->INB(hwif->dma_master + 0x11);
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, separating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk(KERN_DEBUG "         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+	} else {
+		if (ultra_66) {
+			/*
+			 * 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 & 0x0078) {
+					hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+				} else {
+					hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+			}
+		}
+	}
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	if (!(test1 & SYNC_ERRDY_EN)) {
+		if (drive->select.b.unit & 0x01) {
+			pci_read_config_byte(dev, drive_pci - 4, &test2);
+			if ((test2 & SYNC_ERRDY_EN) &&
+			    !(test1 & SYNC_ERRDY_EN)) {
+				pci_write_config_byte(dev, drive_pci,
+					test1|SYNC_ERRDY_EN);
+			}
+		} else {
+			pci_write_config_byte(dev, drive_pci,
+				test1|SYNC_ERRDY_EN);
+		}
+	}
+
+chipset_is_set:
+
+	if (drive->media == ide_disk) {
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (id->capability & 4)	/* IORDY_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (drive->media == ide_disk)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+	}
+
+	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+	if (!(speed)) {
+		/* restore original pci-config space */
+		pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		struct request *rq	= HWGROUP(drive)->rq;
+		ide_hwif_t *hwif	= HWIF(drive);
+//		struct pci_dev *dev	= hwif->pci_dev;
+//		unsgned long high_16	= pci_resource_start(dev, 4);
+		unsigned long high_16   = hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u32 word_count	= 0;
+		u8 clock = hwif->INB(high_16 + 0x11);
+
+		hwif->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;
+		hwif->OUTL(word_count, atapi_reg);
+	}
+	return __ide_dma_begin(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif	= HWIF(drive);
+//		unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+		unsigned long high_16	= hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock		= 0;
+
+		hwif->OUTL(0, atapi_reg); /* zero out extra */
+		clock = hwif->INB(high_16 + 0x11);
+		hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+	}
+	return __ide_dma_end(drive);
+}
+
+static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	struct pci_dev *dev	= hwif->pci_dev;
+//	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long high_16	= hwif->dma_master;
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8 sc1d			= hwif->INB((high_16 + 0x001d));
+
+	if (hwif->channel) {
+		if ((sc1d & 0x50) == 0x50)
+			goto somebody_else;
+		else if ((sc1d & 0x40) == 0x40)
+			return (dma_stat & 4) == 4;
+	} else {
+		if ((sc1d & 0x05) == 0x05)
+			goto somebody_else;
+		else if ((sc1d & 0x04) == 0x04)
+			return (dma_stat & 4) == 4;
+	}
+somebody_else:
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdc202xx_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdc202xx_reset_host(hwif);
+	pdc202xx_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * 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)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 sc1f			= hwif->INB(high_16|0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+	} else {
+		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	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(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		ide_pci_register_host_proc(&pdc202xx_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	/*
+	 * 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.
+	 */
+#if 0
+	if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+		unsigned long high_16	= pci_resource_start(dev, 4);
+		byte udma_speed_flag	= inb(high_16 + 0x001f);
+		outb(udma_speed_flag | 0x10, high_16 + 0x001f);
+		mdelay(100);
+		outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		mdelay(2000);	/* 2 seconds ?! */
+	}
+
+#endif
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc  = &config_chipset_for_pio;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		hwif->busproc   = &pdc202xx_tristate;
+		hwif->resetproc = &pdc202xx_reset;
+	}
+
+	hwif->speedproc = &pdc202xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		if (!(hwif->udma_four))
+			hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+		hwif->ide_dma_begin = &pdc202xx_old_ide_dma_begin;
+		hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+	} 
+	hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk(KERN_DEBUG "%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */	
+}
+
+static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+	if (hwif->channel) {
+		ide_setup_dma(hwif, dmabase, 8);
+		return;
+	}
+
+	udma_speed_flag	= hwif->INB((dmabase|0x1f));
+	primary_mode	= hwif->INB((dmabase|0x1a));
+	secondary_mode	= hwif->INB((dmabase|0x1b));
+	printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n", hwif->cds->name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+	if (!(udma_speed_flag & 1)) {
+		printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
+			hwif->cds->name, udma_speed_flag,
+			(udma_speed_flag|1));
+		hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+		printk("%sACTIVE\n",
+			(hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+	}
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			primary_mode, (primary_mode|1));
+		hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+	}
+
+	if (!(secondary_mode & 1)) {
+		printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			secondary_mode, (secondary_mode|1));
+		hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+		u8 irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		/* 0xbc */
+		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev,
+				(PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+			printk(KERN_INFO "%s: pci-config space interrupt "
+				"mirror fixed.\n", d->name);
+		}
+	}
+
+#if 0
+        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+
+#if 0
+        {
+                u8 pri = 0, sec = 0;
+
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202xx_init_one	-	called when a PDC202xx is found
+ *	@dev: the pdc202xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise Old IDE",
+	.id_table	= pdc202xx_pci_tbl,
+	.probe		= pdc202xx_init_one,
+};
+
+static int pdc202xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202xx_ide_init);
+module_exit(pdc202xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.h linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_old.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/pdc202xx_old.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,326 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc;
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
+	{
+		.name		= "pdc202xx",
+		.set		= 1,
+		.get_info	= pdc202xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d);
+static void init_setup_pdc20265(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc202xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdc202xx(struct pci_dev *, const char *);
+static void init_hwif_pdc202xx(ide_hwif_t *);
+static void init_dma_pdc202xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20246,
+		.name		= "PDC20246",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 16,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20262,
+		.name		= "PDC20262",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20263,
+		.name		= "PDC20263",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20265,
+		.name		= "PDC20265",
+		.init_setup	= init_setup_pdc20265,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20267,
+		.name		= "PDC20267",
+		.init_setup	= init_setup_pdc202xx,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.c linux-2.4.21-rc3/drivers/ide/pci/piix.c
--- linux-2.4.20/drivers/ide/pci/piix.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/piix.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,842 @@
+/*
+ *  linux/drivers/ide/pci/piix.c	Version 0.42	January 11, 2003
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ *
+ *    ata-33/82371AB
+ *    ata-33/82371EB
+ *    ata-33/82801AB            ata-66/82801AA
+ *    00|00 udma 0              00|00 reserved
+ *    01|01 udma 1              01|01 udma 3
+ *    10|10 udma 2              10|10 udma 4
+ *    11|11 reserved            11|11 reserved
+ *
+ * 54 8421|8421    ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ * Documentation
+ *	Publically available from Intel web site. Errata documentation
+ * is also publically available. As an aide to anyone hacking on this
+ * driver the list of errata that are relevant is below.going back to
+ * PIIX4. Older device documentation is now a bit tricky to find.
+ *
+ * Errata of note:
+ *
+ * Unfixable
+ *	PIIX4    errata #9	- Only on ultra obscure hw
+ *	ICH3	 errata #13     - Not observed to affect real hw
+ *				  by Intel
+ *
+ * Things we must deal with
+ *	PIIX4	errata #10	- BM IDE hang with non UDMA
+ *				  (must stop/start dma to recover)
+ *	440MX   errata #15	- As PIIX4 errata #10
+ *	PIIX4	errata #15	- Must not read control registers
+ * 				  during a PIO transfer
+ *	440MX   errata #13	- As PIIX4 errata #15
+ *	ICH2	errata #21	- DMA mode 0 doesn't work right
+ *	ICH0/1  errata #55	- As ICH2 errata #21
+ *	ICH2	spec c #9	- Extra operations needed to handle
+ *				  drive hotswap [NOT YET SUPPORTED]
+ *	ICH2    spec c #20	- IDE PRD must not cross a 64K boundary
+ *				  and must be dword aligned
+ *	ICH2    spec c #24	- UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ *
+ * Should have been BIOS fixed:
+ *	450NX:	errata #19	- DMA hangs on old 450NX
+ *	450NX:  errata #20	- DMA hangs on old 450NX
+ *	450NX:  errata #25	- Corruption with DMA on old 450NX
+ *	ICH3    errata #15      - IDE deadlock under high load
+ *				  (BIOS must set dev 31 fn 0 bit 23)
+ *	ICH3	errata #18	- Don't use native mode
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "piix.h"
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc = 0;
+#define PIIX_MAX_DEVS		5
+static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
+static int n_piix_devs;
+static int no_piix_dma = 0;
+
+/**
+ *	piix_get_info		-	fill in /proc for PIIX ide
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the PIIX devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_piix_devs; i++) {
+		struct pci_dev *dev	= piix_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+	        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+		u8  c0 = 0, c1 = 0, reg54 = 0, reg55 = 0;
+		u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "\n                                Intel ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_INTEL_82801EB_1:
+				p += sprintf(p, "PIIX4 SATA 150 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82801BA_8:
+			case PCI_DEVICE_ID_INTEL_82801BA_9:
+			case PCI_DEVICE_ID_INTEL_82801CA_10:
+			case PCI_DEVICE_ID_INTEL_82801CA_11:
+			case PCI_DEVICE_ID_INTEL_82801DB_10:
+			case PCI_DEVICE_ID_INTEL_82801DB_11:
+			case PCI_DEVICE_ID_INTEL_82801EB_11:
+			case PCI_DEVICE_ID_INTEL_82801E_11:
+				p += sprintf(p, "PIIX4 Ultra 100 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82372FB_1:
+			case PCI_DEVICE_ID_INTEL_82801AA_1:
+				p += sprintf(p, "PIIX4 Ultra 66 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82451NX:
+			case PCI_DEVICE_ID_INTEL_82801AB_1:
+			case PCI_DEVICE_ID_INTEL_82443MX_1:
+			case PCI_DEVICE_ID_INTEL_82371AB:
+				p += sprintf(p, "PIIX4 Ultra 33 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371SB_1:
+				p += sprintf(p, "PIIX3 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371MX:
+				p += sprintf(p, "MPIIX ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371FB_1:
+			case PCI_DEVICE_ID_INTEL_82371FB_0:
+			default:
+				p += sprintf(p, "PIIX ");
+				break;
+		}
+		p += sprintf(p, "Chipset.\n");
+
+		if (dev->device == PCI_DEVICE_ID_INTEL_82371MX)
+			continue;
+
+		pci_read_config_word(dev, 0x40, &reg40);
+		pci_read_config_word(dev, 0x42, &reg42);
+		pci_read_config_byte(dev, 0x44, &reg44);
+		pci_read_config_byte(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x4a, &reg4a);
+		pci_read_config_byte(dev, 0x4b, &reg4b);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_byte(dev, 0x55, &reg55);
+
+		psitre = (reg40 & 0x4000) ? 1 : 0;
+		ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb(bibma + 0x02);
+		c1 = inb(bibma + 0x0a);
+
+		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 enabled:   %s              %s "
+				"            %s               %s\n",
+				(reg48&0x01) ? "yes" : "no ",
+				(reg48&0x02) ? "yes" : "no ",
+				(reg48&0x04) ? "yes" : "no ",
+				(reg48&0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s "
+				"              %s                 %s\n",
+				((reg54&0x11) &&
+				 (reg55&0x10) && (reg4a&0x01)) ? "5" :
+				((reg54&0x11) && (reg4a&0x02)) ? "4" :
+				((reg54&0x11) && (reg4a&0x01)) ? "3" :
+				(reg4a&0x02) ? "2" :
+				(reg4a&0x01) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x22) &&
+				 (reg55&0x20) && (reg4a&0x10)) ? "5" :
+				((reg54&0x22) && (reg4a&0x20)) ? "4" :
+				((reg54&0x22) && (reg4a&0x10)) ? "3" :
+				(reg4a&0x20) ? "2" :
+				(reg4a&0x10) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x44) &&
+				 (reg55&0x40) && (reg4b&0x03)) ? "5" :
+				((reg54&0x44) && (reg4b&0x02)) ? "4" :
+				((reg54&0x44) && (reg4b&0x01)) ? "3" :
+				(reg4b&0x02) ? "2" :
+				(reg4b&0x01) ? "1" :
+				(reg4b&0x00) ? "0" : "X",
+				((reg54&0x88) &&
+				 (reg55&0x80) && (reg4b&0x30)) ? "5" :
+				((reg54&0x88) && (reg4b&0x20)) ? "4" :
+				((reg54&0x88) && (reg4b&0x10)) ? "3" :
+				(reg4b&0x20) ? "2" :
+				(reg4b&0x10) ? "1" :
+				(reg4b&0x00) ? "0" : "X");
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+
+		/*
+		 * FIXME.... Add configuration junk data....blah blah......
+		 */
+	}
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	piix_ratemask		-	compute rate mask for PIIX IDE
+ *	@drive: IDE drive to compute for
+ *
+ *	Returns the available modes for the PIIX IDE controller.
+ */
+ 
+static u8 piix_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801EB_1:
+			mode = 3;
+			break;
+		/* UDMA 100 capable */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_10:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		case PCI_DEVICE_ID_INTEL_82801EB_11:
+			mode = 3;
+			break;
+		/* UDMA 66 capable */
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+			mode = 2;
+			break;
+		/* UDMA 33 capable */
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			return 1;
+		/* Non UDMA capable (MWDMA2) */
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		default:
+			return 0;
+	}
+	
+	/*
+	 *	If we are UDMA66 capable fall back to UDMA33 
+	 *	if the drive cannot see an 80pin cable.
+	 */
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	piix_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+ 
+static u8 piix_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/**
+ *	piix_tune_drive		-	tune a drive attached to a PIIX
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode based upon  the settings done by AMI BIOS
+ *	(might be useful if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ *	piix_tune_chipset	-	tune a PIIX interface
+ *	@drive: IDE drive to tune
+ *	@xferspeed: speed to configure
+ *
+ *	Set a PIIX interface channel to the desired speeds. This involves
+ *	requires the right timing data into the PIIX configuration space
+ *	then setting the drive parameters appropriately
+ */
+ 
+static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed		= ide_rate_filter(piix_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg44, reg48, reg4a, reg54;
+	u8			reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if (!(reg4a & u_speed)) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag)) {
+				pci_write_config_word(dev, 0x54, reg54|v_flag);
+			}
+		} else {
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/**
+ *	piix_faulty_dma0		-	check for DMA0 errata
+ *	@hwif: IDE interface to check
+ *
+ *	If an ICH/ICH0/ICH2 interface is is operating in multi-word
+ *	DMA mode with 600nS cycle time the IDE PIO prefetch buffer will
+ *	inadvertently provide an extra piece of secondary data to the primary
+ *	device resulting in data corruption.
+ *
+ *	With such a device this test function returns true. This allows
+ *	our tuning code to follow Intel recommendations and use PIO on
+ *	such devices.
+ */
+ 
+static int piix_faulty_dma0(ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device)
+	{
+		case PCI_DEVICE_ID_INTEL_82801AA_1:	/* ICH */
+		case PCI_DEVICE_ID_INTEL_82801AB_1:	/* ICH0 */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:	/* ICH2 */
+		case PCI_DEVICE_ID_INTEL_82801BA_9:	/* ICH2 */
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ *	piix_config_drive_for_dma	-	configure drive for DMA
+ *	@drive: IDE drive to configure
+ *
+ *	Set up a PIIX interface channel for the best available speed.
+ *	We prefer UDMA if it is available and then MWDMA. If DMA is 
+ *	not available we switch to PIO and return 0. 
+ */
+ 
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
+	
+	/* Some ICH devices cannot support DMA mode 0 */
+	if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive)))
+		speed = 0;
+
+	/* If no DMA speed was available or the chipset has DMA bugs
+	   then disable DMA and use PIO */
+	   
+	if (!speed || no_piix_dma) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) piix_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	piix_config_drive_xfer_rate	-	set up an IDE device
+ *	@drive: IDE drive to configure
+ *
+ *	Set up the PIIX interface for the best available speed on this
+ *	interface, preferring DMA to PIO.
+ */
+ 
+static int piix_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				if ((id->field_valid & 2) &&
+				    (!piix_config_drive_for_dma(drive)))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!piix_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!piix_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	init_chipset_piix	-	set up the PIIX chipset
+ *	@dev: PCI device to set up
+ *	@name: Name of the device
+ *
+ *	Initialize the PCI device as required. For the PIIX this turns
+ *	out to be nice and simple
+ */
+ 
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+        switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801EB_1:
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_10:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		case PCI_DEVICE_ID_INTEL_82801EB_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		{
+			unsigned int extra = 0;
+			pci_read_config_dword(dev, 0x54, &extra);
+			pci_write_config_dword(dev, 0x54, extra|0x400);
+		}
+		default:
+			break;
+	}
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	piix_devs[n_piix_devs++] = dev;
+
+	if (!piix_proc) {
+		piix_proc = 1;
+		ide_pci_register_host_proc(&piix_procs[0]);
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/**
+ *	init_hwif_piix		-	fill in the hwif for the PIIX
+ *	@hwif: IDE interface
+ *
+ *	Set up the ide_hwif_t for the PIIX interface according to the
+ *	capabilities of the hardware.
+ */
+ 
+static void __init init_hwif_piix (ide_hwif_t *hwif)
+{
+	u8 reg54h = 0, reg55h = 0, ata66 = 0;
+	u8 mask = hwif->channel ? 0xc0 : 0x30;
+
+#ifndef CONFIG_IA64
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+		/* This is a painful system best to let it self tune for now */
+		return;
+	}
+
+	hwif->autodma = 0;
+	hwif->tuneproc = &piix_tune_drive;
+	hwif->speedproc = &piix_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82371MX:
+			hwif->mwdma_mask = 0x80;
+			hwif->swdma_mask = 0x80;
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+			hwif->ultra_mask = 0x80;
+			break;
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			hwif->ultra_mask = 0x07;
+			break;
+		default:
+			pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+			pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
+			ata66 = (reg54h & mask) ? 1 : 0;
+			break;
+	}
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+	hwif->ide_dma_check = &piix_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_piix		-	set up the PIIX DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA PCI base
+ *
+ *	Set up the DMA on the PIIX controller, providing a DMA base is
+ *	available. The PIIX follows the normal specs so we do nothing
+ *	magical here.
+ */
+
+static void __init init_dma_piix (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	init_setup_piix		-	callback for IDE initialize
+ *	@dev: PIIX PCI device
+ *	@d: IDE pci info
+ *
+ *	Enable the xp fixup for the PIIX controller and then perform
+ *	a standard ide PCI setup
+ */
+ 
+static void __init init_setup_piix (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	piix_init_one	-	called when a PIIX is found
+ *	@dev: the piix device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &piix_pci_info[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	piix_check_450nx	-	Check for problem 450NX setup
+ *	
+ *	Check for the present of 450NX errata #19 and errata #25. If
+ *	they are found, disable use of DMA IDE
+ */
+ 
+static void __init piix_check_450nx(void)
+{
+	struct pci_dev *pdev = NULL;
+	u16 cfg;
+	u8 rev;
+	while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+	{
+		/* Look for 450NX PXB. Check for problem configurations
+		   A PCI quirk checks bit 6 already */
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+		pci_read_config_word(pdev, 0x41, &cfg);
+		/* Only on the original revision: IDE DMA can hang */
+		if(rev == 0x00)
+			no_piix_dma = 1;
+		/* On all revisions PXB bus lock must be disabled for IDE */
+		else if(cfg & (1<<14))
+			no_piix_dma = 2;
+	}
+	if(no_piix_dma)
+		printk(KERN_WARNING "piix: 450NX errata present, disabling IDE DMA.\n");
+	if(no_piix_dma == 2)
+		printk(KERN_WARNING "piix: A BIOS update may resolve this.\n");
+}		
+
+static struct pci_device_id piix_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+ 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PIIX IDE",
+	.id_table	= piix_pci_tbl,
+	.probe		= piix_init_one,
+};
+
+static int piix_ide_init(void)
+{
+	piix_check_450nx();
+	return ide_pci_register_driver(&driver);
+}
+
+static void piix_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(piix_ide_init);
+module_exit(piix_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.h linux-2.4.21-rc3/drivers/ide/pci/piix.h
--- linux-2.4.20/drivers/ide/pci/piix.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/piix.h	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,317 @@
+#ifndef PIIX_H
+#define PIIX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define PIIX_DEBUG_DRIVE_INFO		0
+
+#define DISPLAY_PIIX_TIMINGS
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc;
+
+static int piix_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t piix_procs[] __devinitdata = {
+	{
+		.name		= "piix",
+		.set		= 1,
+		.get_info	= piix_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_piix(struct pci_dev *, ide_pci_device_t *);
+static unsigned int __devinit init_chipset_piix(struct pci_dev *, const char *);
+static void init_hwif_piix(ide_hwif_t *);
+static void init_dma_piix(ide_hwif_t *, unsigned long);
+
+
+/*
+ *	Table of the various PIIX capability blocks
+ *
+ */
+ 
+static ide_pci_device_t piix_pci_info[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_0,
+		.name		= "PIIXa",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_1,
+		.name		= "PIIXb",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371MX,
+		.name		= "MPIIX",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371SB_1,
+		.name		= "PIIX3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371AB,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AB_1,
+		.name		= "ICH0",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82443MX_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AA_1,
+		.name		= "ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82372FB_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 9 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82451NX,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 10 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_9,
+		.name		= "ICH2",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 11 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_8,
+		.name		= "ICH2M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 12 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_10,
+		.name		= "ICH3M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 13 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_11,
+		.name		= "ICH3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 14 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801DB_11,
+		.name		= "ICH4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 15 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801EB_11,
+		.name		= "ICH5",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 16 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801E_11,
+		.name		= "C-ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 17 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801DB_10,
+		.name		= "ICH4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 18 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801EB_1,
+		.name		= "ICH5-SATA",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.init_setup	= NULL,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PIIX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.c linux-2.4.21-rc3/drivers/ide/pci/rz1000.c
--- linux-2.4.20/drivers/ide/pci/rz1000.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/rz1000.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ *  linux/drivers/ide/pci/rz1000.c	Version 0.06	January 12, 2003
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author:  mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for disabling the buggy read-ahead
+ *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ *  Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "rz1000.h"
+
+static void __init init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+	u16 reg;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->chipset = ide_rz1000;
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+		printk(KERN_INFO "%s: disabled chipset read-ahead "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	} else {
+		hwif->serialized = 1;
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk(KERN_INFO "%s: serialized, disabled unmasking "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	}
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &rz1000_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id rz1000_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "RZ1000 IDE",
+	.id_table	= rz1000_pci_tbl,
+	.probe		= rz1000_init_one,
+};
+
+static int rz1000_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void rz1000_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(rz1000_ide_init);
+module_exit(rz1000_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.h linux-2.4.21-rc3/drivers/ide/pci/rz1000.h
--- linux-2.4.20/drivers/ide/pci/rz1000.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/rz1000.h	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef RZ100X_H
+#define RZ100X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_rz1000(ide_hwif_t *);
+
+static ide_pci_device_t rz1000_chipsets[] __devinitdata = {
+{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1000,
+		.name		= "RZ1000",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1001,
+		.name		= "RZ1001",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* RZ100X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.c linux-2.4.21-rc3/drivers/ide/pci/sc1200.c
--- linux-2.4.20/drivers/ide/pci/sc1200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sc1200.c	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,598 @@
+/*
+ * linux/drivers/ide/pci/sc1200.c		Version 0.91	28-Jan-2003
+ *
+ * Copyright (C) 2000-2002		Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ *	Available from National Semiconductor
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sc1200.h"
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sc1200_get_info(char *, char **, off_t, int);
+extern int (*sc1200_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static u8 sc1200_proc = 0;
+
+#define SC1200_REV_A	0x00
+#define SC1200_REV_B1	0x01
+#define SC1200_REV_B3	0x02
+#define SC1200_REV_C1	0x03
+#define SC1200_REV_D1	0x04
+
+#define PCI_CLK_33	0x00
+#define PCI_CLK_48	0x01
+#define PCI_CLK_66	0x02
+#define PCI_CLK_33A	0x03
+
+static unsigned short sc1200_get_pci_clock (void)
+{
+	unsigned char chip_id, silicon_revision;
+	unsigned int pci_clock;
+	/*
+	 * Check the silicon revision, as not all versions of the chip
+	 * have the register with the fast PCI bus timings.
+	 */
+	chip_id = inb (0x903c);
+	silicon_revision = inb (0x903d);
+
+	// Read the fast pci clock frequency
+	if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
+		pci_clock = PCI_CLK_33;
+	} else {
+		// check clock generator configuration (cfcc)
+		// the clock is in bits 8 and 9 of this word
+
+		pci_clock = inw (0x901e);
+		pci_clock >>= 8;
+		pci_clock &= 0x03;
+		if (pci_clock == PCI_CLK_33A)
+			pci_clock = PCI_CLK_33;
+	}
+	return pci_clock;
+}
+
+static struct pci_dev *bmide_dev;
+
+static int sc1200_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	int len;
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "\n                               National SCx200 Chipset.\n");
+	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");
+
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * Set a new transfer mode at the drive
+ */
+int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
+{
+	printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+	return ide_config_drive_speed(drive, mode);
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static const unsigned int sc1200_pio_timings[4][5] =
+	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},	// format0  33Mhz
+	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010},	// format1, 33Mhz
+	 {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021},	// format1, 48Mhz
+	 {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}};	// format1, 66Mhz
+
+/*
+ * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
+ */
+//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
+
+static int sc1200_autoselect_dma_mode (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+
+	/*
+	 * The SC1200 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if ((mateid->capability & 1) && !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if ((id->capability & 1) && hwif->autodma && !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+	return mode;
+}
+
+/*
+ * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
+{
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	unsigned int		reg, timings;
+	unsigned short		pci_clock;
+	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);			/* turn off DMA while we fiddle */
+	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || sc1200_set_xfer_mode(drive, mode)) {
+		printk("SC1200: set xfer mode failure\n");
+		return 1;	/* failure */
+	}
+
+	pci_clock = sc1200_get_pci_clock();
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 *
+	 * Note that each DMA mode has several timings associated with it.
+	 * The correct timing depends on the fast PCI clock freq.
+	 */
+	timings = 0;
+	switch (mode) {
+		case XFER_UDMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00921250;	break;
+				case PCI_CLK_48:	timings = 0x00932470;	break;
+				case PCI_CLK_66:	timings = 0x009436a1;	break;
+			}
+			break;
+		case XFER_UDMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911140;	break;
+				case PCI_CLK_48:	timings = 0x00922260;	break;
+				case PCI_CLK_66:	timings = 0x00933481;	break;
+			}
+			break;
+		case XFER_UDMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911030;	break;
+				case PCI_CLK_48:	timings = 0x00922140;	break;
+				case PCI_CLK_66:	timings = 0x00923261;	break;
+			}
+			break;
+		case XFER_MW_DMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00077771;	break;
+				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
+				case PCI_CLK_66:	timings = 0x000ffff3;	break;
+			}
+			break;
+		case XFER_MW_DMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00012121;	break;
+				case PCI_CLK_48:	timings = 0x00024241;	break;
+				case PCI_CLK_66:	timings = 0x00035352;	break;
+			}
+			break;
+		case XFER_MW_DMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00002020;	break;
+				case PCI_CLK_48:	timings = 0x00013131;	break;
+				case PCI_CLK_66:	timings = 0x00015151;	break;
+			}
+			break;
+	}
+
+	if (timings == 0) {
+		printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock);
+		return 1;	/* failure */
+	}
+
+	if (unit == 0) {			/* are we configuring drive0? */
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+		timings |= reg & 0x80000000;	/* preserve PIO format bit */
+		pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
+	} else {
+		pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
+	}
+
+	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/*
+ * sc1200_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma (ide_drive_t *drive)
+{
+	return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive));
+}
+
+
+/*  Replacement for the standard ide_dma_end action in
+ *  dma_proc.
+ *
+ *  returns 1 on error, 0 otherwise
+ */
+int sc1200_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte dma_stat;
+
+	dma_stat = inb(dma_base+2);		/* get DMA status */
+
+	if (!(dma_stat & 4))
+		printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
+		  dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
+
+	outb(dma_stat|0x1b, dma_base+2);	/* clear the INTR & ERROR bits */
+	outb(inb(dma_base)&~1, dma_base);	/* !! DO THIS HERE !! stop DMA */
+
+	drive->waiting_for_dma = 0;
+	ide_destroy_dmatable(drive);		/* purge DMA mappings */
+
+	return (dma_stat & 7) != 4;		/* verify good DMA status */
+}
+
+/*
+ * sc1200_tuneproc() handles selection/setting of PIO modes
+ * for both the chipset and drive.
+ *
+ * All existing BIOSs for this chipset guarantee that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+static void sc1200_tuneproc (ide_drive_t *drive, byte pio)	/* mode=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+	int		mode = -1;
+
+	switch (pio) {
+		case 200: mode = XFER_UDMA_0;	break;
+		case 201: mode = XFER_UDMA_1;	break;
+		case 202: mode = XFER_UDMA_2;	break;
+		case 100: mode = XFER_MW_DMA_0;	break;
+		case 101: mode = XFER_MW_DMA_1;	break;
+		case 102: mode = XFER_MW_DMA_2;	break;
+	}
+	if (mode != -1) {
+		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
+		(void)sc1200_config_dma2(drive, mode);
+		return;
+	}
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
+	if (!sc1200_set_xfer_mode(drive, modes[pio])) {
+		unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+		pci_read_config_dword (hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]);
+ 	}
+}
+
+static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (prev) {
+			if (hwif == prev)
+				prev = NULL;	// found previous, now look for next match
+		} else {
+			if (hwif && hwif->pci_dev == dev)
+				return hwif;	// found next match
+		}
+	}
+	return NULL;	// not found
+}
+
+typedef struct sc1200_saved_state_s {
+	__u32		regs[4];
+} sc1200_saved_state_t;
+
+static int sc1200_save_state (struct pci_dev *dev, u32 state)
+{
+	ide_hwif_t		*hwif = NULL;
+
+printk("SC1200: save_state(%u)\n", state);
+	if (state != 0)
+		return 0;	// we only save state when going from full power to less
+	//
+	// Loop over all interfaces that are part of this PCI device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		sc1200_saved_state_t	*ss;
+		unsigned int		basereg, r;
+		//
+		// allocate a permanent save area, if not already allocated
+		//
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		if (ss == NULL) {
+			ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+			if (ss == NULL)
+				return -ENOMEM;
+			(sc1200_saved_state_t *)hwif->config_data = ss;
+		}
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		//
+		// Save timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		for (r = 0; r < 4; ++r) {
+			pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
+		}
+	}
+	return 0;
+}
+
+static int sc1200_suspend (struct pci_dev *dev, u32 state)
+{
+	printk("SC1200: suspend(%u)\n", state);
+	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+
+	pci_disable_device(dev);
+	pci_set_power_state(dev,state);
+	dev->current_state = state;
+	return 0;
+}
+
+static int sc1200_resume (struct pci_dev *dev)
+{
+	ide_hwif_t	*hwif = NULL;
+
+printk("SC1200: resume\n");
+	pci_set_power_state(dev,0);	// bring chip back from sleep state
+	dev->current_state = 0;
+	pci_enable_device(dev);
+	//
+	// loop over all interfaces that are part of this pci device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		unsigned int		basereg, r, d, format;
+		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
+printk("%s: SC1200: resume\n", hwif->name);
+
+		//
+		// Restore timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		if (ss != NULL) {
+			for (r = 0; r < 4; ++r) {
+				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
+			}
+		}
+		//
+		// Re-program drive PIO modes
+		//
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		for (d = 0; d < 2; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present) {
+				unsigned int pio, timings;
+				pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
+				for (pio = 0; pio <= 4; ++pio) {
+					if (sc1200_pio_timings[format][pio] == timings)
+						break;
+				}
+				if (pio > 4)
+					pio = 255; /* autotune */
+				(void)sc1200_tuneproc(drive, pio);
+			}
+		}
+		//
+		// Re-program drive DMA modes
+		//
+		for (d = 0; d < MAX_DRIVES; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present && !hwif->ide_dma_bad_drive(drive)) {
+				int was_using_dma = drive->using_dma;
+				hwif->ide_dma_off_quietly(drive);
+				sc1200_config_dma(drive);
+				if (!was_using_dma && drive->using_dma) {
+					hwif->ide_dma_off_quietly(drive);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Initialize the sc1200 bridge for reliable IDE DMA operation.
+ */
+static unsigned int __init init_chipset_sc1200 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!bmide_dev) {
+		sc1200_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&sc1200_procs[0]);
+	}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/*
+ * This gets invoked by the IDE driver once for each channel,
+ * and performs channel-specific pre-initialization before drive probing.
+ */
+static void __init init_hwif_sc1200 (ide_hwif_t *hwif)
+{
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+	hwif->autodma = 0;
+	if (hwif->dma_base) {
+		hwif->ide_dma_check = &sc1200_config_dma;
+		hwif->ide_dma_end   = &sc1200_ide_dma_end;
+        	if (!noautodma)
+                	hwif->autodma = 1;
+		hwif->tuneproc = &sc1200_tuneproc;
+	}
+        hwif->atapi_dma = 1;
+        hwif->ultra_mask = 0x07;
+        hwif->mwdma_mask = 0x07;
+
+        hwif->drives[0].autodma = hwif->autodma;
+        hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_sc1200 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sc1200_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sc1200_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SC1200 IDE",
+	.id_table	= sc1200_pci_tbl,
+	.probe		= sc1200_init_one,
+	.save_state	= sc1200_save_state,
+	.suspend	= sc1200_suspend,
+	.resume		= sc1200_resume,
+};
+
+static int sc1200_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sc1200_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sc1200_ide_init);
+module_exit(sc1200_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.h linux-2.4.21-rc3/drivers/ide/pci/sc1200.h
--- linux-2.4.20/drivers/ide/pci/sc1200.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sc1200.h	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SC1200_H
+#define SC1200_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sc1200_proc;
+
+static int sc1200_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sc1200_procs[] __initdata = {
+	{
+		name:		"sc1200",
+		set:		1,
+		get_info:	sc1200_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_sc1200(struct pci_dev *, const char *);
+static void init_hwif_sc1200(ide_hwif_t *);
+static void init_dma_sc1200(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sc1200_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_SCx200_IDE,
+		name:		"SC1200",
+		init_chipset:	init_chipset_sc1200,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_sc1200,
+		init_dma:	init_dma_sc1200,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SC1200_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.c linux-2.4.21-rc3/drivers/ide/pci/serverworks.c
--- linux-2.4.20/drivers/ide/pci/serverworks.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/serverworks.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,837 @@
+/*
+ * linux/drivers/ide/pci/serverworks.c		Version 0.8	 25 Ebr 2003
+ *
+ * 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
+ *
+ *
+ * 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. ***
+ *
+ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ * Documentation:
+ *	Available under NDA only. Errata info very hard to get.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "serverworks.h"
+
+static u8 svwks_revision = 0;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc = 0;
+#define SVWKS_MAX_DEVS		2
+static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
+static int n_svwks_devs;
+
+static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i, len;
+
+	p += sprintf(p, "\n                             "
+			"ServerWorks OSB4/CSB5/CSB6\n");
+
+	for (i = 0; i < n_svwks_devs; i++) {
+		struct pci_dev *dev = svwks_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u32 reg40, reg44;
+		u16 reg48, reg56;
+		u8  reg54, c0=0, c1=0;
+
+		pci_read_config_dword(dev, 0x40, &reg40);
+		pci_read_config_dword(dev, 0x44, &reg44);
+		pci_read_config_word(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_word(dev, 0x56, &reg56);
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p(bibma + 0x02);
+		c1 = inb_p(bibma + 0x0a);
+
+		p += sprintf(p, "\n                            ServerWorks ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+				p += sprintf(p, "CSB6 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				p += sprintf(p, "CSB5 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+				p += sprintf(p, "OSB4 ");
+				break;
+			default:
+				p += sprintf(p, "%04x ", dev->device);
+				break;
+		}
+		p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);
+
+		p += sprintf(p, "------------------------------- "
+				"General Status "
+				"---------------------------------\n");
+		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 enabled:   %s              %s"
+				"             %s               %s\n",
+			(reg54 & 0x01) ? "yes" : "no ",
+			(reg54 & 0x02) ? "yes" : "no ",
+			(reg54 & 0x04) ? "yes" : "no ",
+			(reg54 & 0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg56&0x0005)==0x0005)?"5":
+				((reg56&0x0004)==0x0004)?"4":
+				((reg56&0x0003)==0x0003)?"3":
+				((reg56&0x0002)==0x0002)?"2":
+				((reg56&0x0001)==0x0001)?"1":
+				((reg56&0x000F))?"?":"0",
+			((reg56&0x0050)==0x0050)?"5":
+				((reg56&0x0040)==0x0040)?"4":
+				((reg56&0x0030)==0x0030)?"3":
+				((reg56&0x0020)==0x0020)?"2":
+				((reg56&0x0010)==0x0010)?"1":
+				((reg56&0x00F0))?"?":"0",
+			((reg56&0x0500)==0x0500)?"5":
+				((reg56&0x0400)==0x0400)?"4":
+				((reg56&0x0300)==0x0300)?"3":
+				((reg56&0x0200)==0x0200)?"2":
+				((reg56&0x0100)==0x0100)?"1":
+				((reg56&0x0F00))?"?":"0",
+			((reg56&0x5000)==0x5000)?"5":
+				((reg56&0x4000)==0x4000)?"4":
+				((reg56&0x3000)==0x3000)?"3":
+				((reg56&0x2000)==0x2000)?"2":
+				((reg56&0x1000)==0x1000)?"1":
+				((reg56&0xF000))?"?":"0");
+		p += sprintf(p, "DMA enabled:    %s                %s"
+				"               %s                 %s\n",
+			((reg44&0x00002000)==0x00002000)?"2":
+				((reg44&0x00002100)==0x00002100)?"1":
+				((reg44&0x00007700)==0x00007700)?"0":
+				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
+			((reg44&0x00000020)==0x00000020)?"2":
+				((reg44&0x00000021)==0x00000021)?"1":
+				((reg44&0x00000077)==0x00000077)?"0":
+				((reg44&0x000000FF)==0x000000FF)?"X":"?",
+			((reg44&0x20000000)==0x20000000)?"2":
+				((reg44&0x21000000)==0x21000000)?"1":
+				((reg44&0x77000000)==0x77000000)?"0":
+				((reg44&0xFF000000)==0xFF000000)?"X":"?",
+			((reg44&0x00200000)==0x00200000)?"2":
+				((reg44&0x00210000)==0x00210000)?"1":
+				((reg44&0x00770000)==0x00770000)?"0":
+				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+
+		p += sprintf(p, "PIO  enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg40&0x00002000)==0x00002000)?"4":
+				((reg40&0x00002200)==0x00002200)?"3":
+				((reg40&0x00003400)==0x00003400)?"2":
+				((reg40&0x00004700)==0x00004700)?"1":
+				((reg40&0x00005D00)==0x00005D00)?"0":"?",
+			((reg40&0x00000020)==0x00000020)?"4":
+				((reg40&0x00000022)==0x00000022)?"3":
+				((reg40&0x00000034)==0x00000034)?"2":
+				((reg40&0x00000047)==0x00000047)?"1":
+				((reg40&0x0000005D)==0x0000005D)?"0":"?",
+			((reg40&0x20000000)==0x20000000)?"4":
+				((reg40&0x22000000)==0x22000000)?"3":
+				((reg40&0x34000000)==0x34000000)?"2":
+				((reg40&0x47000000)==0x47000000)?"1":
+				((reg40&0x5D000000)==0x5D000000)?"0":"?",
+			((reg40&0x00200000)==0x00200000)?"4":
+				((reg40&0x00220000)==0x00220000)?"3":
+				((reg40&0x00340000)==0x00340000)?"2":
+				((reg40&0x00470000)==0x00470000)?"1":
+				((reg40&0x005D0000)==0x005D0000)?"0":"?");
+
+	}
+	p += sprintf(p, "\n");
+
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	while (*list)
+		if (!strcmp(*list++, drive->id->model))
+			return 1;
+	return 0;
+}
+
+static u8 svwks_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev     = HWIF(drive)->pci_dev;
+	u8 mode;
+
+	if (!svwks_revision)
+		pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		u32 reg = 0;
+		if (isa_dev)
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			
+		/*
+		 *	Don't enable UDMA on disk devices for the moment
+		 */
+		if(drive->media == ide_disk)
+			return 0;
+		/* Check the OSB4 DMA33 enable bit */
+		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+		return 1;
+	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+		u8 btr = 0;
+		pci_read_config_byte(dev, 0x5A, &btr);
+		mode = btr & 0x3;
+		if (!eighty_ninty_three(drive))
+			mode = min(mode, (u8)1);
+		/* If someone decides to do UDMA133 on CSB5 the same 
+		   issue will bite so be inclusive */
+		if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
+			mode = 2;
+	}
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		mode = 2;
+	return mode;
+}
+
+static u8 svwks_csb_check (struct pci_dev *dev)
+{
+	switch (dev->device) {
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+	u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
+	u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
+	u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= ide_rate_filter(svwks_ratemask(drive), xferspeed);
+	u8 pio			= ide_get_best_pio_mode(drive, 255, 5, NULL);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 csb5			= svwks_csb_check(dev);
+	u8 ultra_enable		= 0, ultra_timing = 0;
+	u8 dma_timing		= 0, pio_timing = 0;
+	u16 csb5_pio		= 0;
+
+	/* If we are about to put a disk into UDMA mode we screwed up.
+	   Our code assumes we never _ever_ do this on an OSB4 */
+	   
+	if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
+		drive->media == ide_disk && speed >= XFER_UDMA_0)
+			BUG();
+			
+	pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+	pci_read_config_word(dev, 0x4A, &csb5_pio);
+	pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+		if (!drive->init_speed) {
+			u8 dma_stat = hwif->INB(hwif->dma_status);
+
+dma_pio:
+			if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
+			    ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
+				drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
+				return 0;
+			} else if ((dma_timing) &&
+				   ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
+				u8 dmaspeed = dma_timing;
+
+				dma_timing &= ~0xFF;
+				if ((dmaspeed & 0x20) == 0x20)
+					dmaspeed = XFER_MW_DMA_2;
+				else if ((dmaspeed & 0x21) == 0x21)
+					dmaspeed = XFER_MW_DMA_1;
+				else if ((dmaspeed & 0x77) == 0x77)
+					dmaspeed = XFER_MW_DMA_0;
+				else
+					goto dma_pio;
+				drive->current_speed = drive->init_speed = dmaspeed;
+				return 0;
+			} else if (pio_timing) {
+				u8 piospeed = pio_timing;
+
+				pio_timing &= ~0xFF;
+				if ((piospeed & 0x20) == 0x20)
+					piospeed = XFER_PIO_4;
+				else if ((piospeed & 0x22) == 0x22)
+					piospeed = XFER_PIO_3;
+				else if ((piospeed & 0x34) == 0x34)
+					piospeed = XFER_PIO_2;
+				else if ((piospeed & 0x47) == 0x47)
+					piospeed = XFER_PIO_1;
+				else if ((piospeed & 0x5d) == 0x5d)
+					piospeed = XFER_PIO_0;
+				else
+					goto oem_setup_failed;
+				drive->current_speed = drive->init_speed = piospeed;
+				return 0;
+			}
+		}
+	}
+
+oem_setup_failed:
+
+	pio_timing	&= ~0xFF;
+	dma_timing	&= ~0xFF;
+	ultra_timing	&= ~(0x0F << (4*unit));
+	ultra_enable	&= ~(0x01 << drive->dn);
+	csb5_pio	&= ~(0x0F << (4*drive->dn));
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pio_timing |= pio_modes[speed - XFER_PIO_0];
+			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
+			break;
+
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			pio_timing |= pio_modes[pio];
+			csb5_pio   |= (pio << (4*drive->dn));
+			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+			break;
+
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		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];
+			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+			ultra_enable |= (0x01 << drive->dn);
+		default:
+			break;
+	}
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
+	if (csb5)
+		pci_write_config_word(dev, 0x4A, csb5_pio);
+
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+	pci_write_config_byte(dev, 0x54, ultra_enable);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+	u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+	u8 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)
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	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;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+	drive->current_speed = speed;
+}
+
+static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	if(pio == 255)
+		(void) svwks_tune_chipset(drive, 255);
+	else
+		(void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+
+	if (!(speed))
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	(void) svwks_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto no_dma_set;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive);
+		//	hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* This can go soon */
+
+static int svwks_ide_dma_end (ide_drive_t *drive)
+{
+	return __ide_dma_end(drive);
+}
+
+static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
+{
+	unsigned int reg;
+	u8 btr;
+
+	/* save revision id to determine DMA capability */
+	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+	/* 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 */
+			if(!(reg & 0x00004000))
+				printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name);
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
+
+	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+//		u32 pioreg = 0, dmareg = 0;
+
+		/* Third Channel Test */
+		if (!(PCI_FUNC(dev->devfn) & 1)) {
+#if 1
+			struct pci_dev * findev = NULL;
+			u32 reg4c = 0;
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+			if (findev) {
+				pci_read_config_dword(findev, 0x4C, &reg4c);
+				reg4c &= ~0x000007FF;
+				reg4c |=  0x00000040;
+				reg4c |=  0x00000020;
+				pci_write_config_dword(findev, 0x4C, reg4c);
+			}
+#endif
+			outb_p(0x06, 0x0c00);
+			dev->irq = inb_p(0x0c01);
+#if 0
+			/* WE need to figure out how to get the correct one */
+			printk("%s: interrupt %d\n", name, dev->irq);
+			if (dev->irq != 0x0B)
+				dev->irq = 0x0B;
+#endif
+#if 0
+			printk("%s: device class (0x%04x)\n",
+				name, dev->class);
+#else
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				dev->class &= ~0x000F0F00;
+		//		dev->class |= ~0x00000400;
+				dev->class |= ~0x00010100;
+				/**/
+			}
+#endif
+		} else {
+			struct pci_dev * findev = NULL;
+			u8 reg41 = 0;
+
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+					PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+			if (findev) {
+				pci_read_config_byte(findev, 0x41, &reg41);
+				reg41 &= ~0x40;
+				pci_write_config_byte(findev, 0x41, reg41);
+			}
+			/*
+			 * This is a device pin issue on CSB6.
+			 * Since there will be a future raid mode,
+			 * early versions of the chipset require the
+			 * interrupt pin to be set, and it is a compatibility
+			 * mode issue.
+			 */
+			dev->irq = 0;
+		}
+//		pci_read_config_dword(dev, 0x40, &pioreg)
+//		pci_write_config_dword(dev, 0x40, 0x99999999);
+//		pci_read_config_dword(dev, 0x44, &dmareg);
+//		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
+		/* 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;
+		if (!(PCI_FUNC(dev->devfn) & 1))
+			btr |= 0x2;
+		else
+			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
+	}
+
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+	svwks_devs[n_svwks_devs++] = dev;
+
+	if (!svwks_proc) {
+		svwks_proc = 1;
+		ide_pci_register_host_proc(&svwks_procs[0]);
+	}
+#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+
+	return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+	return 1;
+}
+
+/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
+ * of the subsystem device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set   = secondary IDE channel has 80-pin cable.
+ * 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 ||
+	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+		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;
+}
+
+static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+		return 1;
+
+	/* Server Works */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+		return ata66_svwks_svwks (hwif);
+	
+	/* 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;
+}
+
+#undef CAN_SW_DMA
+static void __init init_hwif_svwks (ide_hwif_t *hwif)
+{
+	u8 dma_stat = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &svwks_tune_drive;
+	hwif->speedproc = &svwks_tune_chipset;
+
+	hwif->atapi_dma = 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ultra_mask = 0x3f;
+
+	hwif->mwdma_mask = 0x07;
+#ifdef CAN_SW_DMA
+	hwif->swdma_mask = 0x07;
+#endif /* CAN_SW_DMA */
+
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ide_dma_end = &svwks_ide_dma_end;
+	else if (!(hwif->udma_four))
+		hwif->udma_four = ata66_svwks(hwif);
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	dma_stat = hwif->INB(hwif->dma_status);
+	hwif->drives[0].autodma = (dma_stat & 0x20);
+	hwif->drives[1].autodma = (dma_stat & 0x40);
+	hwif->drives[0].autotune = (!(dma_stat & 0x20));
+	hwif->drives[1].autotune = (!(dma_stat & 0x40));
+//	hwif->drives[0].autodma = hwif->autodma;
+//	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+		return;
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if (!(PCI_FUNC(dev->devfn) & 1)) {
+		d->bootable = NEVER_BOARD;
+		if (dev->resource[0].start == 0x01f1)
+			d->bootable = ON_BOARD;
+	} else {
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+			return;
+	}
+#if 0
+	if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+             (!(PCI_FUNC(dev->devfn) & 1)))
+		d->autodma = AUTODMA;
+#endif
+
+	d->channels = (((d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+			(d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+		       (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	svwks_init_one	-	called when a OSB/CSB is found
+ *	@dev: the svwks device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id svwks_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Serverworks IDE",
+	.id_table	= svwks_pci_tbl,
+	.probe		= svwks_init_one,
+#if 0	/* FIXME: implement */
+	.suspend	= ,
+	.resume		= ,
+#endif
+};
+
+static int svwks_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void svwks_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(svwks_ide_init);
+module_exit(svwks_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.h linux-2.4.21-rc3/drivers/ide/pci/serverworks.h
--- linux-2.4.20/drivers/ide/pci/serverworks.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/serverworks.h	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,115 @@
+
+#ifndef SERVERWORKS_H
+#define SERVERWORKS_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef SVWKS_DEBUG_DRIVE_INFO
+
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
+ * can overrun their FIFOs when used with the CSB5 */
+const char *svwks_bad_ata100[] = {
+	"ST320011A",
+	"ST340016A",
+	"ST360021A",
+	"ST380021A",
+	NULL
+};
+
+#define DISPLAY_SVWKS_TIMINGS	1
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc;
+
+static int svwks_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t svwks_procs[] __initdata = {
+{
+		.name		= "svwks",
+		.set		= 1,
+		.get_info	= svwks_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_svwks(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_csb6(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_svwks(struct pci_dev *, const char *);
+static void init_hwif_svwks(ide_hwif_t *);
+static void init_dma_svwks(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		.name		= "SvrWks OSB4",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		.name		= "SvrWks CSB5",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 1,	/* 2 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SERVERWORKS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.c linux-2.4.21-rc3/drivers/ide/pci/siimage.c
--- linux-2.4.20/drivers/ide/pci/siimage.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/siimage.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,916 @@
+/*
+ * linux/drivers/ide/pci/siimage.c		Version 1.02	Jan 30, 2003
+ *
+ * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003		Red Hat <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "siimage.h"
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 siimage_proc = 0;
+#define SIIMAGE_MAX_DEVS		16
+static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];
+static int n_siimage_devs;
+
+static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p		= buf;
+	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;
+	unsigned long bmdma	= (mmio) ? ((unsigned long) pci_get_drvdata(dev)) :
+				    (pci_resource_start(dev, 4));
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
+	if (mmio)
+		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);
+
+	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 (char *)p;
+}
+
+static int siimage_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int len;
+	u16 i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_siimage_devs; i++) {
+		struct pci_dev *dev	= siimage_devs[i];
+		p = print_siimage_get_info(p, dev, i);
+	}
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+
+#endif	/* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	siimage_ratemask	-	Compute available modes
+ *	@drive: IDE drive
+ *
+ *	Compute the available speeds for the devices on the interface.
+ *	For the CMD680 this depends on the clocking mode (scsc), for the
+ *	SI3312 SATA controller life is a bit simpler. Enforce UDMA33
+ *	as a limit if there is no 80pin cable present.
+ */
+ 
+static byte siimage_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode	= 0, scsc = 0;
+
+	if (hwif->mmio)
+		scsc = hwif->INB(HWIFADDR(0x4A));
+	else
+		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_SII_3112:
+			return 4;
+		case PCI_DEVICE_ID_SII_680:
+			if ((scsc & 0x30) == 0x10)	/* 133 */
+				mode = 4;
+			else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
+				mode = 4;
+			else if ((scsc & 0x30) == 0x00)	/* 100 */
+				mode = 3;
+			else 	/* Disabled ? */
+				BUG();
+			break;
+		default:	return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static byte siimage_taskfile_timing (ide_hwif_t *hwif)
+{
+	u16 timing	= 0x328a;
+
+	if (hwif->mmio)
+		timing = hwif->INW(SELADDR(2));
+	else
+		pci_read_config_word(hwif->pci_dev, SELREG(2), &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+/**
+ *	simmage_tuneproc	-	tune a drive
+ *	@drive: drive to tune
+ *	@mode_wanted: the target operating mode
+ *
+ *	Load the timing settings for this device mode into the
+ *	controller
+ */
+ 
+static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 speedt		= 0;
+	u8 unit			= drive->select.b.unit;
+
+	if (hwif->mmio)
+		speedt = hwif->INW(SELADDR(0x04|(unit<<unit)));
+	else
+		pci_read_config_word(dev, SELADDR(0x04|(unit<<unit)), &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(siimage_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;
+	}
+	if (hwif->mmio)
+		hwif->OUTW(speedt, SELADDR(0x04|(unit<<unit)));
+	else
+		pci_write_config_word(dev, SELADDR(0x04|(unit<<unit)), speedt);
+}
+
+static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
+	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	/* 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;
+
+	siimage_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	config_siimage_chipset_for_pio(drive, set_speed);
+}
+
+static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 ultra = 0, multi	= 0;
+	u8 mode = 0, unit	= drive->select.b.unit;
+	u8 speed	= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
+				    ((hwif->mmio) ? 0xF4 : 0x84) :
+				    ((hwif->mmio) ? 0xB4 : 0x80));
+
+	if (hwif->mmio) {
+		scsc = hwif->INB(HWIFADDR(0x4A));
+		mode = hwif->INB(HWIFADDR(addr_mask));
+		multi = hwif->INW(SELADDR(0x08|(unit<<unit)));
+		ultra = hwif->INW(SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), &multi);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), &ultra);
+	}
+
+	mode &= ~((unit) ? 0x30 : 0x03);
+	ultra &= ~0x3F;
+	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+	scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc;
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			siimage_tuneproc(drive, (speed - XFER_PIO_0));
+			mode |= ((unit) ? 0x10 : 0x01);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			multi = dma[speed - XFER_MW_DMA_0];
+			mode |= ((unit) ? 0x20 : 0x02);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			multi = dma[2];
+			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
+					   (ultra5[speed - XFER_UDMA_0]));
+			mode |= ((unit) ? 0x30 : 0x03);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		default:
+			return 1;
+	}
+
+	if (hwif->mmio) {
+		hwif->OUTB(mode, HWIFADDR(addr_mask));
+		hwif->OUTW(multi, SELADDR(0x08|(unit<<unit)));
+		hwif->OUTW(ultra, SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), multi);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), ultra);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
+
+	config_chipset_for_pio(drive, !speed);
+
+	if (!speed)
+		return 0;
+
+	if (ide_set_xfer_rate(drive, speed))
+		return 0;
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int siimage_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id->capability & 1) != 0 && drive->autodma) {
+		if (!(hwif->atapi_dma))
+			goto fast_ata_pio;
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if ((id->field_valid & 4) && siimage_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_altstat		= 0;
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 4) == 4)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat);
+	if (dma_altstat & 8)
+		return 0;	//return 1;
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
+{
+#ifdef SIIMAGE_VIRTUAL_DMAPIO
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 count		= (rq->nr_sectors * SECTOR_SIZE);
+	u32 rcount		= 0;
+
+	hwif->OUTL(count, SELADDR(0x1C));
+	rcount = hwif->INL(SELADDR(0x1C));
+
+	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
+		drive->name, count, rcount, rq->nr_sectors);
+
+#endif /* SIIMAGE_VIRTUAL_DMAPIO */
+	return __ide_dma_count(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (SATA_ERROR_REG) {
+		u32 ext_stat = hwif->INL(HWIFADDR(0x10));
+		u8 watchdog = 0;
+		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+			u32 sata_error = hwif->INL(SATA_ERROR_REG);
+			hwif->OUTL(sata_error, SATA_ERROR_REG);
+			watchdog = (sata_error & 0x00680000) ? 1 : 0;
+#if 1
+			printk(KERN_WARNING "%s: sata_error = 0x%08x, "
+				"watchdog = %d, %s\n",
+				drive->name, sata_error, watchdog,
+				__FUNCTION__);
+#endif
+
+		} else {
+			watchdog = (ext_stat & 0x8000) ? 1 : 0;
+		}
+		ext_stat >>= 16;
+
+		if (!(ext_stat & 0x0404) && !watchdog)
+			return 0;
+	}
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((hwif->INB(SELADDR(1)) & 8) == 8)
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive)
+{
+	int temp = __ide_dma_verbose(drive);
+#if 0
+	drive->using_dma = 0;
+#endif
+	return temp;
+}
+
+/**
+ *	siimage_busproc		-	bus isolation ioctl
+ *	@drive: drive to isolate/restore
+ *	@state: bus state to set
+ *
+ *	Used by the SII3112 to handle bus isolation. As this is a 
+ *	SATA controller the work required is quite limited, we 
+ *	just have to clean up the statistics
+ */
+ 
+static int siimage_busproc (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 stat_config		= 0;
+
+	if (hwif->mmio) {
+		stat_config = hwif->INL(SELADDR(0));
+	} else
+		pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config);
+
+	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 -EINVAL;
+	}
+	hwif->bus_state = state;
+	return 0;
+}
+
+static int siimage_reset_poll (ide_drive_t *drive)
+{
+	if (SATA_STATUS_REG) {
+		ide_hwif_t *hwif	= HWIF(drive);
+
+		if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+			printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+				hwif->name, hwif->INL(SATA_STATUS_REG));
+			HWGROUP(drive)->poll_timeout = 0;
+			return ide_started;
+		}
+		return 0;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ *	siimage_pre_reset	-	reset hook
+ *	@drive: IDE device being reset
+ *
+ *	For the SATA devices we need to handle recalibration/geometry
+ *	differently
+ */
+ 
+static void siimage_pre_reset (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		drive->special.b.set_geometry = 0;
+		drive->special.b.recalibrate = 0;
+	}
+}
+
+/**
+ *	siimage_reset	-	reset a device on an siimage controller
+ *	@drive: drive to reset
+ *
+ *	Perform a controller level reset fo the device. For
+ *	SATA we must also check the PHY.
+ */
+ 
+static void siimage_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 reset		= 0;
+
+	if (hwif->mmio) {
+		reset = hwif->INB(SELADDR(0));
+		hwif->OUTB((reset|0x03), SELADDR(0));
+		udelay(25);
+		hwif->OUTB(reset, SELADDR(0));
+		(void) hwif->INB(SELADDR(0));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03);
+		udelay(25);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset);
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+	}
+
+	if (SATA_STATUS_REG) {
+		u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+		printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n",
+			hwif->name, sata_stat, __FUNCTION__);
+		if (!(sata_stat)) {
+			printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+				hwif->name, sata_stat);
+			drive->failures++;
+		}
+	}
+
+}
+
+/**
+ *	proc_reports_siimage		-	add siimage controller to proc
+ *	@dev: PCI device
+ *	@clocking: SCSC value
+ *	@name: controller name
+ *
+ *	Report the clocking mode of the controller and add it to
+ *	the /proc interface layer
+ */
+ 
+static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_SII_3112)
+		goto sata_skip;
+
+	printk(KERN_INFO "%s: BASE CLOCK ", name);
+	clocking &= ~0x03;
+	switch(clocking) {
+		case 0x03: printk("DISABLED !\n"); break;
+		case 0x02: printk("== 2X PCI \n"); break;
+		case 0x01: printk("== 133 \n"); break;
+		case 0x00: printk("== 100 \n"); break;
+	}
+
+sata_skip:
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+	siimage_devs[n_siimage_devs++] = dev;
+
+	if (!siimage_proc) {
+		siimage_proc = 1;
+		ide_pci_register_host_proc(&siimage_procs[0]);
+	}
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */
+}
+
+static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+{
+	unsigned long bar5	= pci_resource_start(dev, 5);
+	unsigned long end5	= pci_resource_end(dev, 5);
+	u8 tmpbyte	= 0;
+	unsigned long addr;
+	void *ioaddr;
+
+	/*
+	 *	Drop back to PIO if we can't map the mmio. Some
+	 *	systems seem to get terminally confused in the PCI
+	 *	spaces.
+	 */
+	 
+	if(check_mem_region(bar5, (end5-bar5)+1)!=0)
+	{
+		printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n");
+		return 0;
+	}
+		
+	ioaddr = ioremap_nocache(bar5, (end5 - bar5)+1);
+
+	if (ioaddr == NULL)
+		return 0;
+
+	pci_set_master(dev);
+	pci_set_drvdata(dev, ioaddr);
+	addr = (unsigned long) ioaddr;
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		writel(0, DEVADDR(0x148));
+		writel(0, DEVADDR(0x1C8));
+	}
+
+	writeb(0, DEVADDR(0xB4));
+	writeb(0, DEVADDR(0xF4));
+	tmpbyte = readb(DEVADDR(0x4A));
+
+	switch(tmpbyte & 0x30) {
+		case 0x00:
+			/* In 100 MHz clocking, try and switch to 133 */
+			writeb(tmpbyte|0x10, DEVADDR(0x4A));
+			break;
+		case 0x10:
+			/* On 133Mhz clocking */
+			break;
+		case 0x20:
+			/* On PCIx2 clocking */
+			break;
+		case 0x30:
+			/* Clocking is disabled */
+			/* 133 clock attempt to force it on */
+			writeb(tmpbyte & ~0x20, DEVADDR(0x4A));
+			break;
+	}
+	
+	writeb(0x72, DEVADDR(0xA1));
+	writew(0x328A, DEVADDR(0xA2));
+	writel(0x62DD62DD, DEVADDR(0xA4));
+	writel(0x43924392, DEVADDR(0xA8));
+	writel(0x40094009, DEVADDR(0xAC));
+	writeb(0x72, DEVADDR(0xE1));
+	writew(0x328A, DEVADDR(0xE2));
+	writel(0x62DD62DD, DEVADDR(0xE4));
+	writel(0x43924392, DEVADDR(0xE8));
+	writel(0x40094009, DEVADDR(0xEC));
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		writel(0xFFFF0000, DEVADDR(0x108));
+		writel(0xFFFF0000, DEVADDR(0x188));
+		writel(0x00680000, DEVADDR(0x148));
+		writel(0x00680000, DEVADDR(0x1C8));
+	}
+
+	tmpbyte = readb(DEVADDR(0x4A));
+
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 1;
+}
+
+static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev	= 0;
+	u8 tmpbyte	= 0;
+	u8 BA5_EN	= 0;
+
+        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+        class_rev &= 0xff;
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);	
+
+	pci_read_config_byte(dev, 0x8A, &BA5_EN);
+	if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
+		if (setup_mmio_siimage(dev, name)) {
+			return 0;
+		}
+	}
+
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	switch(tmpbyte & 0x30) {
+		case 0x00:
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
+		case 0x30:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
+		case 0x10:
+			/* 133 already */
+			break;
+		case 0x20:
+			/* BIOS set PCI x2 clocking */
+			break;
+	}
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0xA1, 0x72);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xA8, 0x43924392);
+	pci_write_config_dword(dev, 0xAC, 0x40094009);
+	pci_write_config_byte(dev, 0xB1, 0x72);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xB8, 0x43924392);
+	pci_write_config_dword(dev, 0xBC, 0x40094009);
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 0;
+}
+
+static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long addr	= (unsigned long) pci_get_drvdata(hwif->pci_dev);
+	u8 ch			= hwif->channel;
+//	u16 i			= 0;
+	hw_regs_t hw;
+
+	default_hwif_mmiops(hwif);
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+#if 1
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xD0 : 0x90);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xD1 : 0x91);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xD2 : 0x92);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xD3 : 0x93);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xD4 : 0x94);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xD5 : 0x95);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xD6 : 0x96);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xD7 : 0x97);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xC0 : 0x80);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xC1 : 0x81);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xC2 : 0x82);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xC3 : 0x83);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xC4 : 0x84);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xC5 : 0x85);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xC6 : 0x86);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xC7 : 0x87);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#else
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#endif
+
+#if 0
+	printk(KERN_DEBUG "%s: ", hwif->name);
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i));
+	printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i));
+#endif
+
+	hw.io_ports[IDE_IRQ_OFFSET]	= 0;
+
+        if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		hw.sata_scr[SATA_STATUS_OFFSET]	= DEVADDR((ch) ? 0x184 : 0x104);
+		hw.sata_scr[SATA_ERROR_OFFSET]	= DEVADDR((ch) ? 0x188 : 0x108);
+		hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100);
+		hw.sata_misc[SATA_MISC_OFFSET]	= DEVADDR((ch) ? 0x1C0 : 0x140);
+		hw.sata_misc[SATA_PHY_OFFSET]	= DEVADDR((ch) ? 0x1C4 : 0x144);
+		hw.sata_misc[SATA_IEN_OFFSET]	= DEVADDR((ch) ? 0x1C8 : 0x148);
+	}
+
+	hw.priv				= (void *) addr;
+//	hw.priv				= pci_get_drvdata(hwif->pci_dev);
+	hw.irq				= hwif->pci_dev->irq;
+
+	memcpy(&hwif->hw, &hw, sizeof(hw));
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr));
+		memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc));
+	}
+
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+        hwif->addressing = 1;
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+	hwif->irq			= hw.irq;
+	hwif->hwif_data			= pci_get_drvdata(hwif->pci_dev);
+
+#ifdef SIIMAGE_LARGE_DMA
+	hwif->dma_base			= DEVADDR((ch) ? 0x18 : 0x10);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_prdtable		= (hwif->dma_base2 + 4);
+#else /* ! SIIMAGE_LARGE_DMA */
+	hwif->dma_base			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x18 : 0x10);
+#endif /* SIIMAGE_LARGE_DMA */
+	hwif->mmio			= 1;
+}
+
+static void __init init_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 class_rev		= 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->rqsize = 128;
+	if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev)))
+		hwif->rqsize = 16;
+
+	if (pci_get_drvdata(dev) == NULL)
+		return;
+	init_mmio_iops_siimage(hwif);
+}
+
+static unsigned int __init ata66_siimage (ide_hwif_t *hwif)
+{
+	if (pci_get_drvdata(hwif->pci_dev) == NULL) {
+		u8 ata66 = 0;
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66);
+		return (ata66 & 0x01) ? 1 : 0;
+	}
+
+	return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0;
+}
+
+static void __init init_hwif_siimage (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	
+	hwif->resetproc = &siimage_reset;
+	hwif->speedproc = &siimage_tune_chipset;
+	hwif->tuneproc	= &siimage_tuneproc;
+	hwif->reset_poll = &siimage_reset_poll;
+	hwif->pre_reset = &siimage_pre_reset;
+
+	if(hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112)
+		hwif->busproc   = &siimage_busproc;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112)
+		hwif->atapi_dma = 1;
+
+	hwif->ide_dma_check = &siimage_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_siimage(hwif);
+
+	if (hwif->mmio) {
+		hwif->ide_dma_count = &siimage_mmio_ide_dma_count;
+		hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
+		hwif->ide_dma_verbose = &siimage_mmio_ide_dma_verbose;
+	} else {
+		hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
+	}
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &siimage_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SiI IDE",
+	.id_table	= siimage_pci_tbl,
+	.probe		= siimage_init_one,
+};
+
+static int siimage_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void siimage_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(siimage_ide_init);
+module_exit(siimage_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.h linux-2.4.21-rc3/drivers/ide/pci/siimage.h
--- linux-2.4.20/drivers/ide/pci/siimage.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/siimage.h	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,96 @@
+#ifndef SIIMAGE_H
+#define SIIMAGE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_SIIMAGE_TIMINGS
+
+#undef SIIMAGE_VIRTUAL_DMAPIO
+#undef SIIMAGE_BUFFERED_TASKFILE
+#undef SIIMAGE_LARGE_DMA
+
+#if 0
+typedef struct ide_io_ops_s siimage_iops {
+
+}
+#endif
+
+#define SII_DEBUG 0
+
+#if SII_DEBUG
+#define siiprintk(x...)	printk(x)
+#else
+#define siiprintk(x...)
+#endif
+
+#define ADJREG(B,R)	((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio)))))
+#define SELREG(R)	ADJREG((0xA0),(R))
+#define SELADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
+#define HWIFADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|(R))
+#define DEVADDR(R)	(((unsigned long) pci_get_drvdata(dev))|(R))
+
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char * print_siimage_get_info(char *, struct pci_dev *, int);
+static int siimage_get_info(char *, char **, off_t, int);
+
+static u8 siimage_proc;
+
+static ide_pci_host_proc_t siimage_procs[] __initdata = {
+	{
+		.name		= "siimage",
+		.set		= 1,
+		.get_info	= siimage_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */	
+
+static unsigned int init_chipset_siimage(struct pci_dev *, const char *);
+static void init_iops_siimage(ide_hwif_t *);
+static void init_hwif_siimage(ide_hwif_t *);
+static void init_dma_siimage(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_680,
+		.name		= "SiI680",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_3112,
+		.name		= "SiI3112 Serial ATA",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIIMAGE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.c linux-2.4.21-rc3/drivers/ide/pci/sis5513.c
--- linux-2.4.20/drivers/ide/pci/sis5513.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sis5513.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,1107 @@
+/*
+ * linux/drivers/ide/pci/sis5513.c		Version 0.14ac	Sept 11, 2002
+ *
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt	:
+ *			  for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ *
+ * Documentation:
+ *	SiS chipset documentation available under NDA to companies not
+ *	individuals only.
+ */
+
+/*
+ * Notes/Special cases:
+ * - SiS5513 derivatives usually have the same PCI IDE register layout when
+ *  supporting the same UDMA modes.
+ * - There are exceptions :
+ *  . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support
+ *   ATA_100
+ *  . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously
+ *   south and northbridge were integrated, making IDE (a southbridge function)
+ *   capabilities easily deduced from the northbridge PCI id. With ATA_133,
+ *   chipsets started to be split in the usual north/south bridges chips
+ *   -> the driver needs to detect the correct southbridge when faced to newest
+ *   northbridges.
+ *  . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the
+ *   configuration space is moved from 0x40 to 0x70.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sis5513.h"
+
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */
+// #define DEBUG
+/* When BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
+
+/* Miscellaneous flags */
+#define SIS5513_LATENCY		0x01
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
+#define ATA_100		0x05
+#define ATA_133a	0x06 // SiS961b with 133 support
+#define ATA_133		0x07 // SiS962
+/* 2/ variable holding the controller chipset family value */
+static u8 chipset_family;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers fewer will be used
+ * Some odd chipsets hang if unused registers are accessed
+ * -> We only access them in #DEBUG code (then we'll see if SiS did
+ * it right from day one) */
+static u8 ide_regs_copy[0xff];
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	u8 reg_val;
+	u8 changed=0;
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%02x: %02x -> %02x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
+
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print config space registers a la "lspci -vxxx" */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i,j;
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+
+	for(i=0; i<=0xf; i++) {
+		printk("SIS5513 dump: %d" "0:", i);
+		for(j=0; j<=0xf; j++) {
+			printk(" %02x", ide_regs_copy[(i<<16)+j]);
+		}
+		printk("\n");
+	}
+}
+#endif
+
+
+/*
+ * Devices supported
+ */
+static const struct {
+	const char *name;
+	u16 host_id;
+	u8 chipset_family;
+	u8 flags;
+} SiSHostChipInfo[] = {
+	{ "SiS752",	PCI_DEVICE_ID_SI_752,	ATA_133,	0 },
+	{ "SiS751",	PCI_DEVICE_ID_SI_751,	ATA_133,	0 },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_133,	0 },
+	{ "SiS748",	PCI_DEVICE_ID_SI_748,	ATA_133,	0 },
+	{ "SiS746",	PCI_DEVICE_ID_SI_746,	ATA_133,	0 },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_133,	0 },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	0 },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
+	{ "SiS652",	PCI_DEVICE_ID_SI_652,	ATA_133,	0 },
+	{ "SiS651",	PCI_DEVICE_ID_SI_651,	ATA_133,	0 },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_133,	0 },
+	{ "SiS648",	PCI_DEVICE_ID_SI_648,	ATA_133,	0 },
+	{ "SiS646",	PCI_DEVICE_ID_SI_646,	ATA_133,	0 },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_133,	0 },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS550",	PCI_DEVICE_ID_SI_550,	ATA_100a,	0},
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
+};
+
+/* Cycle time bits and values vary across chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+
+/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
+static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
+static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
+static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0,0}, /* ATA_33 */
+	{7,5,3,2,1,0,0}, /* ATA_66 */
+	{7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
+	{11,7,5,4,2,1,0}, /* ATA_100 */
+	{15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
+	{15,10,7,5,3,2,1}, /* ATA_133 */
+};
+/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
+   See SiS962 data sheet for more detail */
+static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{2,1,1,0,0,0,0},
+	{4,3,2,1,0,0,0},
+	{4,3,2,1,0,0,0},
+	{6,4,3,1,1,1,0},
+	{9,6,4,2,2,2,2},
+	{9,6,4,2,2,2,2},
+};
+/* Initialize time, Active time, Recovery time vary across
+   IDE clock settings. These 3 arrays hold the register value
+   for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
+static u8 ini_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{2,1,0,0,0,1,0,0},
+	{4,3,1,1,1,3,1,1},
+	{4,3,1,1,1,3,1,1},
+	{6,4,2,2,2,4,2,2},
+	{9,6,3,3,3,6,3,3},
+	{9,6,3,3,3,6,3,3},
+};
+static u8 act_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,9,9,2,2,7,2,2},
+	{19,19,19,5,4,14,5,4},
+	{19,19,19,5,4,14,5,4},
+	{28,28,28,7,6,21,7,6},
+	{38,38,38,10,9,28,10,9},
+	{38,38,38,10,9,28,10,9},
+};
+static u8 rco_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,2,0,2,0,7,1,1},
+	{19,5,1,5,2,16,3,2},
+	{19,5,1,5,2,16,3,2},
+	{30,9,3,9,4,25,6,4},
+	{40,12,4,12,5,34,12,5},
+	{40,12,4,12,5,34,12,5},
+};
+
+static struct pci_dev *host_dev = NULL;
+
+/*
+ * Printing configuration
+ */
+/* Used for chipset type printing at boot time */
+static char* chipset_capability[] = {
+	"ATA", "ATA 16",
+	"ATA 33", "ATA 66",
+	"ATA 100", "ATA 100",
+	"ATA 133", "ATA 133"
+};
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char* recovery_time[] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"13 CLK", "14 CLK",
+	"15 CLK", "16 CLK"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, u8 pos)
+{
+	u8 reg00, reg01, reg10, reg11; /* timing registers */
+	u32 regdw0, regdw1;
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	if (chipset_family < ATA_133) {
+		pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+		p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+			     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+			     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+		pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+		pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+		pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+		pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+	} else {
+		u32 reg54h;
+		u8 drive_pci = 0x40;
+		pci_read_config_dword(bmide_dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) {
+			// Configuration space remapped to 0x70
+			drive_pci = 0x70;
+		}
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos, &regdw0);
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos+4, &regdw1);
+		p += sprintf(p, "Drive %d:\n", pos);
+	}
+
+
+/* UDMA */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (regdw0 & 0x04) ? "Enabled" : "Disabled",
+			     (regdw1 & 0x04) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+			     cycle_time[(regdw0 & 0xF0) >> 4],
+			     cycle_time[(regdw1 & 0xF0) >> 4]);
+	} else if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80) ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:  p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	if (chipset_family < ATA_133) {
+		p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+			     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+	}
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int len;
+	u8 reg;
+	u16 reg2, reg3;
+
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133a:
+		case ATA_133: p += sprintf(p, "Ultra 133"); break;
+		default: p+= sprintf(p, "Unknown???"); break;
+	}
+	p += sprintf(p, " chipset\n");
+	p += sprintf(p, "--------------- Primary Channel "
+		     "---------------- Secondary Channel "
+		     "-------------\n");
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	if (chipset_family == ATA_133) {
+		pci_read_config_word(bmide_dev, 0x50, &reg2);
+		pci_read_config_word(bmide_dev, 0x52, &reg3);
+	}
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else if (chipset_family < ATA_133) {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	} else { /* ATA_133 */
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg2 & 0x02) ? "On" : "Off",
+			     (reg3 & 0x02) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg2 & 0x01) ? cable_type[1] : cable_type[0],
+			     (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
+	} else if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
+
+/* Prefetch Count */
+	if (chipset_family < ATA_133) {
+		pci_read_config_word(bmide_dev, 0x4c, &reg2);
+		pci_read_config_word(bmide_dev, 0x4e, &reg3);
+		p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+			     reg2, reg3);
+	}
+
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
+
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 sis5513_ratemask (ide_drive_t *drive)
+{
+#if 0
+	u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
+	u8 mode = rates[chipset_family];
+#else
+	u8 mode;
+
+	switch(chipset_family) {
+		case ATA_133:
+		case ATA_133a:
+			mode = 4;
+			break;
+		case ATA_100:
+		case ATA_100a:
+			mode = 3;
+			break;
+		case ATA_66:
+			mode = 2;
+			break;
+		case ATA_33:
+			return 1;
+		case ATA_16:
+                case ATA_00:	
+		default:
+			return 0;
+	}
+#endif
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 reg4bh		= 0;
+	u8 rw_prefetch		= (0x11 << drive->dn);
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
+	if (drive->media != ide_disk)
+		return;
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+	if ((reg4bh & rw_prefetch) != rw_prefetch)
+		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
+}
+
+
+/* Set per-drive active and recovery time */
+static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8			timing, drive_pci, test1, test2;
+
+	u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
+	config_drive_art_rwp(drive);
+	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 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 {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, "
+		"drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
+
+	/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
+	drive_pci = 0x40;
+	/* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+	}
+
+	/* register layout changed with newer ATA100 chips */
+	if (chipset_family < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else if (chipset_family < ATA_133) {
+		switch(timing) { /*		active  recovery
+						  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+	} else { /* ATA_133 */
+		u32 test3;
+		pci_read_config_dword(dev, drive_pci, &test3);
+		test3 &= 0xc0c00fff;
+		if (test3 & 0x08) {
+			test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24;
+		} else {
+			test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24;
+		}
+		pci_write_config_dword(dev, drive_pci, test3);
+	}
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+#if 0
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, (XFER_PIO_0 + pio));
+#else
+	u8 speed;
+
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, speed);
+#endif
+}
+
+static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 drive_pci, reg, speed;
+	u32 regdw;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+#endif
+
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL);
+#endif
+	if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
+#endif
+
+	speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+#ifdef DEBUG
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, xferspeed);
+#endif
+
+	/* See config_art_rwp_pio for drive pci config registers */
+	drive_pci = 0x40;
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+		pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if (speed < XFER_UDMA_0) {
+			regdw &= 0xfffffffb;
+			pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+		}
+	
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+		pci_read_config_byte(dev, drive_pci+1, &reg);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+			reg &= 0x7F;
+			pci_write_config_byte(dev, drive_pci+1, reg);
+		}
+	}
+
+	/* Config chip for mode */
+	switch(speed) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (chipset_family >= ATA_133) {
+				regdw |= 0x04;
+				regdw &= 0xfffff00f;
+				/* check if ATA133 enable */
+				if (regdw & 0x08) {
+					regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8;
+				} else {
+				/* if ATA133 disable, we should not set speed above UDMA5 */
+					if (speed > XFER_UDMA_5)
+						speed = XFER_UDMA_5;
+					regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8;
+				}
+				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+			} else {
+				/* Force the UDMA bit on if we want to use UDMA */
+				reg |= 0x80;
+				/* clean reg cycle time bits */
+				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+					 << cycle_time_offset[chipset_family]);
+				/* set reg cycle time bits */
+				reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+					<< cycle_time_offset[chipset_family];
+				pci_write_config_byte(dev, drive_pci+1, reg);
+			}
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			break;
+		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+		case XFER_PIO_0:
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
+
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
+	       drive->dn, drive->id->dma_ultra);
+#endif
+
+	if (!(speed))
+		return 0;
+
+	sis5513_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		sis5513_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+	config_drive_art_rwp(drive);
+	config_art_rwp_pio(drive, 5);
+	return sis5513_config_drive_xfer_rate(drive);
+}
+
+/* Chip detection and general config */
+static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *host;
+	int i = 0;
+
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_SI,
+					SiSHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
+	
+		/* check 100/133 chipset family */
+		if (chipset_family == ATA_133) {
+			u32 reg54h;
+			u16 reg02h;
+			pci_read_config_dword(dev, 0x54, &reg54h);
+			pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff));
+			pci_read_config_word(dev, 0x02, &reg02h);
+			pci_write_config_dword(dev, 0x54, reg54h);
+			/* devid 5518 here means SiS962 or later
+			   which supports ATA133 */
+			if (reg02h != 0x5518) {
+				u8 reg49h;
+				unsigned long sbrev;
+				/* SiS961 family */
+
+		/*
+		 * FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING 
+		 */
+				outl(0x80001008, 0x0cf8);
+				sbrev = inl(0x0cfc);
+
+				pci_read_config_byte(dev, 0x49, &reg49h);
+				if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80))
+					chipset_family = ATA_133a;
+				else
+					chipset_family = ATA_100;
+			}
+		}
+		printk(SiSHostChipInfo[i].name);
+		printk("    %s controller", chipset_capability[chipset_family]);
+		printk("\n");
+
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+		}
+	}
+
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compatibility mode only
+	   2/ tell old chips to allow per drive IDE timings */
+	if (host_dev) {
+		u8 reg;
+		u16 regw;
+		switch(chipset_family) {
+			case ATA_133:
+				/* SiS962 operation mode */
+				pci_read_config_word(dev, 0x50, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x50, regw&0xfff7);
+				pci_read_config_word(dev, 0x52, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x52, regw&0xfff7);
+				break;
+			case ATA_133a:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_100a:
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
+		}
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		if (!sis_proc) {
+			sis_proc = 1;
+			bmide_dev = dev;
+			ide_pci_register_host_proc(&sis_procs[0]);
+		}
+#endif
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
+	return 0;
+}
+
+static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0;
+
+	if (chipset_family >= ATA_133) {
+		u16 regw = 0;
+		u16 reg_addr = hwif->channel ? 0x52: 0x50;
+		pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
+		ata66 = (regw & 0x8000) ? 0 : 1;
+	} else if (chipset_family >= ATA_66) {
+		u8 reg48h = 0;
+		u8 mask = hwif->channel ? 0x20 : 0x10;
+		pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+		ata66 = (reg48h & mask) ? 0 : 1;
+	}
+        return ata66;
+}
+
+static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &sis5513_tune_drive;
+	hwif->speedproc = &sis5513_tune_chipset;
+
+	if (!(hwif->dma_base)) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!host_dev)
+		return;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_sis5513(hwif);
+
+	if (chipset_family > ATA_16) {
+		hwif->ide_dma_check = &sis5513_config_xfer_rate;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+	return;
+}
+
+static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sis5513_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sis5513_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SIS IDE",
+	.id_table	= sis5513_pci_tbl,
+	.probe		= sis5513_init_one,
+};
+
+static int sis5513_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sis5513_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sis5513_ide_init);
+module_exit(sis5513_ide_exit);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
+ */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.h linux-2.4.21-rc3/drivers/ide/pci/sis5513.h
--- linux-2.4.20/drivers/ide/pci/sis5513.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sis5513.h	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SIS5513_H
+#define SIS5513_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SIS_TIMINGS
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc;
+
+static int sis_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sis_procs[] __initdata = {
+{
+		.name		= "sis",
+		.set		= 1,
+		.get_info	= sis_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
+static void init_hwif_sis5513(ide_hwif_t *);
+static void init_dma_sis5513(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sis5513_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_5513,
+		.name		= "SIS5513",
+		.init_chipset	= init_chipset_sis5513,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sis5513,
+		.init_dma	= init_dma_sis5513,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIS5513_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.c linux-2.4.21-rc3/drivers/ide/pci/sl82c105.c
--- linux-2.4.20/drivers/ide/pci/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sl82c105.c	2003-05-22 22:06:39.000000000 +0000
@@ -0,0 +1,539 @@
+/*
+ * linux/drivers/ide/pci/sl82c105.c
+ *
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Rebel.com's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
+ * 
+ * Merge in Russell's HW workarounds, fix various problems
+ * with the timing registers setup.
+ *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "ide_modes.h"
+#include "sl82c105.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(arg) printk arg
+#else
+#define DBG(fmt,...)
+#endif
+/*
+ * SL82C105 PCI config register 0x40 bits.
+ */
+#define CTRL_IDE_IRQB   (1 << 30)
+#define CTRL_IDE_IRQA   (1 << 28)
+#define CTRL_LEGIRQ     (1 << 11)
+#define CTRL_P1F16      (1 << 5)
+#define CTRL_P1EN       (1 << 4)
+#define CTRL_P0F16      (1 << 1)
+#define CTRL_P0EN       (1 << 0)
+
+/*
+ * Convert a PIO mode and cycle time to the required on/off
+ * times for the interface.  This has protection against run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+	unsigned int cmd_on;
+	unsigned int cmd_off;
+
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+	if (cmd_on > 32)
+		cmd_on = 32;
+	if (cmd_on == 0)
+		cmd_on = 1;
+
+	if (cmd_off > 32)
+		cmd_off = 32;
+	if (cmd_off == 0)
+		cmd_off = 1;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+}
+
+/*
+ * Configure the drive and chipset for PIO
+ */
+static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	ide_pio_data_t p;
+	u16 drv_ctrl = 0x909;
+	unsigned int xfer_mode, reg;
+
+	DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n",
+		drive->name, pio, report, chipset_only));
+		
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+	xfer_mode = XFER_PIO_0 + pio;
+
+	if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) {
+		drv_ctrl = get_timing_sl82c105(&p);
+		drive->pio_speed = xfer_mode;
+	} else
+		drive->pio_speed = XFER_PIO_0;
+
+	if (drive->using_dma == 0) {
+		/*
+		 * If we are actually using MW DMA, then we can not
+		 * reprogram the interface drive control register.
+		 */
+		pci_write_config_word(dev, reg, drv_ctrl);
+		pci_read_config_word(dev, reg, &drv_ctrl);
+
+		if (report) {
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+		}
+	}
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int reg;
+
+	DBG(("config_for_dma(drive:%s)\n", drive->name));
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0)
+		return 1;
+
+	pci_write_config_word(dev, reg, 0x0240);
+
+	return 0;
+}
+
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+
+static int sl82c105_check_drive (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	DBG(("sl82c105_check_drive(drive:%s)\n", drive->name));
+
+	do {
+		struct hd_driveid *id = drive->id;
+
+		if (!drive->autodma)
+			break;
+
+		if (!(id->capability & 1))
+			break;
+
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			break;
+
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask))
+				return hwif->ide_dma_on(drive);
+		}
+
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
+	} while (0);
+
+	return hwif->ide_dma_off_quietly(drive);
+}
+
+/*
+ * The SL82C105 holds off all IDE interrupts while in DMA mode until
+ * all DMA activity is completed.  Sometimes this causes problems (eg,
+ * when the drive wants to report an error condition).
+ *
+ * 0x7e is a "chip testing" register.  Bit 2 resets the DMA controller
+ * state machine.  We need to kick this to work around various bugs.
+ */
+static inline void sl82c105_reset_host(struct pci_dev *dev)
+{
+	u16 val;
+
+	pci_read_config_word(dev, 0x7e, &val);
+	pci_write_config_word(dev, 0x7e, val | (1 << 2));
+	pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
+}
+
+/*
+ * If we get an IRQ timeout, it might be that the DMA state machine
+ * got confused.  Fix from Todd Inglett.  Details from Winbond.
+ *
+ * This function is called when the IDE timer expires, the drive
+ * indicates that it is READY, and we were waiting for DMA to complete.
+ */
+static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+	unsigned long dma_base = hwif->dma_base;
+
+	printk("sl82c105: lost IRQ: resetting host\n");
+
+	/*
+	 * Check the raw interrupt from the drive.
+	 */
+	pci_read_config_dword(dev, 0x40, &val);
+	if (val & mask)
+		printk("sl82c105: drive was requesting IRQ, but host lost it\n");
+
+	/*
+	 * Was DMA enabled?  If so, disable it - we're resetting the
+	 * host.  The IDE layer will be handling the drive for us.
+	 */
+	val = hwif->INB(dma_base);
+	if (val & 1) {
+		outb(val & ~1, dma_base);
+		printk("sl82c105: DMA was enabled\n");
+	}
+
+	sl82c105_reset_host(dev);
+
+	/* ide_dmaproc would return 1, so we do as well */
+	return 1;
+}
+
+/*
+ * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
+ * Winbond recommend that the DMA state machine is reset prior to
+ * setting the bus master DMA enable bit.
+ *
+ * The generic IDE core will have disabled the BMEN bit before this
+ * function is called.
+ */
+static int sl82c105_ide_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+
+//	DBG(("sl82c105_ide_dma_begin(drive:%s)\n", drive->name));
+
+	sl82c105_reset_host(dev);
+	return __ide_dma_begin(drive);
+}
+
+static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+
+	DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
+
+	sl82c105_reset_host(dev);
+	return __ide_dma_timeout(drive);
+}
+
+static int sl82c105_ide_dma_on (ide_drive_t *drive)
+{
+	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
+
+	if (config_for_dma(drive)) {
+		config_for_pio(drive, 4, 0, 0);
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	}
+	printk(KERN_INFO "%s: DMA enabled\n", drive->name);
+	return __ide_dma_on(drive);
+}
+
+static int sl82c105_ide_dma_off (ide_drive_t *drive)
+{
+	u8 speed = XFER_PIO_0;
+	int rc;
+	
+	DBG(("sl82c105_ide_dma_off(drive:%s)\n", drive->name));
+
+	rc = __ide_dma_off(drive);
+	if (drive->pio_speed)
+		speed = drive->pio_speed - XFER_PIO_0;
+	config_for_pio(drive, speed, 0, 1);
+	drive->current_speed = drive->pio_speed;
+
+	return rc;
+}
+
+static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+{
+	u8 speed = XFER_PIO_0;
+	int rc;
+	
+	DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name));
+
+	rc = __ide_dma_off_quietly(drive);
+	if (drive->pio_speed)
+		speed = drive->pio_speed - XFER_PIO_0;
+	config_for_pio(drive, speed, 0, 1);
+	drive->current_speed = drive->pio_speed;
+
+	return rc;
+}
+
+/*
+ * Ok, that is nasty, but we must make sure the DMA timings
+ * won't be used for a PIO access. The solution here is
+ * to make sure the 16 bits mode is diabled on the channel
+ * when DMA is enabled, thus causing the chip to use PIO0
+ * timings for those operations.
+ */
+static void sl82c105_selectproc(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val, old, mask;
+
+	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
+
+	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
+	old = val = *((u32 *)&hwif->hwif_data);
+	if (drive->using_dma)
+		val &= ~mask;
+	else
+		val |= mask;
+	if (old != val) {
+		pci_write_config_dword(dev, 0x40, val);	
+		*((u32 *)&hwif->hwif_data) = val;
+	}
+}
+
+/*
+ * ATA reset will clear the 16 bits mode in the control
+ * register, we need to update our cache
+ */
+static void sl82c105_resetproc(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val;
+
+	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
+
+	pci_read_config_dword(dev, 0x40, &val);
+	*((u32 *)&hwif->hwif_data) = val;
+}
+	
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+{
+	DBG(("tune_sl82c105(drive:%s)\n", drive->name));
+
+	config_for_pio(drive, pio, 1, 0);
+
+	/*
+	 * We support 32-bit I/O on this interface, and it
+	 * doesn't have problems with interrupts.
+	 */
+	drive->io_32bit = 1;
+	drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+	struct pci_dev *bridge;
+	u8 rev;
+
+	/*
+	 * The bridge should be part of the same device, but function 0.
+	 */
+	bridge = pci_find_slot(dev->bus->number,
+			       PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
+	if (!bridge)
+		return -1;
+
+	/*
+	 * Make sure it is a Winbond 553 and is an ISA bridge.
+	 */
+	if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
+	    bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
+	    bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+		return -1;
+
+	/*
+	 * We need to find function 0's revision, not function 1
+	 */
+	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+	return rev;
+}
+
+/*
+ * Enable the PCI device
+ * 
+ * --BenH: It's arch fixup code that should enable channels that
+ * have not been enabled by firmware. I decided we can still enable
+ * channel 0 here at least, but channel 1 has to be enabled by
+ * firmware or arch code. We still set both to 16 bits mode.
+ */
+static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	u32 val;
+
+	DBG(("init_chipset_sl82c105()\n"));
+
+	pci_read_config_dword(dev, 0x40, &val);
+	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+	pci_write_config_dword(dev, 0x40, val);
+
+	return dev->irq;
+}
+
+static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	unsigned int rev;
+	u8 dma_state;
+
+	DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
+
+	hwif->autodma = 0;
+
+	if (!dma_base)
+		return;
+
+	dma_state = hwif->INB(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+		       hwif->name, rev);
+		dma_state &= ~0x60;
+	} else {
+		dma_state |= 0x60;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->OUTB(dma_state, dma_base + 2);
+
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+
+	ide_setup_dma(hwif, dma_base, 8);
+}
+
+/*
+ * Initialise the chip
+ */
+
+static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val;
+	
+	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
+
+	hwif->tuneproc = tune_sl82c105;
+	hwif->selectproc = sl82c105_selectproc;
+	hwif->resetproc = sl82c105_resetproc;
+	
+	/* Default to PIO 0 for fallback unless tuned otherwise,
+	 * we always autotune PIO, this is done before DMA is
+	 * checked, so there is no risk of accidentally disabling
+	 * DMA
+	  */
+	hwif->drives[0].pio_speed = XFER_PIO_0;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].pio_speed = XFER_PIO_0;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_dword(dev, 0x40, &val);
+	*((u32 *)&hwif->hwif_data) = val;
+	
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &sl82c105_check_drive;
+	hwif->ide_dma_on = &sl82c105_ide_dma_on;
+	hwif->ide_dma_off = &sl82c105_ide_dma_off;
+	hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+	hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+	hwif->ide_dma_begin = &sl82c105_ide_dma_begin;
+	hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sl82c105_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sl82c105_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "W82C105 IDE",
+	.id_table	= sl82c105_pci_tbl,
+	.probe		= sl82c105_init_one,
+};
+
+static int sl82c105_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sl82c105_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sl82c105_ide_init);
+module_exit(sl82c105_ide_exit);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.h linux-2.4.21-rc3/drivers/ide/pci/sl82c105.h
--- linux-2.4.20/drivers/ide/pci/sl82c105.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/sl82c105.h	2003-05-22 22:06:24.000000000 +0000
@@ -0,0 +1,34 @@
+#ifndef W82C105_H
+#define W82C105_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_sl82c105(struct pci_dev *, const char *);
+static void init_hwif_sl82c105(ide_hwif_t *);
+static void init_dma_sl82c105(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sl82c105_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_WINBOND,
+		.device		= PCI_DEVICE_ID_WINBOND_82C105,
+		.name		= "W82C105",
+		.init_chipset	= init_chipset_sl82c105,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sl82c105,
+		.init_dma	= init_dma_sl82c105,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* W82C105_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.c linux-2.4.21-rc3/drivers/ide/pci/slc90e66.c
--- linux-2.4.20/drivers/ide/pci/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/slc90e66.c	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,412 @@
+/*
+ *  linux/drivers/ide/pci/slc90e66.c	Version 0.11	September 11, 2002
+ *
+ *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "slc90e66.h"
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int len;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x47, &reg47);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "                                SLC90E66 Chipset.\n");
+	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 enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg4a&0x04)==0x04) ? "4" :
+			((reg4a&0x03)==0x03) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4a&0x40)==0x40) ? "4" :
+			((reg4a&0x30)==0x30) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4b&0x04)==0x04) ? "4" :
+			((reg4b&0x03)==0x03) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg4b&0x40)==0x40) ? "4" :
+			((reg4b&0x30)==0x30) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	/* p - buffer must be less than 4k! */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+	
+	return len > count ? count : len;
+}
+#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 slc90e66_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 2;
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed	= ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
+	int u_speed = 0, u_flag = 1 << drive->dn;
+	u16			reg4042, reg44, reg48, reg4a;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:        break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if ((reg4a & u_speed) != u_speed) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_read_config_word(dev, 0x4a, &reg4a);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) slc90e66_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = slc90e66_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!slc90e66_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!slc90e66_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_slc90e66 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!slc90e66_proc) {
+		slc90e66_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&slc90e66_procs[0]);
+	}
+#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+{
+	u8 reg47 = 0;
+	u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->speedproc = &slc90e66_tune_chipset;
+	hwif->tuneproc = &slc90e66_tune_drive;
+
+	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	if (!(hwif->udma_four))
+		/* bit[0(1)]: 0:80, 1:40 */
+		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+
+	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_slc90e66 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &slc90e66_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id slc90e66_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SLC90e66 IDE",
+	.id_table	= slc90e66_pci_tbl,
+	.probe		= slc90e66_init_one,
+};
+
+static int slc90e66_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void slc90e66_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(slc90e66_ide_init);
+module_exit(slc90e66_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.h linux-2.4.21-rc3/drivers/ide/pci/slc90e66.h
--- linux-2.4.20/drivers/ide/pci/slc90e66.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/slc90e66.h	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,56 @@
+#ifndef SLC90E66_H
+#define SLC90E66_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SLC90E66_TIMINGS
+
+#define SLC90E66_DEBUG_DRIVE_INFO	0
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc;
+
+static int slc90e66_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t slc90e66_procs[] __initdata = {
+	{
+		.name		= "slc90e66",
+		.set		= 1,
+		.get_info	= slc90e66_get_info,
+		.parent		= NULL,
+	},
+};
+#endif	/* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_slc90e66(struct pci_dev *, const char *);
+static void init_hwif_slc90e66(ide_hwif_t *);
+static void init_dma_slc90e66(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t slc90e66_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_EFAR,
+		.device		= PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		.name		= "SLC90E66",
+		.init_chipset	= init_chipset_slc90e66,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_slc90e66,
+		.init_dma	= init_dma_slc90e66,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SLC90E66_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/triflex.c linux-2.4.21-rc3/drivers/ide/pci/triflex.c
--- linux-2.4.20/drivers/ide/pci/triflex.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/triflex.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,256 @@
+/*
+ * triflex.c
+ * 
+ * IDE Chipset driver for the Compaq TriFlex IDE controller.
+ * 
+ * Known to work with the Compaq Workstation 5x00 series.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ *	Not publically available.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include "ide_modes.h"
+#include "triflex.h"
+
+static struct pci_dev *triflex_dev;
+
+static int triflex_get_info(char *buf, char **addr, off_t offset, int count)
+{
+	char *p = buf;
+	int len;
+
+	struct pci_dev *dev	= triflex_dev;
+	unsigned long bibma = pci_resource_start(dev, 4);
+	u8  c0 = 0, c1 = 0;
+	u32 pri_timing, sec_timing;
+
+	p += sprintf(p, "\n                                Compaq Triflex Chipset\n");
+	
+	pci_read_config_dword(dev, 0x70, &pri_timing);
+	pci_read_config_dword(dev, 0x74, &sec_timing);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	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, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	len = (p - buf) - offset;
+	*addr = buf + offset;
+	
+	return len > count ? count : len;
+}
+
+static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u8 channel_offset = hwif->channel ? 0x74 : 0x70;
+	u16 timing = 0;
+	u32 triflex_timings = 0;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 speed = ide_rate_filter(0, xferspeed);
+	
+	pci_read_config_dword(dev, channel_offset, &triflex_timings);
+	
+	switch(speed) {
+		case XFER_MW_DMA_2:
+			timing = 0x0103; 
+			break;
+		case XFER_MW_DMA_1:
+			timing = 0x0203;
+			break;
+		case XFER_MW_DMA_0:
+			timing = 0x0808;
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			timing = 0x0f0f;
+			break;
+		case XFER_PIO_4:
+			timing = 0x0202;
+			break;
+		case XFER_PIO_3:
+			timing = 0x0204;
+			break;
+		case XFER_PIO_2:
+			timing = 0x0404;
+			break;
+		case XFER_PIO_1:
+			timing = 0x0508;
+			break;
+		case XFER_PIO_0:
+			timing = 0x0808;
+			break;
+		default:
+			return -1;
+	}
+
+	triflex_timings &= ~(0xFFFF << (16 * unit));
+	triflex_timings |= (timing << (16 * unit));
+	
+	pci_write_config_dword(dev, channel_offset, triflex_timings);
+	
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
+}
+
+static int triflex_config_drive_for_dma(ide_drive_t *drive)
+{
+	int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
+
+	if (!speed) { 
+		u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = XFER_PIO_0 + pspeed;
+	}
+	
+	(void) triflex_tune_chipset(drive, speed);
+	 return ide_dma_enable(drive);
+}
+
+static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+	
+	if ((id->capability & 1) && drive->autodma) {
+		if (hwif->ide_dma_bad_drive(drive))
+			goto tune_pio;
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+				(id->dma_1word & hwif->swdma_mask)) {
+				if (!triflex_config_drive_for_dma(drive))
+					goto tune_pio;
+			}
+		} else 
+			goto tune_pio;
+	} else {
+tune_pio:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+	return hwif->ide_dma_on(drive);
+}
+
+static void __init init_hwif_triflex(ide_hwif_t *hwif)
+{
+	hwif->tuneproc = &triflex_tune_drive;
+	hwif->speedproc = &triflex_tune_chipset;
+
+	hwif->atapi_dma  = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+	hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
+	
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __init init_chipset_triflex(struct pci_dev *dev, 
+		const char *name) 
+{
+#ifdef CONFIG_PROC_FS
+	ide_pci_register_host_proc(&triflex_proc);
+#endif
+	return 0;	
+}
+
+static int __devinit triflex_init_one(struct pci_dev *dev, 
+		const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &triflex_devices[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	
+	ide_setup_pci_device(dev, d);
+	triflex_dev = dev;
+	MOD_INC_USE_COUNT;
+	
+	return 0;
+}
+
+static struct pci_driver driver = {
+	.name		= "TRIFLEX IDE",
+	.id_table	= triflex_pci_tbl,
+	.probe		= triflex_init_one,
+};
+
+static int triflex_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void triflex_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(triflex_ide_init);
+module_exit(triflex_ide_exit);
+
+MODULE_AUTHOR("Torben Mathiasen");
+MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
+MODULE_LICENSE("GPL");
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/triflex.h linux-2.4.21-rc3/drivers/ide/pci/triflex.h
--- linux-2.4.20/drivers/ide/pci/triflex.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/triflex.h	2003-05-22 22:06:26.000000000 +0000
@@ -0,0 +1,50 @@
+/* 
+ * triflex.h
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ */
+#ifndef TRIFLEX_H
+#define TRIFLEX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int __devinit init_chipset_triflex(struct pci_dev *, const char *);
+static void init_hwif_triflex(ide_hwif_t *);
+static int triflex_get_info(char *, char **, off_t, int);
+
+static ide_pci_device_t triflex_devices[] __devinitdata = {
+	{
+		.vendor 	= PCI_VENDOR_ID_COMPAQ,
+		.device		= PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+		.name		= "TRIFLEX",
+		.init_chipset	= init_chipset_triflex,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_triflex,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
+		.bootable	= ON_BOARD,
+	},{	
+		.bootable	= EOL,
+	}
+};
+
+#ifdef CONFIG_PROC_FS
+static ide_pci_host_proc_t triflex_proc __initdata = {
+	.name		= "triflex",
+	.set		= 1,
+	.get_info 	= triflex_get_info,
+};
+#endif
+
+static struct pci_device_id triflex_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, PCI_ANY_ID, 
+		PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+#endif /* TRIFLEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.c linux-2.4.21-rc3/drivers/ide/pci/trm290.c
--- linux-2.4.20/drivers/ide/pci/trm290.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/trm290.c	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,452 @@
+/*
+ *  linux/drivers/ide/pci/trm290.c		Version 1.02	Mar. 18, 2000
+ *
+ *  Copyright (c) 1997-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA function
+ * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
+ * including a "Precision Instruments" board.  The TRM290 pre-dates
+ * the sff-8038 standard (ide-dma.c) by a few months, and differs
+ * significantly enough to warrant separate routines for some functions,
+ * while re-using others from ide-dma.c.
+ *
+ * EXPERIMENTAL!  It works for me (a sample of one).
+ *
+ * Works reliably for me in DMA mode (READs only),
+ * DMA WRITEs are disabled by default (see #define below);
+ *
+ * DMA is not enabled automatically for this chipset,
+ * but can be turned on manually (with "hdparm -d1") at run time.
+ *
+ * I need volunteers with "spare" drives for further testing
+ * and development, and maybe to help figure out the peculiarities.
+ * Even knowing the registers (below), some things behave strangely.
+ */
+
+#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
+
+/*
+ * TRM-290 PCI-IDE2 Bus Master Chip
+ * ================================
+ * The configuration registers are addressed in normal I/O port space
+ * and are used as follows:
+ *
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
+ *	bit7 must always be written as "1"
+ *	bits6-2 undefined
+ *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
+ *	bit0 1=test_mode, 0=normal(default)
+ *
+ * trm290_base+2 when READ: status register (byte, read-only)
+ *	bits7-2 undefined
+ *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
+ *	bit0 channel0 interrupt status 0=none, 1=asserted
+ *
+ * trm290_base+3 Interrupt mask register
+ *	bits7-5 undefined
+ *	bit4 legacy_header: 1=present, 0=absent
+ *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
+ *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
+ *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
+ *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
+ *
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
+ *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
+ *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
+ *	bit5 0=enabled master burst access (default), 1=disable  (write only)
+ *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
+ *	bit3 0=primary IDE channel, 1=secondary IDE channel
+ *	bits2-0 register index for accesses through CDR port
+ *
+ * trm290_base+0 "CDR" Config Data Register (word)
+ *	two sets of seven config registers,
+ *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
+ *	each index defined below:
+ *
+ * Index-0 Base address register for command block (word)
+ *	defaults: 0x1f0 for primary, 0x170 for secondary
+ *
+ * Index-1 general config register (byte)
+ *	bit7 1=DMA enable, 0=DMA disable
+ *	bit6 1=activate IDE_RESET, 0=no action (default)
+ *	bit5 1=enable IORDY, 0=disable IORDY (default)
+ *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
+ *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
+ *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
+ *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
+ *	bit0 enable_io_ports: 1=enable(default), 0=disable
+ *
+ * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
+ *	bits7-0 bits7-0 of readahead count
+ *
+ * Index-3 read-ahead config register (byte, write only)
+ *	bit7 1=enable_readahead, 0=disable_readahead(default)
+ *	bit6 1=clear_FIFO, 0=no_action
+ *	bit5 undefined
+ *	bit4 mode4 timing control: 1=enable, 0=disable(default)
+ *	bit3 undefined
+ *	bit2 undefined
+ *	bits1-0 bits9-8 of read-ahead count
+ *
+ * Index-4 base address register for control block (word)
+ *	defaults: 0x3f6 for primary, 0x376 for secondary
+ *
+ * Index-5 data port timings (shared by both drives) (byte)
+ *	standard PCI "clk" (clock) counts, default value = 0xf5
+ *
+ *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
+ *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
+ *				011=4clk, 100=5clk, 101=6clk,
+ *				110=8clk, 111=12clk
+ *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
+ *				011=5clk, 100=6clk, 101=8clk,
+ *				110=12clk, 111=16clk
+ *
+ * Index-6 command/control port timings (shared by both drives) (byte)
+ *	same layout as Index-5, default value = 0xde
+ *
+ * Suggested CDR programming for PIO mode0 (600ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode3 (180ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode4 (120ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "trm290.h"
+
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 reg = 0;
+	unsigned long flags;
+
+	/* select PIO or DMA */
+	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+	local_irq_save(flags);
+
+	if (reg != hwif->select_data) {
+		hwif->select_data = reg;
+		/* set PIO/DMA */
+		hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+		hwif->OUTW(reg & 0xff, hwif->config_data);
+	}
+
+	/* enable IRQ if not probing */
+	if (drive->present) {
+		reg = hwif->INW(hwif->config_data + 3);
+		reg &= 0x13;
+		reg &= ~(1 << hwif->channel);
+		hwif->OUTW(reg, hwif->config_data+3);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+	trm290_prepare_drive(drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	reading = 0;
+	writing = 1;
+#ifdef TRM290_NO_DMA_WRITES
+	/* always use PIO for writes */
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
+	return 1;
+#endif
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_READDMA_EXT : */ WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_read (ide_drive_t *drive  /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_WRITEDMA_EXT : */ WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_begin (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int trm290_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;;
+
+	drive->waiting_for_dma = 0;
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	status = hwif->INW(hwif->dma_status);
+	return (status != 0x00ff);
+}
+
+static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;
+
+	status = hwif->INW(hwif->dma_status);
+	return (status == 0x00ff);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Invoked from ide-dma.c at boot time.
+ */
+void __init init_hwif_trm290 (ide_hwif_t *hwif)
+{
+	unsigned int cfgbase = 0;
+	unsigned long flags;
+	u8 reg = 0;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->addressing = 1;
+	hwif->chipset = ide_trm290;
+	cfgbase = pci_resource_start(dev, 4);
+	if ((dev->class & 5) && cfgbase) {
+		hwif->config_data = cfgbase;
+		printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+			hwif->config_data);
+	} else {
+		hwif->config_data = 0x3df0;
+		printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+			hwif->config_data);
+	}
+
+	local_irq_save(flags);
+	/* put config reg into first byte of hwif->select_data */
+	hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+	/* select PIO as default */
+	hwif->select_data = 0x21;
+	hwif->OUTB(hwif->select_data, hwif->config_data);
+	/* get IRQ info */
+	reg = hwif->INB(hwif->config_data+3);
+	/* mask IRQs for both ports */
+	reg = (reg & 0x10) | 0x03;
+	hwif->OUTB(reg, hwif->config_data+3);
+	local_irq_restore(flags);
+
+	if ((reg & 0x10))
+		/* legacy mode */
+		hwif->irq = hwif->channel ? 15 : 14;
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		/* sharing IRQ with mate */
+		hwif->irq = hwif->mate->irq;
+
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_write = &trm290_ide_dma_write;
+	hwif->ide_dma_read = &trm290_ide_dma_read;
+	hwif->ide_dma_begin = &trm290_ide_dma_begin;
+	hwif->ide_dma_end = &trm290_ide_dma_end;
+	hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	hwif->selectproc = &trm290_selectproc;
+	hwif->autodma = 0;		/* play it safe for now */
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#if 1
+	{
+	/*
+	 * My trm290-based card doesn't seem to work with all possible values
+	 * for the control basereg, so this kludge ensures that we use only
+	 * values that are known to work.  Ugh.		-ml
+	 */
+		u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
+		static u16 next_offset = 0;
+		u8 old_mask;
+
+		hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = hwif->INW(hwif->config_data);
+		old &= ~1;
+		old_mask = hwif->INB(old+2);
+		if (old != compat && old_mask == 0xff) {
+			/* leave lower 10 bits untouched */
+			compat += (next_offset += 0x400);
+#  if 1
+			if (check_region(compat + 2, 1))
+				printk(KERN_ERR "%s: check_region failure at 0x%04x\n",
+					hwif->name, (compat + 2));
+			/*
+			 * The region check is not needed; however.........
+			 * Since this is the checked in ide-probe.c,
+			 * this is only an assignment.
+			 */
+#  endif
+			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+			hwif->OUTW(compat|1, hwif->config_data);
+			new = hwif->INW(hwif->config_data);
+			printk(KERN_INFO "%s: control basereg workaround: "
+				"old=0x%04x, new=0x%04x\n",
+				hwif->name, old, new & ~1);
+		}
+	}
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &trm290_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	trm290_remove_one	-	called when an trm290 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a trm290 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void trm290_remove_one(struct pci_dev *dev)
+{
+	printk("trm290 removal not yet supported.\n");
+}
+
+static struct pci_device_id trm290_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"TRM290 IDE",
+	id_table:	trm290_pci_tbl,
+	probe:		trm290_init_one,
+	remove:		__devexit_p(trm290_remove_one),
+};
+
+static int trm290_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void trm290_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(trm290_ide_init);
+module_exit(trm290_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.h linux-2.4.21-rc3/drivers/ide/pci/trm290.h
--- linux-2.4.20/drivers/ide/pci/trm290.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/trm290.h	2003-05-22 22:06:55.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef TRM290_H
+#define TRM290_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_hwif_trm290(ide_hwif_t *);
+
+static ide_pci_device_t trm290_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_TEKRAM,
+		device:		PCI_DEVICE_ID_TEKRAM_DC290,
+		name:		"TRM290",
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_trm290,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* TRM290_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.c linux-2.4.21-rc3/drivers/ide/pci/via82cxxx.c
--- linux-2.4.20/drivers/ide/pci/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/via82cxxx.c	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,672 @@
+/*
+ *
+ * Version 3.36
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ *   vt8235
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ *
+ * Documentation:
+ *	Obsolete device documentation publically available from via.com.tw
+ *	Current device documentation available under NDA only
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "via82cxxx.h"
+
+#define VIA_IDE_ENABLE		0x40
+#define VIA_IDE_CONFIG		0x41
+#define VIA_FIFO_CONFIG		0x43
+#define VIA_MISC_1		0x44
+#define VIA_MISC_2		0x45
+#define VIA_MISC_3		0x46
+#define VIA_DRIVE_TIMING	0x48
+#define VIA_8BIT_TIMING		0x4e
+#define VIA_ADDRESS_SETUP	0x4c
+#define VIA_UDMA_TIMING		0x50
+
+#define VIA_UDMA		0x007
+#define VIA_UDMA_NONE		0x000
+#define VIA_UDMA_33		0x001
+#define VIA_UDMA_66		0x002
+#define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
+#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
+#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
+#define VIA_BAD_AST		0x200	/* Don't touch Address Setup Timing */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+	char *name;
+	u16 id;
+	u8 rev_min;
+	u8 rev_max;
+	u16 flags;
+} via_isa_bridges[] = {
+#ifdef FUTURE_BRIDGES
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+#endif
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
+	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+	{ NULL }
+};
+
+static struct via_isa_bridge *via_config;
+static unsigned char via_enabled;
+static unsigned int via_80w;
+static unsigned int via_clock;
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+
+/*
+ * VIA /proc entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc = 0;
+static unsigned long via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+
+/**
+ *	via_get_info		-	generate via /proc file 
+ *	@buffer: buffer for data
+ *	@addr: set to start of data to use
+ *	@offset: current file offset
+ *	@count: size of read
+ *
+ *	Fills in buffer with the debugging/configuration information for
+ *	the VIA chipset tuning and attached drives
+ */
+ 
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	int len;
+	u16 c, w;
+	u8 t, x;
+	char *p = buffer;
+
+	via_print("----------VIA BusMastering IDE Configuration"
+		"----------------");
+
+	via_print("Driver Version:                     3.36");
+	via_print("South Bridge:                       VIA %s",
+		via_config->name);
+
+	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+	via_print("Revision:                           ISA %#x IDE %#x", t, x);
+	via_print("Highest DMA rate:                   %s",
+		via_dma[via_config->flags & VIA_UDMA]);
+
+	via_print("BM-DMA base:                        %#lx", via_base);
+	via_print("PCI clock:                          %d.%dMHz",
+		via_clock / 1000, via_clock / 100 % 10);
+
+	pci_read_config_byte(dev, VIA_MISC_1, &t);
+	via_print("Master Read  Cycle IRDY:            %dws",
+		(t & 64) >> 6);
+	via_print("Master Write Cycle IRDY:            %dws",
+		(t & 32) >> 5);
+	via_print("BM IDE Status Register Read Retry:  %s",
+		(t & 8) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_MISC_3, &t);
+	via_print("Max DRDY Pulse Width:               %s%s",
+		via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+	via_print("-----------------------Primary IDE"
+		"-------Secondary IDE------");
+	via_print("Read DMA FIFO flush:   %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+	via_print("End Sector FIFO flush: %10s%20s",
+		(t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+	via_print("Prefetch Buffer:       %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	via_print("Post Write Buffer:     %10s%20s",
+		(t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+	via_print("Enabled:               %10s%20s",
+		(t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
+	via_print("Simplex only:          %10s%20s",
+		(c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	via_print("Cable Type:            %10s%20s",
+		(via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+	via_print("-------------------drive0----drive1"
+		"----drive2----drive3-----");
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+	if (via_config->flags & VIA_UDMA)
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+	else u = 0;
+
+	for (i = 0; i < 4; i++) {
+
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+		if (!uen[i] || !den[i])
+			continue;
+
+		switch (via_config->flags & VIA_UDMA) {
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_66:
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+				break;
+
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
+				break;
+		}
+	}
+
+	via_print_drive("Transfer Mode: ", "%10s",
+		den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	via_print_drive("Address Setup: ", "%8dns",
+		1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns",
+		1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns",
+		1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns",
+		1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns",
+		1000000 * recover[i] / via_clock);
+	via_print_drive("Cycle Time:    ", "%8dns",
+		cycle[i]);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s",
+		speed[i] / 1000, speed[i] / 100 % 10);
+
+	/* hoping it is less than 4K... */
+	len = (p - buffer) - offset;
+	*addr = buffer + offset;
+
+	return len > count ? count : len;
+}
+
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	via_set_speed			-	write timing registers
+ *	@dev: PCI device
+ *	@dn: device
+ *	@timing: IDE timing data to use
+ *
+ *	via_set_speed writes timing values to the chipset registers
+ */
+
+static void via_set_speed(struct pci_dev *dev, u8 dn, struct ide_timing *timing)
+{
+	u8 t;
+
+	if (~via_config->flags & VIA_BAD_AST) {
+		pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+		t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+		pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
+	}
+
+	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+}
+
+/**
+ *	via_set_drive		-	configure transfer mode
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	via_set_drive() computes timing values configures the drive and
+ *	the chipset to a desired transfer mode. It also can be called
+ *	by upper layers.
+ */
+
+static int via_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	unsigned int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't "
+				"accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / via_clock;
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:   UT = T;   break;
+		case VIA_UDMA_66:   UT = T/2; break;
+		case VIA_UDMA_100:  UT = T/3; break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
+	}
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/**
+ *	via82cxxx_tune_drive	-	PIO setup
+ *	@drive: drive to set up
+ *	@pio: mode to use (255 for 'best possible')
+ *
+ *	A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((via_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		via_set_drive(drive,
+			ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
+}
+
+/**
+ *	via82cxxx_ide_dma_check		-	set up for DMA if possible
+ *	@drive: IDE drive to set up
+ *
+ *	Set up the drive for the highest supported speed considering the
+ *	driver, controller and cable
+ */
+ 
+static int via82cxxx_ide_dma_check (ide_drive_t *drive)
+{
+	u16 w80 = HWIF(drive)->udma_four;
+
+	u16 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+		(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+	via_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/**
+ *	init_chipset_via82cxxx	-	initialization handler
+ *	@dev: PCI device
+ *	@name: Name of interface
+ *
+ *	The initialization callback. Here we determine the IDE chip type
+ *	and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *isa = NULL;
+	u8 t, v;
+	unsigned int u;
+	int i;
+
+	/*
+	 * Find the ISA bridge to see how good the IDE is.
+	 */
+
+	for (via_config = via_isa_bridges; via_config->id; via_config++)
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID),
+			via_config->id, NULL))) {
+
+			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+			if (t >= via_config->rev_min &&
+			    t <= via_config->rev_max)
+				break;
+		}
+
+	if (!via_config->id) {
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Check 80-wire cable presence and setup Clk66.
+	 */
+
+	switch (via_config->flags & VIA_UDMA) {
+
+		case VIA_UDMA_66:
+			/* Enable Clk66 */
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> (i & 16)) & 8) &&
+				    ((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 2)) {
+					/*
+					 * 2x PCI clock and
+					 * UDMA w/ < 3T/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 4))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 8))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+	}
+
+	/* Disable Clk66 */
+	if (via_config->flags & VIA_BAD_CLK66) {
+		/* Would cause trouble on 596a and 686 */
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
+	}
+
+	/*
+	 * Check whether interfaces are enabled.
+	 */
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
+
+	/*
+	 * Set up FIFO sizes and thresholds.
+	 */
+
+	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
+
+	/* Disable PREQ# till DDACK# */
+	if (via_config->flags & VIA_BAD_PREQ) {
+		/* Would crash on 586b rev 41 */
+		t &= 0x7f;
+	}
+
+	/* Fix FIFO split between channels */
+	if (via_config->flags & VIA_SET_FIFO) {
+		t &= (t & 0x9f);
+		switch (via_enabled) {
+			case 1: t |= 0x00; break;	/* 16 on primary */
+			case 2: t |= 0x60; break;	/* 16 on secondary */
+			case 3: t |= 0x20; break;	/* 8 pri 8 sec */
+		}
+	}
+
+	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
+
+	/*
+	 * Determine system bus clock.
+	 */
+
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
+		printk(KERN_WARNING "VP_IDE: User given PCI clock speed "
+			"impossible (%d), using 33 MHz instead.\n", via_clock);
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want "
+			"to assume 80-wire cable.\n");
+		via_clock = 33333;
+	}
+
+	/*
+	 * Print the boot message.
+	 */
+
+	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+		"controller on pci%s\n",
+		via_config->name, t,
+		via_dma[via_config->flags & VIA_UDMA],
+		dev->slot_name);
+
+	/*
+	 * Setup /proc/ide/via entry.
+	 */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!via_proc) {
+		via_base = pci_resource_start(dev, 4);
+		bmide_dev = dev;
+		isa_dev = isa;
+		ide_pci_register_host_proc(&via_procs[0]);
+		via_proc = 1;
+	}
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &via82cxxx_tune_drive;
+	hwif->speedproc = &via_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1;
+	hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_via82cxxx	-	set up for IDE DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA base address
+ *
+ *	We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+
+static void __init init_dma_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((via_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &via82cxxx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id via_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name 		= "VIA IDE",
+	.id_table 	= via_pci_tbl,
+	.probe 		= via_init_one,
+};
+
+static int via_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void via_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(via_ide_init);
+module_exit(via_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.h linux-2.4.21-rc3/drivers/ide/pci/via82cxxx.h
--- linux-2.4.20/drivers/ide/pci/via82cxxx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pci/via82cxxx.h	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,67 @@
+#ifndef VIA82CXXX_H
+#define VIA82CXXX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc;
+
+static int via_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t via_procs[] __initdata = {
+	{
+		.name		= "via",
+		.set		= 1,
+		.get_info	= via_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_via82cxxx(struct pci_dev *, const char *);
+static void init_hwif_via82cxxx(ide_hwif_t *);
+static void init_dma_via82cxxx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C576_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C586_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* VIA82CXXX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc202xx.c linux-2.4.21-rc3/drivers/ide/pdc202xx.c
--- linux-2.4.20/drivers/ide/pdc202xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pdc202xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1188 +0,0 @@
-/*
- *  linux/drivers/ide/pdc202xx.c	Version 0.32	Feb. 27, 2002
- *
- *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Promise Ultra66 cards with BIOS v1.11 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100 cards with BIOS v2.01 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100TX2 with BIOS v2.10 & Ultra133TX2 with BIOS v2.20
- *  support 8 hard drives on UDMA mode.
- *
- *  Linux kernel will misunderstand FastTrak ATA-RAID series as Ultra
- *  IDE Controller, UNLESS you enable "CONFIG_PDC202XX_FORCE"
- *  That's you can use FastTrak ATA-RAID controllers as IDE controllers.
- *
- *  History :
- *  05/22/01    v1.20 b1
- *           (1) support PDC20268
- *           (2) fix cable judge function
- *  08/22/01    v1.20 b2
- *           (1) support ATA-133 PDC20269/75
- *           (2) support UDMA Mode 6
- *           (3) fix proc report information
- *           (4) set ATA133 timing
- *           (5) fix ultra dma bit 14 selectable
- *           (6) support 32bit LBA
- *  09/11/01    v1.20 b3 
- *           (1) fix eighty_ninty_three()
- *           (2) fix offset address 0x1c~0x1f
- *  10/30/01    v1.20 b4
- *           (1) fix 48bit LBA HOB bit
- *           (2) force rescan drive under PIO modes if need
- *  11/02/01    v1.20.0.5
- *           (1) could be patched with ext3 filesystem code
- *  11/06/01    v1.20.0.6
- *           (1) fix LBA48 drive running without Promise controllers
- *           (2) fix LBA48 drive running under PIO modes
- *  01/28/02    v1.20.0.6
- *           (1) release for linux IDE Group kernel 2.4.18
- *           (2) add version and controller info to proc
- *  05/23/02    v1.20.0.7
- *           (1) disable PDC20262 running with 48bit
- *           (2) Add quirk drive lists for PDC20265/67
- *
- *  Copyright (C) 1999-2002 Promise Technology, Inc.
- *  Author: Frank Tiernan <frankt@promise.com>
- *          PROMISE pdc202xx IDE Controller driver MAINTAINERS
- *  Released under terms of General Public License
- */
- 
-#define VERSION	"1.20.0.7"
-#define VERDATE "2002-05-23"
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define PDC202XX_DEBUG_DRIVE_INFO		0
-#define PDC202XX_DECODE_REGISTER_INFO		0
-
-#define DISPLAY_PDC202XX_TIMINGS
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdc202xx_get_info(char *, char **, off_t, int);
-extern int (*pdc202xx_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 hd_driveid *id[4];
-static int speed_rate[4];
-
-static char * pdc202xx_info (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;
-	u16 word88 = 0;
-	int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0};
-	int i = 0, hd = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	u8 c0	= inb_p((unsigned short)bibma + 0x02);
-	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
-
-	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
-	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
-	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
-	/* u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
-	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
-	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
-	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f); */
-
-	pci_read_config_word(dev, 0x50, &reg50h);
-	pci_read_config_dword(dev, 0x60, &reg60h);
-	pci_read_config_dword(dev, 0x64, &reg64h);
-	pci_read_config_dword(dev, 0x68, &reg68h);
-	pci_read_config_dword(dev, 0x6c, &reg6ch);
-
-	p+=sprintf(p, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE);
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "MBUltra133\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "Ultra133 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			p += sprintf(p, "Ultra100 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "Ultra100\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "Ultra100 on M/B\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "Ultra66\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "Ultra33\n");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "Ultra Series\n");
-			break;
-	}
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %s                         %s\n",
-		(c0&0x80)?"disabled":"enabled ",
-		(c1&0x80)?"disabled":"enabled ");
-	p += sprintf(p, "66 Clocking     %s                         %s\n",
-		(sc11&0x02)?"enabled ":"disabled",
-		(sc11&0x08)?"enabled ":"disabled");
-	p += sprintf(p, "Mode            %s                           %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ",
-		(id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no ");
-	for( hd = 0; hd < 4 ; hd++) {
-		if (id[hd] == NULL)
-			continue;
-		word88 = id[hd]->dma_ultra;
-		for ( i = 7 ; i >= 0 ; i--)
-			if (word88 >> (i+8)) {
-				udmasel[hd] = i;	/* get select UDMA mode */
-				break;
-			}
-		piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3;
-        }
-	p += sprintf(p, "UDMA Mode:      %d                %d               %d                 %d\n",
-		udmasel[0], udmasel[1], udmasel[2], udmasel[3]);
-	p += sprintf(p, "PIO Mode:       %d                %d               %d                 %d\n",
-		piosel[0], piosel[1], piosel[2], piosel[3]);
-#if 0
-	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
-#endif
-	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);
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte pdc202xx_proc = 0;
-
-const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX13.6",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/* A Register */
-#define	SYNC_ERRDY_EN	0xC0
-
-#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
-#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
-#define	IORDY_EN	0x20	/* PIO: IOREADY */
-#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
-
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
-
-#if PDC202XX_DECODE_REGISTER_INFO
-
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
-
-static void decode_registers (byte registers, byte value)
-{
-	byte	bit = 0, bit1 = 0, bit2 = 0;
-
-	switch(registers) {
-		case REG_A:
-			bit2 = 0;
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			bit1 = 0;bit2 = 0;
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			bit2 = 0;
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
-
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	unsigned int		drive_conf;
-	int			err = 0, i = 0, j = hwif->channel ? 2 : 0 ;
-	byte			drive_pci, AP, BP, CP, DP;
-	byte			TA = 0, TB = 0, TC = 0;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0x60; break;
-		case 1: drive_pci = 0x64; break;
-		case 2: drive_pci = 0x68; break;
-		case 3: drive_pci = 0x6c; break;
-		default: return -1;
-	}
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
-
-	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);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		if ((BP & 0xF0) && (CP & 0x0F)) {
-			/* clear DMA modes of upper 842 bits of B Register */
-			/* clear PIO forced mode upper 1 bit of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			/* clear DMA modes of lower 8421 bits of C Register */
-			pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-		}
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((AP & 0x0F) || (BP & 0x07)) {
-			/* clear PIO modes of lower 8421 bits of A Register */
-			pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
-			/* clear PIO modes of lower 421 bits of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-		}
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-
-	for ( i = 0; i < 2; i++)
-		if (hwif->drives[i].present)
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-
-	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 */
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;	/* speed 6 == UDMA mode 2 */
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;	/* speed 5 == UDMA mode 1 */
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;	/* speed 4 == UDMA mode 0 */
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;	/* speed 4 == MDMA mode 2 */
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;	/* speed 3 == MDMA mode 1 */
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;	/* speed 2 == MDMA mode 0 */
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;	/* speed 0 == SDMA mode 2 */
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;	/* speed 1 == SDMA mode 1 */
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;	/* speed 0 == SDMA mode 0 */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
-		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
-		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
-		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
-		case XFER_PIO_0:
-		default:		TA = 0x09; TB = 0x13; break;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-        if (speed >= XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-	}
-
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, drive_conf);
-		pci_read_config_dword(dev, drive_pci, &drive_conf);
-	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	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 set_speed		= 0, i=0, j=hwif->channel ? 2:0;
-	int                     err;
-
-	/* Setting tHOLD bit to 0 if using UDMA mode 2 */
-	if (speed == XFER_UDMA_2) {
-		OUT_BYTE((thold + adj), indexreg);
-		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
-	}
-	
-	/* We need to set ATA133 timing if ATA133 drives exist */
-	if (speed>=XFER_UDMA_6)
-		set_speed=1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: Before set_feature = %s, word88 = %#x\n",
-		drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra );
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;	
-	for ( i = 0 ; i < 2 ; i++)
-		if (hwif->drives[i].present) {
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-	 		speed_rate[i+j] = speed;	/* get current speed */
-	 	}
-	if (set_speed) {
-		for (i=0; i<4; i++) {
-			if (id[i]==NULL)
-				continue;
-			switch(speed_rate[i]) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-				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;
-#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:
-			}
-		}
-	}
-	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
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed = 0x00;
-
-	pio = (pio == 5) ? 4 : pio;
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-        
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	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 new_chip		= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned int		drive_conf;
-	byte			drive_pci = 0;
-	byte			test1, test2, speed = -1;
-	byte			AP;
-	unsigned short		EP;
-	byte CLKSPD		= 0;
-	byte clockreg		= high_16 + 0x11;
-	byte udma_33		= ultra;
-	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 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_20276:
-		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));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 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);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		default:
-			udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1;
-			break;
-	}
-
-	/*
-	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operation. If one drive on
-	 * a channel is U66 capable but the other isn't we
-	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued. I don't
-	 * do that here because it would require modifying the
-	 * kernel, seperating the fop routines from the kernel or
-	 * somehow hooking the fops calls. It may also be possible to
-	 * leave the 66Mhz clock on and readjust the timing
-	 * parameters.
-	 */
-
-	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 */
-		//if (!new_chip)
-		OUT_BYTE(CLKSPD & ~mask, clockreg);
-		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) || (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 & 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, clockreg);
-				} else {
-					OUT_BYTE(CLKSPD & ~mask, clockreg);
-				}
-			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, clockreg);
-			}
-		}
-	}
-
-	if (new_chip)	goto chipset_is_set;
-
-	switch(drive->dn) {
-		case 0:	drive_pci = 0x60;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 1:	drive_pci = 0x64;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x60, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		case 2:	drive_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 3:	drive_pci = 0x6c;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x68, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		default:
-			return ide_dma_off;
-	}
-
-chipset_is_set:
-
-	if (drive->media != ide_disk)
-		return ide_dma_off_quietly;
-	
-	if (new_chip) {
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
-		}
-	}
-	else {
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (id->capability & 4)	/* IORDY_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (drive->media == ide_disk)	/* PREFETCH_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-	}
-
-	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)&&(!new_chip))	speed = XFER_SW_DMA_2;
-	else if ((id->dma_1word & 0x0002)&&(!new_chip))	speed = XFER_SW_DMA_1;
-	else if ((id->dma_1word & 0x0001)&&(!new_chip))	speed = XFER_SW_DMA_0;
-	else {
-		/* restore original pci-config space */
-		if (!new_chip)
-			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) hwif->speedproc(drive, speed);
-
-	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 :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-int pdc202xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
-}
-
-/*
- * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte sc1d		= 0;
-	byte newchip		= 0;
-	byte clock		= 0;
-	byte hardware48fix	= 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 dma_base	= hwif->dma_base;
-	unsigned long atapi_port= hwif->channel ? high_16+0x24 : high_16+0x20;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			hardware48fix = 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.
-			 */
-			/* Enable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				struct request *rq = HWGROUP(drive)->rq;
-				unsigned long word_count = 0;
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-				OUT_BYTE(clock|(hwif->channel ? 0x08:0x02), clockreg);
-				word_count = (rq->nr_sectors << 8);
-				hankval = (rq->cmd == READ) ? 0x05<<24 : 0x06<<24;
-				hankval = hankval | word_count ;
-				outl(hankval, atapi_port);
-			}  
-			break;
-		case ide_dma_end:
-			/* Disable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-			    	outl(hankval, atapi_port);	/* zero out extra */
-				clock = IN_BYTE(clockreg);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), clockreg);
-			}
-			break;
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			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)
-					return (dma_stat & 4) == 4;
-			} else {
-				if ((sc1d & 0x05) == 0x05) goto somebody_else;
-				else if ((sc1d & 0x04) == 0x04)
-					return (dma_stat & 4) == 4;
-			}
-somebody_else:
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			if (HWIF(drive)->resetproc != NULL)
-				HWIF(drive)->resetproc(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void pdc202xx_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");
-}
-
-/*
- * 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)
-{
-#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);
-
-	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 (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);
-	}
-	
-	printk("%s: (U)DMA Burst Bit %sABLED " \
-		"Primary %s Mode " \
-		"Secondary %s Mode.\n",
-		name,
-		(udma_speed_flag & 1) ? "EN" : "DIS",
-		(primary_mode & 1) ? "MASTER" : "PCI",
-		(secondary_mode & 1) ? "MASTER" : "PCI" );
-
-#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));
-		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
-	}
-#endif /* CONFIG_PDC202XX_BURST */
-
-#ifdef CONFIG_PDC202XX_MASTER
-	if (!(primary_mode & 1)) {
-		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			name, primary_mode, (primary_mode|1));
-		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));
-		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
-	}
-#endif /* CONFIG_PDC202XX_MASTER */
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdc202xx_proc) {
-		pdc202xx_proc = 1;
-		bmide_dev = dev;
-		pdc202xx_display_info = &pdc202xx_get_info;
-	}
-#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-	return dev->irq;
-}
-
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
-{
-	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
-	unsigned short CIS;
-
-        	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			/* check 80pin cable */
-		default:
-			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-			return (!(CIS & mask));
-			/* check 80pin cable */
-	}
-}
-
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
-	hwif->resetproc = &pdc202xx_reset;
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			hwif->speedproc = &pdc202xx_new_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			hwif->speedproc = &pdc202xx_tune_chipset;
-		default:
-			break;
-	}
-
-#undef CONFIG_PDC202XX_32_UNMASK
-#ifdef CONFIG_PDC202XX_32_UNMASK
-	hwif->drives[0].io_32bit = 1;
-	hwif->drives[1].io_32bit = 1;
-	hwif->drives[0].unmask = 1;
-	hwif->drives[1].unmask = 1;
-#endif /* CONFIG_PDC202XX_32_UNMASK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &pdc202xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.c linux-2.4.21-rc3/drivers/ide/pdc4030.c
--- linux-2.4.20/drivers/ide/pdc4030.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,578 +0,0 @@
-/*  -*- linux-c -*-
- *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
- *
- *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
- *
- *  This file provides support for the second port and cache of Promise
- *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
- *
- *  Thanks are due to Mark Lord for advice and patiently answering stupid
- *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
- *  especially Andre Hedrick.
- *
- *  Version 0.01	Initial version, #include'd in ide.c rather than
- *                      compiled separately.
- *                      Reads use Promise commands, writes as before. Drives
- *                      on second channel are read-only.
- *  Version 0.02        Writes working on second channel, reads on both
- *                      channels. Writes fail under high load. Suspect
- *			transfers of >127 sectors don't work.
- *  Version 0.03        Brought into line with ide.c version 5.27.
- *                      Other minor changes.
- *  Version 0.04        Updated for ide.c version 5.30
- *                      Changed initialization strategy
- *  Version 0.05	Kernel integration.  -ml
- *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
- *  Version 0.07	Added support for DC4030 variants
- *			Secondary interface autodetection
- *  Version 0.08	Renamed to pdc4030.c
- *  Version 0.09	Obsolete - never released - did manual write request
- *			splitting before max_sectors[major][minor] available.
- *  Version 0.10	Updated for 2.1 series of kernels
- *  Version 0.11	Updated for 2.3 series of kernels
- *			Autodetection code added.
- *
- *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
- */
-
-/*
- * Once you've compiled it in, you'll have to also enable the interface
- * setup routine from the kernel command line, as in 
- *
- *	'linux ide0=dc4030' or 'linux ide1=dc4030'
- *
- * It should now work as a second controller also ('ide1=dc4030') but only
- * if you DON'T have BIOS V4.44, which has a bug. If you have this version
- * and EPROM programming facilities, you need to fix 4 bytes:
- * 	2496:	81	81
- *	2497:	3E	3E
- *	2498:	22	98	*
- *	2499:	06	05	*
- *	249A:	F0	F0
- *	249B:	01	01
- *	...
- *	24A7:	81	81
- *	24A8:	3E	3E
- *	24A9:	22	98	*
- *	24AA:	06	05	*
- *	24AB:	70	70
- *	24AC:	01	01
- *
- * As of January 1999, Promise Technology Inc. have finally supplied me with
- * some technical information which has shed a glimmer of light on some of the
- * problems I was having, especially with writes. 
- *
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
- */
-
-#define DEBUG_READ
-#define DEBUG_WRITE
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "pdc4030.h"
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-/*
- * promise_selectproc() is invoked by ide.c
- * in preparation for access to the specified drive.
- */
-static void promise_selectproc (ide_drive_t *drive)
-{
-	unsigned int number;
-
-	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
-	OUT_BYTE(number,IDE_FEATURE_REG);
-}
-
-/*
- * pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification -
- * 'P' (=0x50) on success, 'p' (=0x70) on failure.
- */
-int pdc4030_cmd(ide_drive_t *drive, byte cmd)
-{
-	unsigned long timeout, timer;
-	byte status_val;
-
-	promise_selectproc(drive);	/* redundant? */
-	OUT_BYTE(0xF3,IDE_SECTOR_REG);
-	OUT_BYTE(cmd,IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
-	timeout = HZ * 10;
-	timeout += jiffies;
-	do {
-		if(time_after(jiffies, timeout)) {
-			return 2; /* device timed out */
-		}
-		/* This is out of delay_10ms() */
-		/* Delays at least 10ms to give interface a chance */
-		timer = jiffies + (HZ + 99)/100 + 1;
-		while (time_after(timer, jiffies));
-		status_val = IN_BYTE(IDE_SECTOR_REG);
-	} while (status_val != 0x50 && status_val != 0x70);
-
-	if(status_val == 0x50)
-		return 0; /* device returned success */
-	else
-		return 1; /* device returned failure */
-}
-
-/*
- * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
- */
-int pdc4030_identify(ide_drive_t *drive)
-{
-	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
-}
-
-int enable_promise_support = 0;
-
-void __init init_pdc4030 (void)
-{
-	enable_promise_support = 1;
-}
-
-/*
- * setup_pdc4030()
- * Completes the setup of a Promise DC4030 controller card, once found.
- */
-int __init setup_pdc4030 (ide_hwif_t *hwif)
-{
-        ide_drive_t *drive;
-	ide_hwif_t *hwif2;
-	struct dc_ident ident;
-	int i;
-	ide_startstop_t startstop;
-	
-	if (!hwif) return 0;
-
-	drive = &hwif->drives[0];
-	hwif2 = &ide_hwifs[hwif->index+1];
-	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
-		return 1;
-
-	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
-		return 0;
-	}
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(0x08,IDE_CONTROL_REG);
-	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
-		return 0;
-	}
-	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
-		printk(KERN_INFO
-			"%s: Failed Promise read config!\n",hwif->name);
-		return 0;
-	}
-	ide_input_data(drive,&ident,SECTOR_WORDS);
-	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
-		return 0;
-	}
-	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
-	switch(ident.type) {
-		case 0x43:	printk("DC4030VL-2, "); break;
-		case 0x41:	printk("DC4030VL-1, "); break;
-		case 0x40:	printk("DC4030VL, "); break;
-		default:
-			printk("unknown - type 0x%02x - please report!\n"
-			       ,ident.type);
-			printk("Please e-mail the following data to "
-			       "promise@pnd-pc.demon.co.uk along with\n"
-			       "a description of your card and drives:\n");
-			for (i=0; i < 0x90; i++) {
-				printk("%02x ", ((unsigned char *)&ident)[i]);
-				if ((i & 0x0f) == 0x0f) printk("\n");
-			}
-			return 0;
-	}
-	printk("%dKB cache, ",(int)ident.cache_mem);
-	switch(ident.irq) {
-            case 0x00: hwif->irq = 14; break;
-            case 0x01: hwif->irq = 12; break;
-            default:   hwif->irq = 15; break;
-	}
-	printk("on IRQ %d\n",hwif->irq);
-
-	/*
-	 * Once found and identified, we set up the next hwif in the array
-	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
-	 * and other settings as the main hwif. This gives us two "mated"
-	 * hwifs pointing to the Promise card.
-	 *
-	 * We also have to shift the default values for the remaining
-	 * interfaces "up by one" to make room for the second interface on the
-	 * same set of values.
-	 */
-
-	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->mate	= hwif2;
-	hwif2->mate	= hwif;
-	hwif2->channel	= 1;
-	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
-	hwif->serialized = hwif2->serialized = 1;
-
-/* Shift the remaining interfaces down by one */
-	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		ide_hwif_t *h = &ide_hwifs[i];
-
-#ifdef DEBUG
-		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
-#endif
-		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
-		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
-		h->noprobe = (h-1)->noprobe;
-	}
-	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
-	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
-	hwif2->irq = hwif->irq;
-	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
-	for (i=0; i<2 ; i++) {
-		hwif->drives[i].io_32bit = 3;
-		hwif2->drives[i].io_32bit = 3;
-		hwif->drives[i].keep_settings = 1;
-		hwif2->drives[i].keep_settings = 1;
-		if (!ident.current_tm[i].cyl)
-			hwif->drives[i].noprobe = 1;
-		if (!ident.current_tm[i+2].cyl)
-			hwif2->drives[i].noprobe = 1;
-	}
-        return 1;
-}
-
-/*
- * detect_pdc4030()
- * Tests for the presence of a DC4030 Promise card on this interface
- * Returns: 1 if found, 0 if not found
- */
-int __init detect_pdc4030(ide_hwif_t *hwif)
-{
-	ide_drive_t *drive = &hwif->drives[0];
-
-	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
-		return 0;
-	}
-	OUT_BYTE(0xF3, IDE_SECTOR_REG);
-	OUT_BYTE(0x14, IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
-	
-	ide_delay_50ms();
-
-	if (IN_BYTE(IDE_ERROR_REG) == 'P' &&
-	    IN_BYTE(IDE_NSECTOR_REG) == 'T' &&
-	    IN_BYTE(IDE_SECTOR_REG) == 'I') {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-void __init ide_probe_for_pdc4030(void)
-{
-	unsigned int	index;
-	ide_hwif_t	*hwif;
-
-	if (enable_promise_support == 0)
-		return;
-	for (index = 0; index < MAX_HWIFS; index++) {
-		hwif = &ide_hwifs[index];
-		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
-			setup_pdc4030(hwif);
-		}
-	}
-}
-
-/*
- * promise_read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t promise_read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int total_remaining;
-	unsigned int sectors_left, sectors_avail, nsect;
-	struct request *rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		return ide_error(drive, "promise_read_intr", stat);
-	}
-
-read_again:
-	do {
-		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
-		IN_BYTE(IDE_SECTOR_REG);
-	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
-	rq = HWGROUP(drive)->rq;
-	sectors_avail = rq->nr_sectors - sectors_left;
-	if (!sectors_avail)
-		goto read_again;
-
-read_next:
-	rq = HWGROUP(drive)->rq;
-	nsect = rq->current_nr_sectors;
-	if (nsect > sectors_avail)
-		nsect = sectors_avail;
-	sectors_avail -= nsect;
-	ide_input_data(drive, rq->buffer, 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,
-	       rq->sector+nsect-1, (unsigned long) rq->buffer,
-	       rq->nr_sectors-nsect);
-#endif
-	rq->sector += nsect;
-	rq->buffer += nsect<<9;
-	rq->errors = 0;
-	rq->nr_sectors -= nsect;
-	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	}
-/*
- * Now the data has been read in, do the following:
- * 
- * if there are still sectors left in the request, 
- *   if we know there are still sectors available from the interface,
- *     go back and read the next bit of the request.
- *   else if DRQ is asserted, there are more sectors available, so
- *     go back and find out how many, then read them in.
- *   else if BUSY is asserted, we are going to get an interrupt, so
- *     set the handler for the interrupt and just return
- */
-	if (total_remaining > 0) {
-		if (sectors_avail)
-			goto read_next;
-		stat = GET_STAT();
-		if (stat & DRQ_STAT)
-			goto read_again;
-		if (stat & BUSY_STAT) {
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
-#ifdef DEBUG_READ
-			printk(KERN_DEBUG "%s: promise_read: waiting for"
-			       "interrupt\n", drive->name);
-#endif
-			return ide_started;
-		}
-		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
-		       "!DRQ !BUSY\n", drive->name);
-		return ide_error(drive, "promise read intr", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_complete_pollfunc()
- * This is the polling function for waiting (nicely!) until drive stops
- * being busy. It is invoked at the end of a write, after the previous poll
- * has finished.
- *
- * Once not busy, the end request is called.
- */
-static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
-{
-	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)) {
-			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: completion timeout - still busy!\n",
-		       drive->name);
-		return ide_error(drive, "busy timeout", GET_STAT());
-	}
-
-	hwgroup->poll_timeout = 0;
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
-#endif
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, hwgroup);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_write_pollfunc() is the handler for disk write completion polling.
- */
-static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		return ide_error (drive, "write timeout", GET_STAT());
-	}
-
-	/*
-	 * Now write out last 4 sectors and poll for not BUSY
-	 */
-	ide_multwrite(drive, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
-		drive->name, GET_STAT());
-#endif
-	return ide_started;
-}
-
-/*
- * promise_write() transfers a block of one or more sectors of data to a
- * drive as part of a disk write operation. All but 4 sectors are transferred
- * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transferred. There is no interrupt generated
- * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
- */
-static ide_startstop_t promise_write (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
-	       "buffer=%p\n", drive->name, rq->sector,
-	       rq->sector + rq->nr_sectors - 1, rq->buffer);
-#endif
-
-	/*
-	 * If there are more than 4 sectors to transfer, do n-4 then go into
-	 * the polling strategy as defined above.
-	 */
-	if (rq->nr_sectors > 4) {
-		if (ide_multwrite(drive, rq->nr_sectors - 4))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-		return ide_started;
-	} else {
-	/*
-	 * There are 4 or fewer sectors to transfer, do them all in one go
-	 * and wait for NOT BUSY.
-	 */
-		if (ide_multwrite(drive, rq->nr_sectors))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
-			"status = %02x\n", drive->name, GET_STAT());
-#endif
-		return ide_started;
-	}
-}
-
-/*
- * do_pdc4030_io() is called from do_rw_disk, having had the block number
- * 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 startstop;
-	unsigned long timeout;
-	byte stat;
-
-	switch(rq->cmd) {
-		case READ:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-#endif
-/*
- * The card's behaviour is odd at this point. If the data is
- * available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the 
- * "interrupt" handler (promise_read_intr) directly. Otherwise, if
- * an interrupt is going to occur, bit0 of the SELECT register will
- * be high, so we can set the handler the just return and be interrupted.
- * If neither of these is the case, we wait for up to 50ms (badly I'm
- * afraid!) until one of them is.
- */
-			timeout = jiffies + HZ/20; /* 50ms wait */
-			do {
-				stat=GET_STAT();
-				if (stat & DRQ_STAT) {
-					udelay(1);
-					return promise_read_intr(drive);
-				}
-				if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name);
-#endif
-					ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-					return ide_started;
-				}
-				udelay(1);
-			} while (time_before(jiffies, timeout));
-
-			printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name);
-			return ide_stopped;
-		case WRITE:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-#endif
-			if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-				printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
-				return startstop;
-		    	}
-			if (!drive->unmask)
-				__cli();	/* local CPU only */
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
-			return promise_write(drive);
-		default:
-			printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd);
-			ide_end_request(0, HWGROUP(drive));
-			return ide_stopped;
-	}
-}
-
-#ifdef __TASKFILE__IO
-
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr taskfile;
-
-	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->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
-
-	do_taskfile(drive, &taskfile, NULL, NULL);
-	return do_pdc4030_io(drive, rq);
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.h linux-2.4.21-rc3/drivers/ide/pdc4030.h
--- linux-2.4.20/drivers/ide/pdc4030.h	2001-07-18 01:53:55.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/*
- *  linux/drivers/ide/pdc4030.h
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & authors
- */
-
-/*
- * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
- */
-
-#ifndef IDE_PROMISE_H
-#define IDE_PROMISE_H
-
-#define	PROMISE_EXTENDED_COMMAND	0xF0
-#define	PROMISE_READ			0xF2
-#define	PROMISE_WRITE			0xF3
-/* Extended commands - main command code = 0xf0 */
-#define	PROMISE_GET_CONFIG		0x10
-#define	PROMISE_IDENTIFY		0x20
-
-struct translation_mode {
-	u16	cyl;
-	u8	head;
-	u8	sect;
-};
-
-struct dc_ident {
-	u8	type;
-	u8	unknown1;
-	u8	hw_revision;
-	u8	firmware_major;
-	u8	firmware_minor;
-	u8	bios_address;
-	u8	irq;
-	u8	unknown2;
-	u16	cache_mem;
-	u16	unknown3;
-	u8	id[2];
-	u16	info;
-	struct translation_mode current_tm[4];
-	u8	pad[SECTOR_WORDS*4 - 32];
-};
-
-#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.c linux-2.4.21-rc3/drivers/ide/pdcraid.c
--- linux-2.4.20/drivers/ide/pdcraid.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,646 +0,0 @@
-/*
-   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   Based on work done by Søren Schmidt for FreeBSD  
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int pdcraid_open(struct inode * inode, struct file * filp);
-static int pdcraid_release(struct inode * inode, struct file * filp);
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-struct disk_dev {
-	int major;
-	int minor;
-	int device;
-};
-
-static struct disk_dev devlist[]= {
-	{IDE0_MAJOR,  0,  -1 },
-	{IDE0_MAJOR, 64,  -1 },
-	{IDE1_MAJOR,  0,  -1 },
-	{IDE1_MAJOR, 64,  -1 },
-	{IDE2_MAJOR,  0,  -1 },
-	{IDE2_MAJOR, 64,  -1 },
-	{IDE3_MAJOR,  0,  -1 },
-	{IDE3_MAJOR, 64,  -1 },
-	{IDE4_MAJOR,  0,  -1 },
-	{IDE4_MAJOR, 64,  -1 },
-	{IDE5_MAJOR,  0,  -1 },
-	{IDE5_MAJOR, 64,  -1 },
-	{IDE6_MAJOR,  0,  -1 },
-	{IDE6_MAJOR, 64,  -1 },
-};
-
-
-struct pdcdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-	unsigned long last_pos;
-};
-
-struct pdcraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct pdcdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations pdcraid0_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid0_make_request
-};
-
-static struct raid_device_operations pdcraid1_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid1_make_request
-};
-
-static struct pdcraid raid[16];
-
-
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-   	unsigned long sectors;
-
-	if (!inode || !inode->i_rdev) 
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-
-         	case BLKGETSIZE:   /* Return device size */
- 			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
-			
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-			
-		case BLKROSET:
-		case BLKROGET:
-		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			printk("Invalid ioctl \n");
-			return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	return block + partition_off;
-}
-
-unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
-
-unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock,temp,temp2;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-
-	if (block < (partition_size / (8*stride))*8*stride ) {
-		temp = block % stride;
-		temp2 = block / stride;
-		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
-		block = temp2*stride+temp;
-	}
-
-	
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-
-
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct pdcraid *thisraid;
-
-	rsect = bh->b_rsector;
-	
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;  
-	}
-	
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1;
-	struct ataraid_bh_private *private;
-	int device;
-	int i;
-
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-
-	private->parent = bh;
-	
-	atomic_set(&private->count,raid[device].disks);
-
-
-	for (i = 0; i< raid[device].disks; i++) { 
-		bh1=ataraid_get_bhead();
-		/* If this ever fails we're doomed */
-		if (!bh1)
-			BUG();
-	
-		/* dupe the bufferhead and update the parts that need to be different */
-		memcpy(bh1, bh, sizeof(*bh));
-		
-		bh1->b_end_io = ataraid_end_request;
-		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
-		bh1->b_rdev = raid[device].disk[i].device;
-
-		/* update the last known head position for the drive */
-		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
-
-		generic_make_request(rw,bh1);
-	}
-	return 0;
-}
-
-static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int device;
-	int dist;
-	int bestsofar,bestdist,i;
-	static int previous;
-
-	/* Reads are simple in principle. Pick a disk and go. 
-	   Initially I cheat by just picking the one which the last known
-	   head position is closest by.
-	   Later on, online/offline checking and performance needs adding */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	bestsofar = 0; 
-	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
-	if (bestdist<0) 
-		bestdist=-bestdist;
-	if (bestdist>4095)
-		bestdist=4095;
-
-	for (i=1 ; i<raid[device].disks; i++) {
-		dist = raid[device].disk[i].last_pos - bh->b_rsector;
-		if (dist<0) 
-			dist = -dist;
-		if (dist>4095)
-			dist=4095;
-		
-		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
-			if ((previous>bestsofar)&&(previous<=i))  
-				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
-		} else if (bestdist>dist) {
-			bestdist = dist;
-			bestsofar = i;
-		}
-	
-	}
-	
-	bh->b_rdev = raid[device].disk[bestsofar].device; 
-	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-                          	
-	return 1;
-}
-
-
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	/* Read and Write are totally different cases; split them totally here */
-	if (rw==READA)
-		rw = READ;
-	
-	if (rw==READ)
-		return pdcraid1_read_request(q,rw,bh);
-	else
-		return pdcraid1_write_request(q,rw,bh);
-}
-
-#include "pdcraid.h"
-
-static unsigned long calc_pdcblock_offset (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
-	lba = lba * (ideinfo->head*ideinfo->sect);
-	lba = lba - ideinfo->sect;
-
-	return lba;
-}
-
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	unsigned long sb_offset;
-
-	if (blksize_size[major]==NULL)   /* device doesn't exist */
-		return -EINVAL;
-                       
-	
-	/*
-	 * Calculate the position of the superblock,
-	 * it's at first sector of the last cylinder
-	 */
-	sb_offset = calc_pdcblock_offset(major,minor)/8;
-	/* The /8 transforms sectors into 4Kb blocks */
-
-	if (sb_offset==0)
-		return -1;	
-	
-	set_blocksize (dev, 4096);
-
-	bh = bread (dev, sb_offset, 4096);
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned int calc_sb_csum (unsigned int* ptr)
-{	
-	unsigned int sum;
-	int count;
-	
-	sum = 0;
-	for (count=0;count<511;count++)
-		sum += *ptr++;
-	
-	return sum;
-}
-
-static int cookie = 0;
-
-static void __init probedisk(int devindex,int device, int raidlevel)
-{
-	int i;
-	int major, minor;
-        struct promise_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-
-	if (devlist[devindex].device!=-1) /* already assigned to another array */
-		return;
-	
-	major = devlist[devindex].major;
-	minor = devlist[devindex].minor; 
-
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct promise_raid_conf*)&block[512];
-
-        /* the checksums must match */
-	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
-		return;
-	if (prom->raid.type!=raidlevel) /* different raidlevel */
-		return;
-
-	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
-		return;
-	
-	cookie = prom->raid.magic_1;
-
-	/* This looks evil. But basically, we have to search for our adapternumber
-	   in the arraydefinition, both of which are in the superblock */	
-        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
-        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
-        	     (prom->raid.disk[i].device == prom->raid.device) ) {
-
-        	        bdev = bdget(MKDEV(major,minor));
-        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
-				raid[device].disk[i].bdev = bdev;
-			}
-			raid[device].disk[i].device = MKDEV(major,minor);
-			raid[device].disk[i].sectors = prom->raid.disk_secs;
-			raid[device].stride = (1<<prom->raid.raid0_shift);
-			raid[device].disks = prom->raid.total_disks;
-			raid[device].sectors = prom->raid.total_secs;
-			raid[device].geom.heads = prom->raid.heads+1;
-			raid[device].geom.sectors = prom->raid.sectors;
-			raid[device].geom.cylinders = prom->raid.cylinders+1;
-			devlist[devindex].device=device;
-        	     }
-        }
-	               
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-				
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-	}
-}
-			   
-static __init int pdcraid_init_one(int device,int raidlevel)
-{
-	int i, count;
-
-	for (i=0; i<14; i++)
-		probedisk(i, device, raidlevel);
-	
-	if (raidlevel==0)
-		fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);        
-		
-	count=0;
-	
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
-				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-}
-
-static __init int pdcraid_init(void)
-{
-	int retval, device, count = 0;
-
-	do {
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid0_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,0);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	do {
-	
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid1_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,1);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	if (count) {
-		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
-		return 0;
-	}
-	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
-	return -ENODEV;
-}
-
-static void __exit pdcraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++) {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}	
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int pdcraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int pdcraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(pdcraid_init);
-module_exit(pdcraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.h linux-2.4.21-rc3/drivers/ide/pdcraid.h
--- linux-2.4.20/drivers/ide/pdcraid.h	2001-09-18 06:23:40.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-struct promise_raid_conf {
-    char                promise_id[24];
-
-    u32             dummy_0;
-    u32             magic_0;
-    u32             dummy_1;
-    u32             magic_1;
-    u16             dummy_2;
-    u8              filler1[470];
-    struct {
-        u32 flags;                          /* 0x200 */
-        u8          dummy_0;
-        u8          disk_number;
-        u8          channel;
-        u8          device;
-        u32         magic_0;
-        u32         dummy_1;
-        u32         dummy_2;                /* 0x210 */
-        u32         disk_secs;
-        u32         dummy_3;
-        u16         dummy_4;
-        u8          status;
-        u8          type;
-        u8        total_disks;            /* 0x220 */
-        u8        raid0_shift;
-        u8        raid0_disks;
-        u8        array_number;
-        u32       total_secs;
-        u16       cylinders;
-        u8        heads;
-        u8        sectors;
-        u32         magic_1;
-        u32         dummy_5;                /* 0x230 */
-        struct {
-            u16     dummy_0;
-            u8      channel;
-            u8      device;
-            u32     magic_0;
-            u32     disk_number;
-        } disk[8];
-    } raid;
-    u32             filler2[346];
-    u32            checksum;
-};
-
-#define PR_MAGIC        "Promise Technology, Inc."
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/piix.c linux-2.4.21-rc3/drivers/ide/piix.c
--- linux-2.4.20/drivers/ide/piix.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/piix.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,542 +0,0 @@
-/*
- *  linux/drivers/ide/piix.c		Version 0.32	June 9, 2000
- *
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  PIO mode setting function for Intel chipsets.  
- *  For use instead of BIOS settings.
- *
- * 40-41
- * 42-43
- * 
- *                 41
- *                 43
- *
- * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
- * 
- * sitre = word40 & 0x4000; primary
- * sitre = word42 & 0x4000; secondary
- *
- * 44 8421|8421    hdd|hdb
- * 
- * 48 8421         hdd|hdc|hdb|hda udma enabled
- *
- *    0001         hda
- *    0010         hdb
- *    0100         hdc
- *    1000         hdd
- *
- * 4a 84|21        hdb|hda
- * 4b 84|21        hdd|hdc
- *
- *    ata-33/82371AB
- *    ata-33/82371EB
- *    ata-33/82801AB            ata-66/82801AA
- *    00|00 udma 0              00|00 reserved
- *    01|01 udma 1              01|01 udma 3
- *    10|10 udma 2              10|10 udma 4
- *    11|11 reserved            11|11 reserved
- *
- * 54 8421|8421    ata66 drive|ata66 enable
- *
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define PIIX_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_PIIX_TIMINGS
-
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int piix_get_info(char *, char **, off_t, int);
-extern int (*piix_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 piix_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-	        case PCI_DEVICE_ID_INTEL_82801CA_10:
-	        case PCI_DEVICE_ID_INTEL_82801CA_11:
-	        case PCI_DEVICE_ID_INTEL_82801DB_11:
-	        case PCI_DEVICE_ID_INTEL_82801E_11:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 66 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82371AB:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			p += sprintf(p, "\n                                Intel PIIX3 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371MX:
-			p += sprintf(p, "\n                                Intel MPIIX Chipset.\n");
-			return p-buffer;	/* => must be less than 4k! */
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		default:
-			p += sprintf(p, "\n                                Intel PIIX Chipset.\n");
-			break;
-	}
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_byte(bmide_dev, 0x55, &reg55);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	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 enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
-			((reg54&0x11) && (reg4a&0x02)) ? "4" :
-			((reg54&0x11) && (reg4a&0x01)) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" :
-			((reg54&0x22) && (reg4a&0x20)) ? "4" :
-			((reg54&0x22) && (reg4a&0x10)) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" :
-			((reg54&0x44) && (reg4b&0x02)) ? "4" :
-			((reg54&0x44) && (reg4b&0x01)) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" :
-			((reg54&0x88) && (reg4b&0x20)) ? "4" :
-			((reg54&0x88) && (reg4b&0x10)) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte piix_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-/*
- *
- */
-static byte piix_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void piix_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1])
-					   << (HWIF(drive)->index ? 4 : 0));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-static int piix_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 3 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int v_flag		= 0x01 << drive->dn;
-	int w_flag		= 0x10 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a, reg54;
-	byte			reg55;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-	pci_read_config_word(dev, 0x54, &reg54);
-	pci_read_config_byte(dev, 0x55, &reg55);
-
-	switch(speed) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if (speed == XFER_UDMA_5) {
-			pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag);
-		} else {
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-		}
-		if (!(reg4a & u_speed)) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-		if (speed > XFER_UDMA_2) {
-			if (!(reg54 & v_flag)) {
-				pci_write_config_word(dev, 0x54, reg54|v_flag);
-			}
-		} else {
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		if (reg54 & v_flag)
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		if (reg55 & w_flag)
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-	}
-
-	piix_tune_drive(drive, piix_dma_2_pio(speed));
-
-#if PIIX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* PIIX_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			speed;
-
-	byte udma_66		= eighty_ninty_three(drive);
-	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801DB_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801E_11)) ? 1 : 0;
-	int ultra66		= ((ultra100) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
-	int ultra		= ((ultra66) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82451NX) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) piix_tune_chipset(drive, speed);
-
-	return ((int)	((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);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL));
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = piix_config_drive_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = piix_config_drive_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = piix_config_drive_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!piix_proc) {
-		piix_proc = 1;
-		bmide_dev = dev;
-		piix_display_info = &piix_get_info;
-	}
-#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/*
- * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards.
- * It does not specify device detection, but channel!!!
- * You determine later if bit 13 of word93 is set...
- */
-unsigned int __init ata66_piix (ide_hwif_t *hwif)
-{
-	byte reg54h = 0, reg55h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0xc0 : 0x30;
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
-
-	ata66 = (reg54h & mask) ? 1 : 0;
-
-	return ata66;
-}
-
-void __init ide_init_piix (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_IA64
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-#endif /* CONFIG_IA64 */
-
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
-		/* This is a painful system best to let it self tune for now */
-		return;
-	}
-
-	hwif->tuneproc = &piix_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_PIIX_TUNING
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &piix_dmaproc;
-	hwif->speedproc = &piix_tune_chipset;
-#endif /* CONFIG_PIIX_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/Makefile linux-2.4.21-rc3/drivers/ide/ppc/Makefile
--- linux-2.4.20/drivers/ide/ppc/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ppc/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,13 @@
+
+O_TARGET := idedriver-ppc.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/mpc8xx.c linux-2.4.21-rc3/drivers/ide/ppc/mpc8xx.c
--- linux-2.4.20/drivers/ide/ppc/mpc8xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ppc/mpc8xx.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,857 @@
+/*
+ *  linux/drivers/ide/ppc/ide-m8xx.c
+ *
+ *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
+ *  Modified for direct IDE interface
+ *	by Thomas Lange, thomas@corelatus.com
+ *  Modified for direct IDE interface on 8xx without using the PCMCIA
+ *  controller
+ *	by Steven.Scholz@imc-berlin.de
+ *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ *	by Mathew Locke <mattl@mvista.com>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+static int identify  (volatile u8 *p);
+static void print_fixed (volatile u8 *p);
+static void print_funcid (int func);
+static int check_ide_device (unsigned long base);
+
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+
+typedef	struct ide_ioport_desc {
+	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
+	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
+	int		irq;			/* IRQ				*/
+} ide_ioport_desc_t;
+
+ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
+#ifdef IDE0_BASE_OFFSET
+	{ IDE0_BASE_OFFSET,
+	    {
+		IDE0_DATA_REG_OFFSET,
+		IDE0_ERROR_REG_OFFSET,
+		IDE0_NSECTOR_REG_OFFSET,
+		IDE0_SECTOR_REG_OFFSET,
+		IDE0_LCYL_REG_OFFSET,
+		IDE0_HCYL_REG_OFFSET,
+		IDE0_SELECT_REG_OFFSET,
+		IDE0_STATUS_REG_OFFSET,
+		IDE0_CONTROL_REG_OFFSET,
+		IDE0_IRQ_REG_OFFSET,
+	    },
+	    IDE0_INTERRUPT,
+	},
+#ifdef IDE1_BASE_OFFSET
+	{ IDE1_BASE_OFFSET,
+	    {
+		IDE1_DATA_REG_OFFSET,
+		IDE1_ERROR_REG_OFFSET,
+		IDE1_NSECTOR_REG_OFFSET,
+		IDE1_SECTOR_REG_OFFSET,
+		IDE1_LCYL_REG_OFFSET,
+		IDE1_HCYL_REG_OFFSET,
+		IDE1_SELECT_REG_OFFSET,
+		IDE1_STATUS_REG_OFFSET,
+		IDE1_CONTROL_REG_OFFSET,
+		IDE1_IRQ_REG_OFFSET,
+	    },
+	    IDE1_INTERRUPT,
+	},
+#endif /* IDE1_BASE_OFFSET */
+#endif	/* IDE0_BASE_OFFSET */
+};
+
+ide_pio_timings_t ide_pio_clocks[6];
+int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
+
+/*
+ * Warning: only 1 (ONE) PCMCIA slot supported here,
+ * which must be correctly initialized by the firmware (PPCBoot).
+ */
+static int _slot_ = -1;			/* will be read from PCMCIA registers   */
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
+
+
+
+/*
+ * IDE stuff.
+ */
+static int
+m8xx_ide_default_irq(ide_ioreg_t base)
+{
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+	if (base >= MAX_HWIFS)
+		return 0;
+
+	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
+	
+	return (ioport_dsc[base].irq);
+#else
+        return 9;
+#endif
+}
+
+static ide_ioreg_t
+m8xx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
+#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef	CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
+#endif
+
+#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
+static int pcmcia_schlvl = PCMCIA_SCHLVL;
+#endif
+
+/*
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
+ */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
+ */
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+static void
+m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
+		ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	typedef struct {
+		ulong br;
+		ulong or;
+	} pcmcia_win_t;
+	volatile pcmcia_win_t *win;
+	volatile pcmconf8xx_t *pcmp;
+
+	uint *pgcrx;
+	u32 pcmcia_phy_base;
+	u32 pcmcia_phy_end;
+	static unsigned long pcmcia_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	if (!pcmcia_base) {
+                /*
+                 * Read out PCMCIA registers. Since the reset values
+                 * are undefined, we sure hope that they have been
+                 * set up by firmware
+		 */
+
+		/* Scan all registers for valid settings */
+		pcmcia_phy_base = 0xFFFFFFFF;
+		pcmcia_phy_end = 0;
+		/* br0 is start of brX and orX regs */
+		win = (pcmcia_win_t *) \
+			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
+		for (i = 0; i < 8; i++) {
+			if (win->or & 1) {	/* This bank is marked as valid */
+				if (win->br < pcmcia_phy_base) {
+					pcmcia_phy_base = win->br;
+				}
+				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
+					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
+				}
+				/* Check which slot that has been defined */
+				_slot_ = (win->or >> 2) & 1;
+
+			}					/* Valid bank */
+			win++;
+		}						/* for */
+
+		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
+			'A' + _slot_,
+			pcmcia_phy_base, pcmcia_phy_end,
+			pcmcia_phy_end - pcmcia_phy_base);
+
+		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
+						   pcmcia_phy_end-pcmcia_phy_base);
+
+#ifdef DEBUG
+		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
+#endif
+		/* Compute clock cycles for PIO timings */
+		for (i=0; i<6; ++i) {
+			bd_t	*binfo = (bd_t *)__res;
+
+			hold_time[i]   =
+				PCMCIA_MK_CLKS (hold_time[i],
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].setup_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].active_time =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].cycle_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+						binfo->bi_busfreq);
+#if 0
+			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
+				i,
+				ide_pio_clocks[i].setup_time,
+				ide_pio_clocks[i].active_time,
+				ide_pio_clocks[i].hold_time,
+				ide_pio_clocks[i].cycle_time,
+				ide_pio_timings[i].setup_time,
+				ide_pio_timings[i].active_time,
+				ide_pio_timings[i].hold_time,
+				ide_pio_timings[i].cycle_time);
+#endif
+		}
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	if (_slot_ == -1) {
+		printk ("PCMCIA slot has not been defined! Using A as default\n");
+		_slot_ = 0;
+	}
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#ifdef DEBUG
+	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
+		pcmp->pcmc_pipr,
+		'A' + _slot_,
+		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
+#endif /* DEBUG */
+
+	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
+		printk ("No card in slot %c: PIPR=%08x\n",
+			'A' + _slot_, (u32) pcmp->pcmc_pipr);
+		return;		/* No card in slot */
+	}
+
+	check_ide_device (pcmcia_base);
+
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	base = pcmcia_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+			pcmcia_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		unsigned int reg;
+
+		*irq = ioport_dsc[data_port].irq;
+		if (_slot_)
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
+		else
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
+
+		reg = *pgcrx;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
+		*pgcrx = reg;
+#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
+		*irq = ioport_dsc[data_port].irq;
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+					(0x80000000 >> ioport_dsc[data_port].irq);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	/* Make sure we dont get garbage irq */
+	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
+
+	/* Enable falling edge irq */
+	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
+#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
+ * MPC8xx's internal PCMCIA interface
+ */
+#if defined(CONFIG_IDE_EXT_DIRECT)
+void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	u32 ide_phy_base;
+	u32 ide_phy_end;
+	static unsigned long ide_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	if (!ide_base) {
+
+		/* TODO:
+		 * - add code to read ORx, BRx
+		 */
+		ide_phy_base = CFG_ATA_BASE_ADDR;
+		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
+
+		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
+			ide_phy_base, ide_phy_end,
+			ide_phy_end - ide_phy_base);
+		
+		ide_base=(unsigned long)ioremap(ide_phy_base,
+						ide_phy_end-ide_phy_base);
+
+#ifdef DEBUG
+		printk ("IDE virt base: %08lx\n", ide_base);
+#endif
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	base = ide_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+		ide_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+		/* direct connected IDE drive, i.e. external IRQ */
+		*irq = ioport_dsc[data_port].irq;
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
+			(0x80000000 >> ioport_dsc[data_port].irq);
+}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+
+/* -------------------------------------------------------------------- */
+
+
+/* PCMCIA Timing */
+#ifndef	PCMCIA_SHT
+#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
+#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
+#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
+#endif
+
+
+/* Calculate PIO timings */
+static void
+m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	volatile pcmconf8xx_t	*pcmp;
+	ulong timing, mask, reg;
+#endif
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+#if 1
+	printk("%s[%d] %s: best PIO mode: %d\n",
+		__FILE__,__LINE__,__FUNCTION__, pio);
+#endif
+
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+	timing  = PCMCIA_SHT(hold_time[pio]  )
+		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
+		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
+		;
+
+#if 1
+	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
+#endif
+	if ((reg = pcmp->pcmc_por0 & mask) != 0)
+		pcmp->pcmc_por0 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por1 & mask) != 0)
+		pcmp->pcmc_por1 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por2 & mask) != 0)
+		pcmp->pcmc_por2 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por3 & mask) != 0)
+		pcmp->pcmc_por3 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por4 & mask) != 0)
+		pcmp->pcmc_por4 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por5 & mask) != 0)
+		pcmp->pcmc_por5 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por6 & mask) != 0)
+		pcmp->pcmc_por6 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por7 & mask) != 0)
+		pcmp->pcmc_por7 = reg | timing;
+
+#elif defined(CONFIG_IDE_EXT_DIRECT)
+
+	printk("%s[%d] %s: not implemented yet!\n",
+		__FILE__,__LINE__,__FUNCTION__);
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
+}
+
+static void
+ide_interrupt_ack (void *dev)
+{
+#ifdef CONFIG_IDE_8xx_PCCARD
+	u_int pscr, pipr;
+
+#if (PCMCIA_SOCKETS_NO == 2)
+	u_int _slot_;
+#endif
+
+	/* get interrupt sources */
+
+	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+
+	/*
+	 * report only if both card detect signals are the same
+	 * not too nice done,
+	 * we depend on that CD2 is the bit to the left of CD1...
+	 */
+
+	if(_slot_==-1){
+	  printk("PCMCIA slot has not been defined! Using A as default\n");
+	  _slot_=0;
+	}
+
+	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
+	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
+	  printk ("card detect interrupt\n");
+	}
+	/* clear the interrupt sources */
+	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
+
+#else /* ! CONFIG_IDE_8xx_PCCARD */
+	/*
+	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
+	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
+	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
+	 * The interrupt is handled somewhere else.	-- Steven
+	 */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+}
+
+
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE	0x01
+
+#define CISTPL_FUNCE_IDE_IFACE	0x01
+#define CISTPL_FUNCE_IDE_MASTER	0x02
+#define CISTPL_FUNCE_IDE_SLAVE	0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON	0x04
+#define CISTPL_IDE_UNIQUE	0x08
+#define CISTPL_IDE_DUAL		0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP	0x01
+#define CISTPL_IDE_HAS_STANDBY	0x02
+#define CISTPL_IDE_HAS_IDLE	0x04
+#define CISTPL_IDE_LOW_POWER	0x08
+#define CISTPL_IDE_REG_INHIBIT	0x10
+#define CISTPL_IDE_HAS_INDEX	0x20
+#define CISTPL_IDE_IOIS16	0x40
+
+
+/* -------------------------------------------------------------------- */
+
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (unsigned long base)
+{
+	volatile u8 *ident = NULL;
+	volatile u8 *feature_p[MAX_FEATURES];
+	volatile u8 *p, *start;
+	int n_features = 0;
+	u8 func_id = ~0;
+	u8 code, len;
+	unsigned short config_base = 0;
+	int found = 0;
+	int i;
+
+#ifdef DEBUG
+	printk ("PCMCIA MEM: %08lX\n", base);
+#endif
+	start = p = (volatile u8 *) base;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#ifdef	DEBUG_PCMCIA
+		{ volatile u8 *q = p;
+			printk ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printk (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG_PCMCIA */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			func_id = *p;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((u8)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printk ("unknown card type\n");
+		return (1);
+	}
+
+	/* set level mode irq and I/O mapped device in config reg*/
+	*((u8 *)(base + config_base)) = 0x41;
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_funcid (int func)
+{
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		printk (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		printk (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		printk (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		printk (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		printk (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		printk (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		printk (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		printk (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		printk (" SCSI Adapter");
+		break;
+	default:
+		printk (" Unknown");
+		break;
+	}
+	printk (" Card\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_fixed (volatile u8 *p)
+{
+	if (p == NULL)
+		return;
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   u8 iface = *(p+2);
+
+		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		printk (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   u8 f1 = *(p+2);
+		u8 f2 = *(p+4);
+
+		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			printk (" [unique]");
+
+		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			printk (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			printk (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			printk (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			printk (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			printk (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			printk (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			printk (" [IOis16]");
+
+		break;
+	    }
+	}
+	printk ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static u8 *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile u8 *p)
+{
+	u8 id_str[MAX_IDENT_CHARS];
+	u8 data;
+	u8 *t;
+	u8 **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	printk ("Card ID: %s\n", id_str);
+
+	for (card=known_cards; *card; ++card) {
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+
+void m8xx_ide_init(void)
+{
+	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
+	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/pmac.c linux-2.4.21-rc3/drivers/ide/ppc/pmac.c
--- linux-2.4.20/drivers/ide/ppc/pmac.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ppc/pmac.c	2003-05-22 22:06:50.000000000 +0000
@@ -0,0 +1,2100 @@
+/*
+ * linux/drivers/ide/ppc/pmac.c
+ *
+ * Support for IDE interfaces on PowerMacs.
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+ * for doing DMA.
+ *
+ *  Copyright (C) 1998-2002 Paul Mackerras & Ben. Herrenschmidt
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ * Some code taken from drivers/ide/ide-dma.c:
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/ide.h>
+#include <asm/mediabay.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#include "ide_modes.h"
+#include "ide-timing.h"
+
+extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+
+#undef IDE_PMAC_DEBUG
+#define DMA_WAIT_TIMEOUT	500
+
+typedef struct pmac_ide_hwif {
+	ide_ioreg_t			regbase;
+	unsigned long			mapbase;
+	int				irq;
+	int				kind;
+	int				aapl_bus_id;
+	int				cable_80;
+	struct device_node*		node;
+	u32				timings[4];
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
+	volatile struct dbdma_regs*	dma_regs;
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
+#endif
+	
+} pmac_ide_hwif_t;
+
+static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata;
+static int pmac_ide_count;
+
+enum {
+	controller_ohare,	/* OHare based */
+	controller_heathrow,	/* Heathrow/Paddington */
+	controller_kl_ata3,	/* KeyLargo ATA-3 */
+	controller_kl_ata4,	/* KeyLargo ATA-4 */
+	controller_un_ata6	/* UniNorth2 ATA-6 */
+};
+
+static const char* model_name[] = {
+	"OHare ATA",	/* OHare based */
+	"Heathrow ATA",	/* Heathrow/Paddington */
+	"KeyLargo ATA-3",	/* KeyLargo ATA-3 */
+	"KeyLargo ATA-4",	/* KeyLargo ATA-4 */
+	"UniNorth ATA-6"	/* UniNorth2 ATA-6 */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/* Kauai (U2) ATA has different register setup */
+#define IDE_KAUAI_PIO_CONFIG	0x200
+#define IDE_KAUAI_ULTRA_CONFIG	0x210
+#define IDE_KAUAI_POLL_CONFIG	0x220
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
+#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
+
+/* 100Mhz cell, found in Uninorth 2. I don't have much infos about
+ * this one yet, it appears as a pci device (106b/0033) on uninorth
+ * internal PCI bus and it's clock is controlled like gem or fw. It
+ * appears to be an evolution of keylargo ATA4 with a timing register
+ * extended to 2 32bits registers and a similar DBDMA channel. Other
+ * registers seem to exist but I can't tell much about them.
+ * 
+ * So far, I'm using pre-calculated tables for this extracted from
+ * the values used by the MacOS X driver.
+ * 
+ * The "PIO" register controls PIO and MDMA timings, the "ULTRA"
+ * register controls the UDMA timings. At least, it seems bit 0
+ * of this one enables UDMA vs. MDMA, and bits 4..7 are the
+ * cycle time in units of 10ns. Bits 8..15 are used by I don't
+ * know their meaning yet
+ */
+#define TR_100_PIOREG_PIO_MASK		0xff000fff
+#define TR_100_PIOREG_MDMA_MASK		0x00fff000
+#define TR_100_UDMAREG_UDMA_MASK	0x0000ffff
+#define TR_100_UDMAREG_UDMA_EN		0x00000001
+
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ * 
+ * 3 Values can be programmed:
+ *  - Write data setup, which appears to match the cycle time. They
+ *    also call it DIOW setup.
+ *  - Ready to pause time (from spec)
+ *  - Address setup. That one is weird. I don't see where exactly
+ *    it fits in UDMA cycles, I got it's name from an obscure piece
+ *    of commented out code in Darwin. They leave it to 0, we do as
+ *    well, despite a comment that would lead to think it has a
+ *    min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads.
+ */
+#define TR_66_UDMA_MASK			0xfff00000
+#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT	29
+#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT	25
+#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT	21
+#define TR_66_MDMA_MASK			0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT	15
+#define TR_66_MDMA_ACCESS_MASK		0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT		10
+#define TR_66_PIO_MASK			0x000003ff
+#define TR_66_PIO_RECOVERY_MASK		0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT	5
+#define TR_66_PIO_ACCESS_MASK		0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT		0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ * 
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK			0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT	16
+#define TR_33_MDMA_ACCESS_MASK		0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT		11
+#define TR_33_MDMA_HALFTICK		0x00200000
+#define TR_33_PIO_MASK			0x000007ff
+#define TR_33_PIO_E			0x00000400
+#define TR_33_PIO_RECOVERY_MASK		0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT	5
+#define TR_33_PIO_ACCESS_MASK		0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT		0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/* Rounded Multiword DMA timings
+ * 
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
+	int	accessTime;
+	int	recoveryTime;
+	int	cycleTime;
+};
+
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  75,  75, 150 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 150, 150, 300 },
+    { 120, 120, 240 },
+    {  90, 120, 210 },
+    {  90,  90, 180 },
+    {  90,  60, 150 },
+    {  90,  30, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  90,  75, 165 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+/* KeyLargo ATA-4 Ultra DMA timings (rounded) */
+struct {
+	int	addrSetup; /* ??? */
+	int	rdy2pause;
+	int	wrDataSetup;
+} kl66_udma_timings[] __pmacdata =
+{
+    {   0, 180,  120 },	/* Mode 0 */
+    {   0, 150,  90 },	/*      1 */
+    {   0, 120,  60 },	/*      2 */
+    {   0, 90,   45 },	/*      3 */
+    {   0, 90,   30 }	/*      4 */
+};
+
+/* UniNorth 2 ATA/100 timings */
+struct kauai_timing {
+	int	cycle_time;
+	u32	timing_reg;
+};
+
+static struct kauai_timing	kauai_pio_timings[] __pmacdata =
+{
+	{ 930	, 0x08000fff },
+	{ 600	, 0x08000a92 },
+	{ 383	, 0x0800060f },
+	{ 360	, 0x08000492 },
+	{ 330	, 0x0800048f },
+	{ 300	, 0x080003cf },
+	{ 270	, 0x080003cc },
+	{ 240	, 0x0800038b },
+	{ 239	, 0x0800030c },
+	{ 180	, 0x05000249 },
+	{ 120	, 0x04000148 }
+};
+
+static struct kauai_timing	kauai_mdma_timings[] __pmacdata =
+{
+	{ 1260	, 0x00fff000 },
+	{ 480	, 0x00618000 },
+	{ 360	, 0x00492000 },
+	{ 270	, 0x0038e000 },
+	{ 240	, 0x0030c000 },
+	{ 210	, 0x002cb000 },
+	{ 180	, 0x00249000 },
+	{ 150	, 0x00209000 },
+	{ 120	, 0x00148000 },
+	{ 0	, 0 },
+};
+
+static struct kauai_timing	kauai_udma_timings[] __pmacdata =
+{
+	{ 120	, 0x000070c0 },
+	{ 90	, 0x00005d80 },
+	{ 60	, 0x00004a60 },
+	{ 45	, 0x00003a50 },
+	{ 30	, 0x00002a30 },
+	{ 20	, 0x00002921 },
+	{ 0	, 0 },
+};
+
+static inline u32
+kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
+{
+	int i;
+	
+	for (i=0; table[i].cycle_time; i++)
+		if (cycle_time > table[i+1].cycle_time)
+			return table[i].timing_reg;
+	return 0;
+}
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS		256
+
+/* Wait 2s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ *       
+ * NOTE2: This has to be fixed with a BSY wait loop. I'm working on adding
+ *        that to the generic probe code.
+ */
+#define IDE_WAKEUP_DELAY_MS	2000
+
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq, int ddir);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
+static int pmac_ide_dma_begin (ide_drive_t *drive);
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+#ifdef CONFIG_PMAC_PBOOK
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * N.B. this can't be an initfunc, because the media-bay task can
+ * call ide_[un]register at any time.
+ */
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
+			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
+			      int *irq)
+{
+	int i, ix;
+
+	if (data_port == 0)
+		return;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (data_port == pmac_ide[ix].regbase)
+			break;
+
+	if (ix >= MAX_HWIFS) {
+		/* Probably a PCI interface... */
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+		return;
+	}
+
+	for (i = 0; i < 8; ++i)
+		hw->io_ports[i] = data_port + i * 0x10;
+	hw->io_ports[8] = data_port + 0x160;
+
+	if (irq != NULL)
+		*irq = pmac_ide[ix].irq;
+}
+
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void __pmac
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (drive->select.b.unit & 0x01)
+		writel(pmif->timings[1],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	else
+		writel(pmif->timings[0],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+}
+
+static void __pmac
+pmac_ide_kauai_selectproc(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (drive->select.b.unit & 0x01) {
+		writel(pmif->timings[1],
+		       (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG));
+		writel(pmif->timings[3],
+		       (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG));
+	} else {
+		writel(pmif->timings[0],
+		       (unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG));
+		writel(pmif->timings[2],
+		       (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG));
+	}
+	(void)readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG));
+}
+
+static void __pmac
+pmac_ide_do_update_timings(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (pmif->kind == controller_un_ata6)
+		pmac_ide_kauai_selectproc(drive);
+	else
+		pmac_ide_selectproc(drive);
+}
+
+static void
+pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
+{
+	u32 tmp;
+	
+	writeb(value, port);	
+	tmp = readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+}
+
+static int __pmac
+pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int result = 1;
+	
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	/* Get rid of pending error state */
+	(void)hwif->INB(IDE_STATUS_REG);
+	/* Timeout bumped for some powerbooks */
+	if (wait_for_ready(drive, 2000)) {
+		/* Timeout bumped for some powerbooks */
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"before SET_FEATURE!\n");
+		goto out;
+	}
+	udelay(10);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(command, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	udelay(1);
+	/* Timeout bumped for some powerbooks */
+	result = wait_for_ready(drive, 2000);
+	hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (result)
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"after SET_FEATURE !\n");
+out:
+	SELECT_MASK(drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:
+				drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:
+				drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:
+				drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:
+				drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:
+				drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:
+				drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:
+				drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:
+				drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2:
+				drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1:
+				drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0:
+				drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2:
+				drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1:
+				drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0:
+				drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
+	enable_irq(hwif->irq);
+	return result;
+}
+
+/* Calculate PIO timings */
+static void __pmac
+pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	u32 *timings;
+	unsigned accessTicks, recTicks;
+	unsigned accessTime, recTime;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	
+	if (pmif == NULL)
+		return;
+		
+	/* which drive is it ? */
+	timings = &pmif->timings[drive->select.b.unit & 0x01];
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+	switch (pmif->kind) {
+	case controller_un_ata6: {
+		/* 100Mhz cell */
+		u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
+		if (tr == 0)
+			return;
+		*timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
+		break;
+		}
+	case controller_kl_ata4:
+		/* 66Mhz cell */
+		recTime = d.cycle_time - ide_pio_timings[pio].active_time
+				- ide_pio_timings[pio].setup_time;
+		recTime = max(recTime, 150U);
+		accessTime = ide_pio_timings[pio].active_time;
+		accessTime = max(accessTime, 150U);
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_66_PIO_MASK) |
+				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
+		break;
+	default: {
+		/* 33Mhz cell */
+		int ebit = 0;
+		recTime = d.cycle_time - ide_pio_timings[pio].active_time
+				- ide_pio_timings[pio].setup_time;
+		recTime = max(recTime, 150U);
+		accessTime = ide_pio_timings[pio].active_time;
+		accessTime = max(accessTime, 150U);
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 4U);
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 5U) - 4;
+		if (recTicks > 9) {
+			recTicks--; /* guess, but it's only for PIO0, so... */
+			ebit = 1;
+		}
+		*timings = ((*timings) & ~TR_33_PIO_MASK) |
+				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
+		if (ebit)
+			*timings |= TR_33_PIO_E;
+		break;
+		}
+	}
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+		pio,  *timings);
+#endif	
+
+	if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+		pmac_ide_do_update_timings(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+static int __pmac
+set_timings_udma_ata4(u32 *timings, u8 speed)
+{
+	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
+
+	if (speed > XFER_UDMA_4)
+		return 1;
+
+	rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause);
+	wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup);
+	addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup);
+
+	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
+			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+			TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+
+	return 0;
+}
+
+static int __pmac
+set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
+{
+	struct ide_timing *t = ide_timing_find_mode(speed);
+	u32 tr;
+
+	if (speed > XFER_UDMA_5 || t == NULL)
+		return 1;
+	tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
+	if (tr == 0)
+		return 1;
+	*ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
+	*ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
+
+	return 0;
+}
+
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, u32 *timings2, u8 speed, int drive_cycle_time)
+{
+	int cycleTime, accessTime, recTime;
+	unsigned accessTicks, recTicks;
+	struct mdma_timings_t* tm = NULL;
+	int i;
+
+	/* Get default cycle time for mode */
+	switch(speed & 0xf) {
+		case 0: cycleTime = 480; break;
+		case 1: cycleTime = 150; break;
+		case 2: cycleTime = 120; break;
+		default:
+			return 1;
+	}
+	/* Adjust for drive */
+	if (drive_cycle_time && drive_cycle_time > cycleTime)
+		cycleTime = drive_cycle_time;
+	/* OHare limits according to some old Apple sources */	
+	if ((intf_type == controller_ohare) && (cycleTime < 150))
+		cycleTime = 150;
+	/* Get the proper timing array for this controller */
+	switch(intf_type) {
+		case controller_un_ata6:
+			break;
+		case controller_kl_ata4:
+			tm = mdma_timings_66;
+			break;
+		case controller_kl_ata3:
+			tm = mdma_timings_33k;
+			break;
+		default:
+			tm = mdma_timings_33;
+			break;
+	}
+	if (tm != NULL) {
+		/* Lookup matching access & recovery times */
+		i = -1;
+		for (;;) {
+			if (tm[i+1].cycleTime < cycleTime)
+				break;
+			i++;
+		}
+		if (i < 0)
+			return 1;
+		cycleTime = tm[i].cycleTime;
+		accessTime = tm[i].accessTime;
+		recTime = tm[i].recoveryTime;
+
+#ifdef IDE_PMAC_DEBUG
+		printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+			cycleTime, accessTime, recTime);
+#endif
+	}
+	switch(intf_type) {
+	case controller_un_ata6: {
+		/* 100Mhz cell */
+		u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
+		if (tr == 0)
+			return 1;
+		*timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
+		*timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
+		}
+		break;
+	case controller_kl_ata4:
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 0x1U);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 0x3U);
+		/* Clear out mdma bits and disable udma */
+		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+		break;
+	case controller_kl_ata3:
+		/* 33Mhz cell on KeyLargo */
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 1U);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		break;
+	default: {
+		/* 33Mhz cell on others */
+		int halfTick = 0;
+		int origAccessTime = accessTime;
+		int origRecTime = recTime;
+		
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 2U) - 1;
+		recTicks = min(recTicks, 0x1fU);
+		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+		if ((accessTicks > 1) &&
+		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+            		halfTick = 1;
+			accessTicks--;
+		}
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		if (halfTick)
+			*timings |= TR_33_MDMA_HALFTICK;
+		}
+	}
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+	return 0;
+}
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/* You may notice we don't use this function on normal operation,
+ * our, normal mdma function is supposed to be more precise
+ */
+static int __pmac
+pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	int unit = (drive->select.b.unit & 0x01);
+	int ret = 0;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings, *timings2;
+
+	if (pmif == NULL)
+		return 1;
+		
+	timings = &pmif->timings[unit];
+	timings2 = &pmif->timings[unit+2];
+	
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		case XFER_UDMA_5:
+			if (pmif->kind != controller_un_ata6)
+				return 1;
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+			if (HWIF(drive)->udma_four == 0)
+				return 1;		
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (pmif->kind == controller_kl_ata4)
+				ret = set_timings_udma_ata4(timings, speed);
+			else if (pmif->kind == controller_un_ata6)
+				ret = set_timings_udma_ata6(timings, timings2, speed);
+			else
+				ret = 1;		
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			ret = set_timings_mdma(pmif->kind, timings, timings2, speed, 0);
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			return 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pmac_ide_tuneproc(drive, speed & 0x07);
+			break;
+		default:
+			ret = 1;
+	}
+	if (ret)
+		return ret;
+
+	ret = pmac_ide_do_setfeature(drive, speed);
+	if (ret)
+		return ret;
+		
+	pmac_ide_do_update_timings(drive);	
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+static void __pmac
+sanitize_timings(pmac_ide_hwif_t *pmif)
+{
+	unsigned int value, value2 = 0;
+	
+	switch(pmif->kind) {
+		case controller_un_ata6:
+			value = 0x08618a92;
+			value2 = 0x00002921;
+			break;
+		case controller_kl_ata4:
+			value = 0x0008438c;
+			break;
+		case controller_kl_ata3:
+			value = 0x00084526;
+			break;
+		case controller_heathrow:
+		case controller_ohare:
+		default:
+			value = 0x00074526;
+			break;
+	}
+	pmif->timings[0] = pmif->timings[1] = value;
+	pmif->timings[2] = pmif->timings[3] = value2;
+}
+
+ide_ioreg_t __pmac
+pmac_ide_get_base(int index)
+{
+	return pmac_ide[index].regbase;
+}
+
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+	int ix;
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return ix;
+	return -1;
+}
+
+struct device_node*
+pmac_ide_get_of_node(int index)
+{
+	/* Don't access the pmac_ide array on non-pmac */
+	if (pmac_ide_count == 0)
+		return NULL;
+	if (pmac_ide[index].regbase == 0)
+		return NULL;
+	return pmac_ide[index].node;
+}
+
+int __pmac
+pmac_ide_get_irq(ide_ioreg_t base)
+{
+	int ix;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return pmac_ide[ix].irq;
+	return 0;
+}
+
+static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
+
+kdev_t __init
+pmac_find_ide_boot(char *bootdevice, int n)
+{
+	int i;
+	
+	/*
+	 * Look through the list of IDE interfaces for this one.
+	 */
+	for (i = 0; i < pmac_ide_count; ++i) {
+		char *name;
+		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+			continue;
+		name = pmac_ide[i].node->full_name;
+		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+			/* XXX should cope with the 2nd drive as well... */
+			return MKDEV(ide_majors[i], 0);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_ide_probe(void)
+{
+	struct device_node *np;
+	int i;
+	struct device_node *atas;
+	struct device_node *p, **pp, *removables, **rp;
+	unsigned long base, regbase;
+	int irq, big_delay;
+	ide_hwif_t *hwif;
+
+	if (_machine != _MACH_Pmac)
+		return;
+	pp = &atas;
+	rp = &removables;
+	p = find_devices("ATA");
+	if (p == NULL)
+		p = find_devices("IDE");
+	if (p == NULL)
+		p = find_type_devices("ide");
+	if (p == NULL)
+		p = find_type_devices("ata");
+	/* Move removable devices such as the media-bay CDROM
+	   on the PB3400 to the end of the list. */
+	for (; p != NULL; p = p->next) {
+		if (p->parent && p->parent->type
+		    && strcasecmp(p->parent->type, "media-bay") == 0) {
+			*rp = p;
+			rp = &p->next;
+		} else {
+			*pp = p;
+			pp = &p->next;
+		}
+	}
+	*rp = NULL;
+	*pp = removables;
+	big_delay = 0;
+
+	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+		struct device_node *tp;
+		struct pmac_ide_hwif* pmif;
+		int *bidp;
+		int in_bay = 0;
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
+
+		/*
+		 * If this node is not under a mac-io or dbdma node,
+		 * leave it to the generic PCI driver. Except for U2's
+		 * Kauai ATA
+		 */
+		if (!device_is_compatible(np, "kauai-ata")) {
+			for (tp = np->parent; tp != 0; tp = tp->parent)
+				if (tp->type && (strcmp(tp->type, "mac-io") == 0
+						 || strcmp(tp->type, "dbdma") == 0))
+					break;
+			if (tp == 0)
+				continue;
+
+			if (np->n_addrs == 0) {
+				printk(KERN_WARNING "ide-pmac: no address for device %s\n",
+				       np->full_name);
+				continue;
+			}
+			/* We need to find the pci_dev of the mac-io holding the
+			 * IDE interface
+			 */
+			if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+				pdev = pci_find_slot(pbus, pid);
+
+			if (pdev == NULL)
+				printk(KERN_WARNING "ide-pmac: no PCI host for device %s, DMA disabled\n",
+				       np->full_name);
+			/*
+			 * Some older OFs have bogus sizes, causing request_OF_resource
+			 * to fail. We fix them up here
+			 */
+			if (np->addrs[0].size > 0x1000)
+				np->addrs[0].size = 0x1000;
+			if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+				np->addrs[1].size = 0x100;
+
+			if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+				printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+				continue;
+			}
+
+			base =  (unsigned long) ioremap(np->addrs[0].address, 0x400);
+			regbase = base;
+			
+			/* XXX This is bogus. Should be fixed in the registry by checking
+			   the kind of host interrupt controller, a bit like gatwick
+			   fixes in irq.c
+			 */
+			if (np->n_intrs == 0) {
+				printk(KERN_WARNING "ide-pmac: no intrs for device %s, using 13\n",
+				       np->full_name);
+				irq = 13;
+			} else {
+				irq = np->intrs[0].line;
+			}
+		} else {
+			unsigned long rbase, rlen;
+
+			if (pci_device_from_OF_node(np, &pbus, &pid) == 0)
+				pdev = pci_find_slot(pbus, pid);
+			if (pdev == NULL) {
+				printk(KERN_WARNING "ide-pmac: no PCI host for device %s, skipping\n",
+				       np->full_name);
+				continue;
+			}
+			if (pci_enable_device(pdev)) {
+				printk(KERN_WARNING "ide-pmac: Can't enable PCI device for %s, skipping\n",
+				       np->full_name);
+				continue;
+			}
+			pci_set_master(pdev);
+			
+			if (pci_request_regions(pdev, "U2 IDE")) {
+				printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources\n");
+				continue;
+			}
+
+			rbase = pci_resource_start(pdev, 0);
+			rlen = pci_resource_len(pdev, 0);
+
+			base = (unsigned long) ioremap(rbase, rlen);
+			regbase = base + 0x2000;
+
+			irq = pdev->irq;
+		}
+
+		/*
+		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
+		 */
+		while (i < MAX_HWIFS
+		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
+			++i;
+		if (i >= MAX_HWIFS)
+			break;
+		pmif = &pmac_ide[i];
+
+		pmif->mapbase = base;
+		pmif->regbase = regbase;
+		pmif->irq = irq;
+		pmif->node = np;
+		pmif->cable_80 = 0;
+		if (device_is_compatible(np, "kauai-ata")) {
+			pmif->kind = controller_un_ata6;
+			pci_set_drvdata(pdev, pmif);
+		} else if (device_is_compatible(np, "keylargo-ata")) {
+			if (strcmp(np->name, "ata-4") == 0)
+				pmif->kind = controller_kl_ata4;
+			else
+				pmif->kind = controller_kl_ata3;
+		} else if (device_is_compatible(np, "heathrow-ata"))
+			pmif->kind = controller_heathrow;
+		else
+			pmif->kind = controller_ohare;
+
+		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+
+		/* Get cable type from device-tree */
+		if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) {
+			char* cable = get_property(np, "cable-type", NULL);
+			if (cable && !strncmp(cable, "80-", 3))
+				pmif->cable_80 = 1;
+		}
+
+		/* Make sure we have sane timings */
+		sanitize_timings(pmif);
+
+		if (np->parent && np->parent->name
+		    && strcasecmp(np->parent->name, "media-bay") == 0) {
+#ifdef CONFIG_PMAC_PBOOK
+			media_bay_set_ide_infos(np->parent,regbase,irq,i);
+#endif /* CONFIG_PMAC_PBOOK */
+			in_bay = 1;
+			if (!bidp)
+				pmif->aapl_bus_id = 1;
+		} else if (pmif->kind == controller_ohare) {
+			/* The code below is having trouble on some ohare machines
+			 * (timing related ?). Until I can put my hand on one of these
+			 * units, I keep the old way
+			 */
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
+		} else {
+ 			/* This is necessary to enable IDE when net-booting */
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+			mdelay(10);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+			big_delay = 1;
+		}
+
+		hwif = &ide_hwifs[i];
+		/* Setup MMIO ops */
+		default_hwif_mmiops(hwif);
+		hwif->OUTBSYNC = pmac_outbsync;
+		/* Tell common code _not_ to mess with resources */
+		hwif->mmio = 2;
+		hwif->hwif_data = pmif;
+		pmac_ide_init_hwif_ports(&hwif->hw, regbase, 0, &hwif->irq);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->chipset = ide_pmac;
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = pmif->cable_80;
+		hwif->pci_dev = pdev;
+		hwif->drives[0].unmask = 1;
+		hwif->drives[1].unmask = 1;
+		hwif->tuneproc = pmac_ide_tuneproc;
+		if (pmif->kind == controller_un_ata6)
+			hwif->selectproc = pmac_ide_kauai_selectproc;
+		else
+			hwif->selectproc = pmac_ide_selectproc;
+		hwif->speedproc = pmac_ide_tune_chipset;
+
+		printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s\n",
+			i, model_name[pmif->kind], pmif->aapl_bus_id,
+			in_bay ? " (mediabay)" : "");
+			
+#ifdef CONFIG_PMAC_PBOOK
+		if (in_bay && check_media_bay_by_base(regbase, MB_CD) == 0)
+			hwif->noprobe = 0;
+#endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		if (np->n_addrs >= 2 || pmif->kind == controller_un_ata6) {
+			/* has a DBDMA controller channel */
+			pmac_ide_setup_dma(np, i);
+		}
+		hwif->atapi_dma = 1;
+		switch(pmif->kind) {
+			case controller_un_ata6:
+				hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
+				hwif->mwdma_mask = 0x07;
+				hwif->swdma_mask = 0x00;
+				break;
+			case controller_kl_ata4:
+				hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07;
+				hwif->mwdma_mask = 0x07;
+				hwif->swdma_mask = 0x00;
+				break;
+			default:
+				hwif->ultra_mask = 0x00;
+				hwif->mwdma_mask = 0x07;
+				hwif->swdma_mask = 0x00;
+				break;
+		}	
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+		++i;
+	}
+	pmac_ide_count = i;
+
+	if (pmac_ide_count == 0)
+		return;
+		
+	if (big_delay)
+		mdelay(IDE_WAKEUP_DELAY_MS);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+static int __pmac
+pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq, int data_dir)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct buffer_head *bh;
+	struct scatterlist *sg = pmif->sg_table;
+	unsigned long lastdataend = ~0UL;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	pmif->sg_dma_direction = data_dir;
+
+	bh = rq->bh;
+	do {
+		int contig = 0;
+
+		if (bh->b_page) {
+			if (bh_phys(bh) == lastdataend)
+				contig = 1;
+		} else {
+			if ((unsigned long) bh->b_data == lastdataend)
+				contig = 1;
+		}
+
+		if (contig) {
+			sg[nents - 1].length += bh->b_size;
+			lastdataend += bh->b_size;
+			continue;
+		}
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		memset(&sg[nents], 0, sizeof(*sg));
+
+		if (bh->b_page) {
+			sg[nents].page = bh->b_page;
+			sg[nents].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
+		} else {
+			if ((unsigned long) bh->b_data < PAGE_SIZE)
+				BUG();
+
+			sg[nents].address = bh->b_data;
+			lastdataend = (unsigned long) bh->b_data + bh->b_size;
+		}
+
+		sg[nents].length = bh->b_size;
+		nents++;
+	} while ((bh = bh->b_reqnext) != NULL);
+
+	if(nents == 0)
+		BUG();
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, data_dir);
+}
+
+static int  __pmac
+pmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	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++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int __pmac
+pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq, int ddir)
+{
+	struct dbdma_cmd *table;
+	int i, count = 0;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	volatile struct dbdma_regs *dma = pmif->dma_regs;
+	struct scatterlist *sg;
+
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmif->dma_table_cpu;
+
+	/* Make sure DMA controller is stopped (necessary ?) */
+	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
+	while (readl(&dma->status) & RUN)
+		udelay(1);
+
+	/* Build sglist */
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq);
+	else
+		pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq, ddir);
+	if (!i)
+		return 0;
+
+	/* Build DBDMA commands list */
+	sg = pmif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+			if (++count >= MAX_DCMDS) {
+				printk(KERN_WARNING "%s: DMA table too small\n",
+				       drive->name);
+				goto use_pio_instead;
+			}
+			st_le16(&table->command,
+				(ddir == PCI_DMA_TODEVICE) ? OUTPUT_MORE: INPUT_MORE);
+			st_le16(&table->req_count, tc);
+			st_le32(&table->phy_addr, cur_addr);
+			table->cmd_dep = 0;
+			table->xfer_status = 0;
+			table->res_count = 0;
+			cur_addr += tc;
+			cur_len -= tc;
+			++table;
+		}
+		sg++;
+		i--;
+	}
+
+	/* convert the last command to an input/output last command */
+	if (count) {
+		st_le16(&table[-1].command,
+			(ddir == PCI_DMA_TODEVICE) ? OUTPUT_LAST: INPUT_LAST);
+		/* add the stop command to the end of the list */
+		memset(table, 0, sizeof(struct dbdma_cmd));
+		st_le16(&table->command, DBDMA_STOP);
+		mb();
+		writel(pmif->dma_table_dma, &dma->cmdptr);
+		return 1;
+	}
+
+	printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+ use_pio_instead:
+	pci_unmap_sg(hwif->pci_dev,
+		     pmif->sg_table,
+		     pmif->sg_nents,
+		     pmif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
+	return 0; /* revert to PIO for this request */
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void __pmac
+pmac_ide_destroy_dmatable (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = pmif->sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction);
+		pmif->sg_nents = 0;
+		HWIF(drive)->sg_dma_active = 0;
+	}
+}
+
+/* Calculate MultiWord DMA timings */
+static int __pmac
+pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	int drive_cycle_time;
+	struct hd_driveid *id = drive->id;
+	u32 *timings, *timings2;
+	u32 timing_local[2];
+	int ret;
+
+	/* which drive is it ? */
+	timings = &pmif->timings[drive->select.b.unit & 0x01];
+	timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
+
+	/* Check if drive provide explicit cycle time */
+	if ((id->field_valid & 2) && (id->eide_dma_time))
+		drive_cycle_time = id->eide_dma_time;
+	else
+		drive_cycle_time = 0;
+
+	/* Copy timings to local image */
+	timing_local[0] = *timings;
+	timing_local[1] = *timings2;
+
+	/* Calculate controller timings */
+	ret = set_timings_mdma(	pmif->kind,
+				&timing_local[0],
+				&timing_local[1],
+				mode,
+				drive_cycle_time);
+	if (ret)
+		return 0;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf);
+	ret = pmac_ide_do_setfeature(drive, mode);
+	if (ret) {
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
+	    	return 0;
+	}
+
+	/* Apply timings to controller */
+	*timings = timing_local[0];
+	*timings2 = timing_local[1];
+	
+	/* Set speed info in drive */
+	drive->current_speed = mode;	
+	if (!drive->init_speed)
+		drive->init_speed = mode;
+
+	return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	u32 *timings, *timings2;
+	u32 timing_local[2];
+	int ret;
+		
+	/* which drive is it ? */
+	timings = &pmif->timings[drive->select.b.unit & 0x01];
+	timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
+
+	/* Copy timings to local image */
+	timing_local[0] = *timings;
+	timing_local[1] = *timings2;
+	
+	/* Calculate timings for interface */
+	if (pmif->kind == controller_un_ata6)
+		ret = set_timings_udma_ata6(	&timing_local[0],
+						&timing_local[1],
+						mode);
+	else
+		ret = set_timings_udma_ata4(&timing_local[0], mode);
+	if (ret)
+		return 0;
+		
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f);
+	ret = pmac_ide_do_setfeature(drive, mode);
+	if (ret) {
+		printk(KERN_WARNING "%s: Failed !\n", drive->name);
+		return 0;
+	}
+
+	/* Apply timings to controller */
+	*timings = timing_local[0];
+	*timings2 = timing_local[1];
+
+	/* Set speed info in drive */
+	drive->current_speed = mode;	
+	if (!drive->init_speed)
+		drive->init_speed = mode;
+
+	return 1;
+}
+
+static __pmac
+int pmac_ide_dma_check(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	int enable = 1;
+	int map;
+	drive->using_dma = 0;
+	
+	if (pmif == NULL)
+		return 0;
+		
+	if (drive->media == ide_floppy)
+		enable = 0;
+	if (((id->capability & 1) == 0) &&
+	    !HWIF(drive)->ide_dma_good_drive(drive))
+		enable = 0;
+	if (HWIF(drive)->ide_dma_bad_drive(drive))
+		enable = 0;
+
+	if (enable) {
+		short mode;
+		
+		map = XFER_MWDMA;
+		if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) {
+			map |= XFER_UDMA;
+			if (pmif->cable_80) {
+				map |= XFER_UDMA_66;
+				if (pmif->kind == controller_un_ata6)
+					map |= XFER_UDMA_100;
+			}
+		}
+		mode = ide_find_best_mode(drive, map);
+		if (mode & XFER_UDMA)
+			drive->using_dma = pmac_ide_udma_enable(drive, mode);
+		else if (mode & XFER_MWDMA)
+			drive->using_dma = pmac_ide_mdma_enable(drive, mode);
+		hwif->OUTB(0, IDE_CONTROL_REG);
+		/* Apply settings to controller */
+		pmac_ide_do_update_timings(drive);
+	}
+	return 0;
+}
+
+static int __pmac
+pmac_ide_dma_read (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4);
+
+	if (!pmac_ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE))
+		/* try PIO instead of DMA */
+		return 1;
+
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit]+0x00800000UL,
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+
+	drive->waiting_for_dma = 1;	
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int __pmac
+pmac_ide_dma_write (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4);
+
+	if (!pmac_ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE))
+		/* try PIO instead of DMA */
+		return 1;
+
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int __pmac
+pmac_ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+static int __pmac
+pmac_ide_dma_begin (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+
+	if (pmif == NULL)
+		return 1;
+	dma = pmif->dma_regs;
+
+	writel((RUN << 16) | RUN, &dma->control);
+	/* Make sure it gets to the controller right now */
+	(void)readl(&dma->control);
+	return 0;
+}
+
+static int __pmac
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	u32 dstat;
+	
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	drive->waiting_for_dma = 0;
+	dstat = readl(&dma->status);
+	writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+	pmac_ide_destroy_dmatable(drive);
+	/* verify good dma status */
+	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+}
+
+static int __pmac
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	/* We have to things to deal with here:
+	 * 
+	 * - The dbdma won't stop if the command was started
+	 * but completed with an error without transfering all
+	 * datas. This happens when bad blocks are met during
+	 * a multi-block transfer.
+	 * 
+	 * - The dbdma fifo hasn't yet finished flushing to
+	 * to system memory when the disk interrupt occurs.
+	 * 
+	 * The trick here is to increment drive->waiting_for_dma,
+	 * and return as if no interrupt occured. If the counter
+	 * reach a certain timeout value, we then return 1. If
+	 * we really got the interrupt, it will happen right away
+	 * again.
+	 * Apple's solution here may be more elegant. They issue
+	 * a DMA channel interrupt (a separate irq line) via a DBDMA
+	 * NOP command just before the STOP, and wait for both the
+	 * disk and DBDMA interrupts to have completed.
+	 */
+ 
+	/* If ACTIVE is cleared, the STOP command have passed and
+	 * transfer is complete.
+	 */
+	status = readl(&dma->status);
+	if (!(status & ACTIVE))
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+			called while not waiting\n", HWIF(drive)->index);
+
+	/* If dbdma didn't execute the STOP command yet, the
+	 * active bit is still set */
+	drive->waiting_for_dma++;
+	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+		printk(KERN_WARNING "ide%d, timeout waiting \
+			for dbdma command stop\n", HWIF(drive)->index);
+		return 1;
+	}
+	udelay(1);
+	return 0;
+}
+
+static int __pmac
+pmac_ide_dma_host_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int __pmac
+pmac_ide_dma_host_on (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int __pmac
+pmac_ide_dma_lostirq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	status = readl(&dma->status);
+	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+	return 0;
+}
+
+static void __init 
+pmac_ide_setup_dma(struct device_node *np, int ix)
+{
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (device_is_compatible(np, "kauai-ata")) {
+		pmif->dma_regs = (volatile struct dbdma_regs*)(pmif->mapbase + 0x1000);
+	} else {
+		if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+			printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
+			return;
+		}
+		pmif->dma_regs =
+			(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
+	}
+
+	/*
+	 * Allocate space for the DBDMA commands.
+	 * The +2 is +1 for the stop command and +1 to allow for
+	 * aligning the start address to a multiple of 16 bytes.
+	 */
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+		       ide_hwifs[ix].name);
+		return;
+	}
+
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
+	ide_hwifs[ix].ide_dma_off = &__ide_dma_off;
+	ide_hwifs[ix].ide_dma_off_quietly = &__ide_dma_off_quietly;
+	ide_hwifs[ix].ide_dma_on = &__ide_dma_on;
+	ide_hwifs[ix].ide_dma_check = &pmac_ide_dma_check;
+	ide_hwifs[ix].ide_dma_read = &pmac_ide_dma_read;
+	ide_hwifs[ix].ide_dma_write = &pmac_ide_dma_write;
+	ide_hwifs[ix].ide_dma_count = &pmac_ide_dma_count;
+	ide_hwifs[ix].ide_dma_begin = &pmac_ide_dma_begin;
+	ide_hwifs[ix].ide_dma_end = &pmac_ide_dma_end;
+	ide_hwifs[ix].ide_dma_test_irq = &pmac_ide_dma_test_irq;
+	ide_hwifs[ix].ide_dma_host_off = &pmac_ide_dma_host_off;
+	ide_hwifs[ix].ide_dma_host_on = &pmac_ide_dma_host_on;
+	ide_hwifs[ix].ide_dma_good_drive = &__ide_dma_good_drive;
+	ide_hwifs[ix].ide_dma_bad_drive = &__ide_dma_bad_drive;
+	ide_hwifs[ix].ide_dma_verbose = &__ide_dma_verbose;
+	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;
+	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;
+	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+	if (!noautodma)
+		ide_hwifs[ix].autodma = 1;
+#endif
+	ide_hwifs[ix].drives[0].autodma = ide_hwifs[ix].autodma;
+	ide_hwifs[ix].drives[1].autodma = ide_hwifs[ix].autodma;
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+static void __pmac
+idepmac_sleep_device(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int j;
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
+		/* Spin down the drive */
+		SELECT_DRIVE(drive);
+		SELECT_MASK(drive, 0);
+		hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+		(void) hwif->INB(IDE_SELECT_REG);
+		udelay(100);
+		hwif->OUTB(0x00, IDE_SECTOR_REG);
+		hwif->OUTB(0x00, IDE_NSECTOR_REG);
+		hwif->OUTB(0x00, IDE_LCYL_REG);
+		hwif->OUTB(0x00, IDE_HCYL_REG);
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);   
+		hwif->OUTB(WIN_STANDBYNOW1, IDE_COMMAND_REG);
+		for (j = 0; j < 10; j++) {
+			u8 status;
+			mdelay(100);
+			status = hwif->INB(IDE_STATUS_REG);
+			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+				break;
+		}
+		break;
+	case ide_cdrom:
+		// todo
+		break;
+	case ide_floppy:
+		// todo
+		break;
+	}
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	if (DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_dma_check(drive);
+		HWGROUP(drive)->busy = 0;
+		if (!list_empty(&drive->queue.queue_head))
+			ide_do_request(HWGROUP(drive), 0);
+		spin_unlock_irq(&io_request_lock);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void __pmac
+idepmac_sleep_interface(pmac_ide_hwif_t *pmif, unsigned base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	/* We clear the timings */
+	pmif->timings[0] = 0;
+	pmif->timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable the bus */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 0);
+}
+
+static void __pmac
+idepmac_wake_interface(pmac_ide_hwif_t *pmif, unsigned long base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+		mdelay(10);
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+	}
+}
+
+static void __pmac
+idepmac_sleep_drive(ide_drive_t *drive)
+{
+	int unlock = 0;
+
+	/* Wait for HW group to complete operations */
+	if (ide_spin_wait_hwgroup(drive)) {
+		// What can we do here ? Wake drive we had already
+		// put to sleep and return an error ?
+	} else {
+		unlock = 1;
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		/* Stop the device */
+		idepmac_sleep_device(drive);
+	}
+	if (unlock)
+		spin_unlock_irq(&io_request_lock);
+}
+
+static void __pmac
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int j;
+	
+	/* Reset timings */
+	pmac_ide_do_update_timings(drive);
+	mdelay(10);
+	
+	/* Wait up to 20 seconds for the drive to be ready */
+	for (j = 0; j < 200; j++) {
+		u8 status = 0;
+		mdelay(100);
+		hwif->OUTB(drive->select.all, base + 0x60);
+		if ((hwif->INB(base + 0x60)) != drive->select.all)
+			continue;
+		status = hwif->INB(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+
+	/* We resume processing on the HW group */
+	spin_lock_irqsave(&io_request_lock, flags);
+	HWGROUP(drive)->busy = 0;
+	if (!list_empty(&drive->queue.queue_head))
+		ide_do_request(HWGROUP(drive), 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);			
+}
+
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	int i, ret;
+	unsigned long base;
+	int big_delay;
+ 
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int dn;
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				if (!hwif->drives[dn].present)
+					continue;
+				idepmac_sleep_drive(&hwif->drives[dn]);
+			}
+			/* Disable irq during sleep */
+			disable_irq(pmac_ide[i].irq);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(&pmac_ide[i], base, (ret == 0));
+		}
+		break;
+	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Make sure we have sane timings */		
+			sanitize_timings(&pmac_ide[i]);
+
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(&pmac_ide[i], base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int used_dma, dn;
+			int irq_on = 0;
+			
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				ide_drive_t *drive = &hwif->drives[dn];
+				if (!drive->present)
+					continue;
+				/* We don't have re-configured DMA yet */
+				used_dma = drive->using_dma;
+				drive->using_dma = 0;
+				idepmac_wake_drive(drive, base);
+				if (!irq_on) {
+					enable_irq(pmac_ide[i].irq);
+					irq_on = 1;
+				}
+				idepmac_wake_device(drive, used_dma);
+			}
+			if (!irq_on)
+				enable_irq(pmac_ide[i].irq);
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/swarm.c linux-2.4.21-rc3/drivers/ide/ppc/swarm.c
--- linux-2.4.20/drivers/ide/ppc/swarm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/ppc/swarm.c	2003-05-22 22:06:52.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define __IDE_SWARM_C
+
+#include <asm/sibyte/swarm_ide.h>
+
+void __init swarm_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Set up our stuff */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
+	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
+//	hwif->hw->ack_intr                    = swarm_ide_ack_intr;
+	hwif->hw.irq                          = SWARM_IDE_INT;
+#if 0
+	hwif->iops                            = swarm_iops;
+#else
+	hwif->OUTB      = hwif->OUTBP         = swarm_outb;
+	hwif->OUTW      = hwif->OUTWP         = swarm_outw;
+	hwif->OUTL      = hwif->OUTLP         = swarm_outl;
+	hwif->OUTSW     = hwif->OUTSWP        = swarm_outsw;
+	hwif->OUTSL     = hwif->OUTSLP        = swarm_outsl;
+	hwif->INB       = hwif->INBP          = swarm_inb;
+	hwif->INW       = hwif->INWP          = swarm_inw;
+	hwif->INL       = hwif->INLP          = swarm_inl;
+	hwif->INSW      = hwif->INSWP         = swarm_insw;
+	hwif->INSL      = hwif->INSLP         = swarm_insl;
+#endif
+#if 0
+	hwif->pioops                          = swarm_pio_ops;
+#else
+	hwif->ata_input_data                  = swarm_ata_input_data;
+	hwif->ata_output_data                 = swarm_ata_output_data;
+	hwif->atapi_input_bytes               = swarm_atapi_input_bytes;
+	hwif->atapi_output_bytes              = swarm_atapi_output_bytes;
+#endif
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->irq                             = hwif->hw.irq;
+	printk("SWARM onboard IDE configured as device %i\n", i);
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif->index);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/q40ide.c linux-2.4.21-rc3/drivers/ide/q40ide.c
--- linux-2.4.20/drivers/ide/q40ide.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/q40ide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,91 +0,0 @@
-/*
- *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
- *
- *     (c) Richard Zidlicky
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/ide.h>
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define Q40IDE_NUM_HWIFS	2
-
-#define PCIDE_BASE1	0x1f0
-#define PCIDE_BASE2	0x170
-#define PCIDE_BASE3	0x1e8
-#define PCIDE_BASE4	0x168
-#define PCIDE_BASE5	0x1e0
-#define PCIDE_BASE6	0x160
-
-static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
-    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
-    PCIDE_BASE6 */
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-
-/* HD_DATA was redefined in asm-m68k/ide.h */
-#undef HD_DATA
-#define HD_DATA  0x1f0
-
-
-#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
-
-static const int pcide_offsets[IDE_NR_PORTS] = {
-    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
-    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
-    PCIDE_REG(CMD)
-};
-
-static int q40ide_default_irq(q40ide_ioreg_t base)
-{
-           switch (base) { 
-	            case 0x1f0: return 14;
-		    case 0x170: return 15;
-		    case 0x1e8: return 11;
-		    default:
-			return 0;
-	   }
-}
-
-
-
-    /*
-     *  Probe for Q40 IDE interfaces
-     */
-
-void q40ide_init(void)
-{
-    int i;
-
-    if (!MACH_IS_Q40)
-      return ;
-
-    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
-	hw_regs_t hw;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets,
-			(ide_ioreg_t)pcide_bases[i]+0x206,
-			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
-    }
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.c linux-2.4.21-rc3/drivers/ide/qd65xx.c
--- linux-2.4.20/drivers/ide/qd65xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,456 +0,0 @@
-/*
- *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
- *
- *  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.07	Second channel bug fix 
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * Please set local bus speed using kernel parameter idebus
- * 	for example, "idebus=33" stands for 33Mhz VLbus
- * To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "ide0=autotune"
- * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#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/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include "ide_modes.h"
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- *	-- qd6500 is a single IDE interface
- *	-- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- *        qd6580: 1
- * upper nibble:
- *        qd6500: 1100
- *        qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- *                                                   channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- *         0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- * 	(maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-static void qd_write_reg (byte content, byte reg)
-{
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb(content,reg);
-	restore_flags(flags);	/* all CPUs */
-}
-
-byte __init qd_read_reg (byte reg)
-{
-	unsigned long flags;
-	byte read;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	read = inb(reg);
-	restore_flags(flags);	/* all CPUs */
-	return read;
-}
-
-/*
- * qd_select:
- *
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-
-static void qd_select (ide_drive_t *drive)
-{
-	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
-			(QD_TIMREG(drive) & 0x02);
-
-	if (timings[index] != QD_TIMING(drive))
-		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- * 	lower nibble represents active time,   in count of VLB clocks
- * 	upper nibble represents recovery time, in count of VLB clocks
- */
-
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
-	byte active_cycle,recovery_cycle;
-
-	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   * 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);
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static byte qd6580_compute_timing (int active_time, int recovery_time)
-{
-	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);
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
-		int *active_time, int *recovery_time)
-{
-	struct qd65xx_timing_s *p;
-	char model[40];
-
-	if (!*drive->id->model) return 0;
-
-	strncpy(model,drive->id->model,40);
-	ide_fixstring(model,40,1); /* byte-swap */
-
-	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset,4)) {
-			printk(KERN_DEBUG "%s: listed !\n",drive->name);
-			*active_time = p->active;
-			*recovery_time = p->recovery;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * qd_timing_ok:
- *
- * check whether timings don't conflict
- */
-
-static int qd_timing_ok (ide_drive_t drives[])
-{
-	return (IDE_IMPLY(drives[0].present && drives[1].present,
-			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
-			          QD_TIMING(drives) == QD_TIMING(drives+1))));
-	/* if same timing register, must be same timing */
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing, and enables selectproc as needed
- */
-
-static void qd_set_timing (ide_drive_t *drive, byte timing)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	if (qd_timing_ok(hwif->drives)) {
-		qd_select(drive); /* selects once */
-		hwif->selectproc = NULL;
-	} else
-		hwif->selectproc = &qd_select;
-
-	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
-}
-
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
-		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
-		&& drive->id->eide_pio >= 240) {
-
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
-		active_time = 110;
-		recovery_time = drive->id->eide_pio - 120;
-	}
-
-	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
-}
-
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int base = HWIF(drive)->select_data;
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
-		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
-		pio = IDE_MIN(pio,4);
-
-		switch (pio) {
-			case 0: break;
-			case 3:
-				if (d.cycle_time >= 110) {
-					active_time = 86;
-					recovery_time = d.cycle_time-102;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			case 4:
-				if (d.cycle_time >= 69) {
-					active_time = 70;
-					recovery_time = d.cycle_time-61;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			default:
-				if (d.cycle_time >= 180) {
-					active_time = 110;
-					recovery_time = d.cycle_time - 120;
-				} else {
-					active_time = ide_pio_timings[pio].active_time;
-					recovery_time = d.cycle_time
-							-active_time;
-				}
-		}
-		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
-	}
-
-	if (!HWIF(drive)->channel && drive->media != ide_disk) {
-		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
-	}
-
-	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
-	byte savereg;
-	byte readreg;
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
-	readreg = inb_p(port);
-	outb(savereg,port);
-	restore_flags(flags);	/* all CPUs */
-
-	if (savereg == QD_TESTVAL) {
-		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
-		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
-		printk(KERN_ERR "Assuming qd65xx is not present.\n");
-		return 1;
-	}
-
-	return (readreg != QD_TESTVAL);
-}
-
-/*
- * probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-int __init probe (int base)
-{
-	byte config;
-	byte index;
-
-	config = qd_read_reg(QD_CONFIG_PORT);
-
-	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
-
-	index = ! (config & QD_CONFIG_IDE_BASEPORT);
-
-	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
-
-		if (qd_testreg(base)) return 1;		/* bad register */
-
-			/* qd6500 found */
-
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
-			ide_hwifs[index].name, base);
-		
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-			config, QD_ID3);
-		
-		if (config & QD_CONFIG_DISABLED) {
-			printk(KERN_WARNING "qd6500 is disabled !\n");
-			return 1;
-		}
-
-		hwif->chipset = ide_qd65xx;
-		hwif->select_data = base;
-		hwif->config_data = config;
-		hwif->drives[0].drive_data =
-		hwif->drives[1].drive_data = QD6500_DEF_DATA;
-		hwif->drives[0].io_32bit =
-		hwif->drives[1].io_32bit = 1;
-		hwif->tuneproc = &qd6500_tune_drive;
-		return 1;
-	}
-
-	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
-		byte control;
-
-		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
-			/* bad registers */
-
-			/* qd6580 found */
-
-		control = qd_read_reg(QD_CONTROL_PORT);
-
-		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-			config, control, QD_ID3);
-
-		if (control & QD_CONTR_SEC_DISABLED) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-
-			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n",
-					ide_hwifs[index].name);
-
-			hwif->chipset = ide_qd65xx;
-			hwif->select_data = base;
-			hwif->config_data = config | (control <<8);
-			hwif->drives[0].drive_data =
-			hwif->drives[1].drive_data = QD6580_DEF_DATA;
-			hwif->drives[0].io_32bit =
-			hwif->drives[1].io_32bit = 1;
-			hwif->tuneproc = &qd6580_tune_drive;
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 1;
-		} else {
-			int i,j;
-			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
-					ide_hwifs[0].name,ide_hwifs[1].name);
-
-			for (i=0;i<2;i++) {
-
-				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].mate = &ide_hwifs[i^1];
-				ide_hwifs[i].channel = i;
-
-				ide_hwifs[i].select_data = base;
-				ide_hwifs[i].config_data = config | (control <<8);
-				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
-
-				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data =
-					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
-					ide_hwifs[i].drives[j].io_32bit = 1;
-				}
-			}
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 0; /* no other qd65xx possible */
-		}
-	}
-	/* no qd65xx found */
-	return 1;
-}
-
-/*
- * init_qd65xx:
- *
- * called at the very beginning of initialization ; should just probe and link
- */
-
-void __init init_qd65xx (void)
-{
-	if (probe(0x30)) probe(0xb0);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.h linux-2.4.21-rc3/drivers/ide/qd65xx.h
--- linux-2.4.20/drivers/ide/qd65xx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,140 +0,0 @@
-/*
- * linux/drivers/ide/qd65xx.h
- *
- * Copyright (c) 2000	Linus Torvalds & authors
- */
-
-/*
- * Authors:	Petr Soucek <petr@ryston.cz>
- * 		Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b)	((!(a)) || (b))
-
-#define QD_TIM1_PORT		(base)
-#define QD_CONFIG_PORT		(base+0x01)
-#define QD_TIM2_PORT		(base+0x02)
-#define QD_CONTROL_PORT		(base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT	0x01
-#define QD_CONFIG_BASEPORT	0x02
-#define QD_CONFIG_ID3		0x04
-#define QD_CONFIG_DISABLED	0x08
-#define QD_CONFIG_QD6500	0xc0
-#define QD_CONFIG_QD6580_A	0xa0
-#define QD_CONFIG_QD6580_B	0x50
-
-#define QD_CONTR_SEC_DISABLED	0x01
-
-#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)
-
-#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
-#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
-
-#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 */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-struct qd65xx_timing_s {
-	char	offset;   /* ofset from the beginning of Model Number" */
-	char	model[4];    /* 4 chars from Model number, no conversion */
-	short	active;   /* active time */
-	short	recovery; /* recovery time */
-} qd65xx_timing [] = {
-	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
-	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
-	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
-	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
-	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
-	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
-	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
-	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
-	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
-	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
-	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
-	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
-	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
-	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
-	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
-	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
-	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
-	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
-	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
-	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
-	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
-	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
-	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
-	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
-	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
-	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
-	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
-	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
-	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
-	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
-	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
-	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
-	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
-	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
-	{  6, "61 0", 135, 285 },  /* WD AC160				*/
-	{  6, "1107", 135, 235 },  /* WD AC1170				*/
-	{  6, "2101", 110, 220 },  /* WD AC1210				*/
-	{  6, "4202", 135, 245 },  /* WD AC2420				*/
-	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
-	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
-	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
-	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
-	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
-	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
-	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
-	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
-	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
-	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
-	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
-	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
-	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
-	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
-	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
-	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
-	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
-	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
-	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
-	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
-	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
-	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
-	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
-	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
-	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
-	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
-	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
-	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
-	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
-	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
-	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
-	{  2, "2309", 175, 295 },  /* ST3290A				*/
-	{  2, "3358", 180, 310 },  /* ST3385A				*/
-	{  2, "6355", 180, 310 },  /* ST3655A				*/
-	{  2, "1900", 175, 270 },  /* ST9100A				*/
-	{  2, "1954", 175, 270 },  /* ST9145A				*/
-	{  2, "1909", 175, 270 },  /* ST9190AG				*/
-	{  2, "2953", 175, 270 },  /* ST9235A				*/
-	{  2, "1359", 175, 270 },  /* ST3195A				*/
-	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
-	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
-	{  4, "2253", 175, 300 },  /* HP C2235A				*/
-	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
-	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
-	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
-	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
-	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/Makefile linux-2.4.21-rc3/drivers/ide/raid/Makefile
--- linux-2.4.20/drivers/ide/raid/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/Makefile	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,19 @@
+
+O_TARGET := idedriver-raid.o
+
+obj-y		:=
+obj-m		:=
+
+export-objs := ataraid.o
+
+# 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_PDC)	+= pdcraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_SII)	+= silraid.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.c linux-2.4.21-rc3/drivers/ide/raid/ataraid.c
--- linux-2.4.20/drivers/ide/raid/ataraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/ataraid.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,317 @@
+/*
+   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+#include <linux/kdev_t.h>
+#include <linux/swap.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+                                        
+static int ataraid_hardsect_size[256];
+static int ataraid_blksize_size[256];
+
+static struct raid_device_operations* ataraid_ops[16];
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ataraid_open(struct inode * inode, struct file * filp);
+static int ataraid_release(struct inode * inode, struct file * filp);
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+struct gendisk ataraid_gendisk;
+static int ataraid_gendisk_sizes[256];
+static int ataraid_readahead[256];
+
+static struct block_device_operations ataraid_fops = {
+	owner:			THIS_MODULE,
+	open:                   ataraid_open,
+	release:                ataraid_release,
+	ioctl:                  ataraid_ioctl,
+};
+                
+
+
+static DECLARE_MUTEX(ataraid_sem);
+
+/* Bitmap for the devices currently in use */
+static unsigned int ataraiduse;
+
+
+/* stub fops functions */
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
+		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
+	return -EINVAL;
+}
+
+static int ataraid_open(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
+		return (ataraid_ops[minor]->open)(inode,filp);
+	return -EINVAL;
+}
+
+
+static int ataraid_release(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
+		return (ataraid_ops[minor]->release)(inode,filp);
+	return -EINVAL;
+}
+
+static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int minor;
+	int retval;
+	minor = MINOR(bh->b_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
+		
+		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
+		if (retval == -1) {
+			ataraid_split_request(q,rw,bh);		
+			return 0;
+		} else
+			return retval;
+	}
+	return -EINVAL;
+}
+
+struct buffer_head *ataraid_get_bhead(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_bhead);
+
+struct ataraid_bh_private *ataraid_get_private(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_private);
+
+void ataraid_end_request(struct buffer_head *bh, int uptodate)
+{
+	struct ataraid_bh_private *private = bh->b_private;
+
+	if (private==NULL)
+		BUG();
+
+	if (atomic_dec_and_test(&private->count)) {
+		private->parent->b_end_io(private->parent,uptodate);
+		private->parent = NULL;
+		kfree(private);
+	}
+	kfree(bh);
+}
+
+EXPORT_SYMBOL(ataraid_end_request);
+
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1,*bh2;
+	struct ataraid_bh_private *private;
+	bh1=ataraid_get_bhead();
+	bh2=ataraid_get_bhead();
+
+	/* If either of those ever fails we're doomed */
+	if ((!bh1)||(!bh2))
+		BUG();
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+	
+	memcpy(bh1, bh, sizeof(*bh));
+	memcpy(bh2, bh, sizeof(*bh));
+	
+	bh1->b_end_io = ataraid_end_request;
+	bh2->b_end_io = ataraid_end_request;
+
+	bh2->b_rsector += bh->b_size >> 10;
+	bh1->b_size /= 2;
+	bh2->b_size /= 2;
+	private->parent = bh;
+
+	bh1->b_private = private;
+	bh2->b_private = private;
+	atomic_set(&private->count,2);
+
+	bh2->b_data +=  bh->b_size/2;
+
+	generic_make_request(rw,bh1);
+	generic_make_request(rw,bh2);
+}
+
+
+
+
+/* device register / release functions */
+
+
+int ataraid_get_device(struct raid_device_operations *fops)
+{
+	int bit;
+	down(&ataraid_sem);
+	if (ataraiduse==~0U) {
+		up(&ataraid_sem);
+		return -ENODEV;
+	}
+	bit=ffz(ataraiduse); 
+	ataraiduse |= 1<<bit;
+	ataraid_ops[bit] = fops;
+	up(&ataraid_sem);
+	return bit;
+}
+
+void ataraid_release_device(int device)
+{
+	down(&ataraid_sem);
+	
+	if ((ataraiduse & (1<<device))==0)
+		BUG();	/* device wasn't registered at all */
+	
+	ataraiduse &= ~(1<<device);
+	ataraid_ops[device] = NULL;
+	up(&ataraid_sem);
+}
+
+void ataraid_register_disk(int device,long size)
+{
+	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
+		&ataraid_fops,size);
+
+}
+
+static __init int ataraid_init(void) 
+{
+	int i;
+        for(i=0;i<256;i++)
+	{
+        	ataraid_hardsect_size[i] = 512;
+		ataraid_blksize_size[i] = 1024;  
+		ataraid_readahead[i] = 1023;
+	}
+	
+	if (blksize_size[ATAMAJOR]==NULL)
+		blksize_size[ATAMAJOR] = ataraid_blksize_size;
+	if (hardsect_size[ATAMAJOR]==NULL)
+		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
+	
+	
+	/* setup the gendisk structure */	
+	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
+	if (ataraid_gendisk.part==NULL) {
+		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
+		return -1;
+	}
+	
+	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
+	
+	
+	ataraid_gendisk.major       = ATAMAJOR;
+	ataraid_gendisk.major_name  = "ataraid";
+	ataraid_gendisk.minor_shift = 4;
+	ataraid_gendisk.max_p	    = 15;
+	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
+	ataraid_gendisk.nr_real	    = 16;
+	ataraid_gendisk.fops        = &ataraid_fops;
+	
+	
+	add_gendisk(&ataraid_gendisk);
+			
+	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
+		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
+		return -1;
+	}
+	
+	                
+	
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
+                                                                                     	
+	return 0;                                                        	
+}
+
+
+static void __exit ataraid_exit(void)
+{
+	unregister_blkdev(ATAMAJOR, "ataraid");
+	hardsect_size[ATAMAJOR] = NULL;
+	blk_size[ATAMAJOR] = NULL;
+	blksize_size[ATAMAJOR] = NULL;                       
+	max_readahead[ATAMAJOR] = NULL;
+
+	del_gendisk(&ataraid_gendisk);
+        
+	if (ataraid_gendisk.part) {
+		kfree(ataraid_gendisk.part);
+		ataraid_gendisk.part = NULL;
+	}
+}
+
+module_init(ataraid_init);
+module_exit(ataraid_exit);
+
+
+
+EXPORT_SYMBOL(ataraid_get_device);
+EXPORT_SYMBOL(ataraid_release_device);
+EXPORT_SYMBOL(ataraid_gendisk);
+EXPORT_SYMBOL(ataraid_register_disk);
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.h linux-2.4.21-rc3/drivers/ide/raid/ataraid.h
--- linux-2.4.20/drivers/ide/raid/ataraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/ataraid.h	2003-05-22 22:06:40.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#define ATAMAJOR 114
+#define SHIFT 4
+#define MINOR_MASK 15
+#define MAJOR_MASK 15
+
+                                        
+/* raid_device_operations is a light struct block_device_operations with an
+   added method for make_request */
+struct raid_device_operations {
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
+	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
+};
+
+
+struct geom {
+	unsigned char heads;
+	unsigned int cylinders;
+	unsigned char sectors;
+};
+
+/* structure for the splitting of bufferheads */
+
+struct ataraid_bh_private {
+	struct buffer_head *parent;
+	atomic_t count;
+};
+
+extern struct gendisk ataraid_gendisk;
+
+extern int ataraid_get_device(struct raid_device_operations *fops);
+extern void ataraid_release_device(int device);
+extern int get_blocksize(kdev_t dev);
+extern void ataraid_register_disk(int device,long size);
+extern struct buffer_head *ataraid_get_bhead(void);
+extern struct ataraid_bh_private *ataraid_get_private(void);
+extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
+
+
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.c linux-2.4.21-rc3/drivers/ide/raid/hptraid.c
--- linux-2.4.20/drivers/ide/raid/hptraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/hptraid.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,661 @@
+/*
+   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+
+   Based on work
+   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
+	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   Based on work done by Søren Schmidt for FreeBSD
+
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int hptraid_open(struct inode * inode, struct file * filp);
+static int hptraid_release(struct inode * inode, struct file * filp);
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int hptraidspan_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct hptdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct hptraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+        u_int32_t magic_0;
+	struct geom geom;
+	
+	struct hptdisk disk[8];
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];	
+};
+
+struct hptraid_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct hptraid_dev devlist[]=
+{
+
+	{IDE0_MAJOR,  0, -1},
+	{IDE0_MAJOR, 64, -1},
+	{IDE1_MAJOR,  0, -1},
+	{IDE1_MAJOR, 64, -1},
+	{IDE2_MAJOR,  0, -1},
+	{IDE2_MAJOR, 64, -1},
+	{IDE3_MAJOR,  0, -1},
+	{IDE3_MAJOR, 64, -1},
+	{IDE4_MAJOR,  0, -1},
+	{IDE4_MAJOR, 64, -1},
+	{IDE5_MAJOR,  0, -1},
+	{IDE5_MAJOR, 64, -1},
+	{IDE6_MAJOR,  0, -1},
+	{IDE6_MAJOR, 64, -1}
+};
+
+static struct raid_device_operations hptraidspan_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraidspan_make_request
+};
+
+static struct raid_device_operations hptraid0_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid0_make_request
+};
+
+static struct raid_device_operations hptraid1_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid1_make_request
+};
+
+static struct hptraid raid[14];
+
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+	unsigned char val;
+	unsigned long sectors;
+	
+	if (!inode || !inode->i_rdev) 	
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+         	case BLKGETSIZE:   /* Return device size */
+			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl;
+			
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val=63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			unsigned int bios_cyl;
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val = 63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+			
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	};
+
+	return 0;
+}
+
+
+static int hptraidspan_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned int disk;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	for (disk=0;disk<thisraid->disks;disk++) {
+		if (disk==1)
+			rsect+=10;
+			// the "on next disk" contition check is a bit odd
+		if (thisraid->disk[disk].sectors > rsect+1)
+			break;
+		rsect-=thisraid->disk[disk].sectors-(disk?11:1);
+	}
+
+		// request spans over 2 disks => request must be split
+	if(rsect+bh->b_size/512 >= thisraid->disk[disk].sectors)
+		return -1;
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;
+	}
+			
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+	
+	/* All but the first disk have a 10 sector offset */
+	if (i>0)
+		rsect+=10;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int hptraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int device;
+	int dist;
+	int bestsofar,bestdist,i;
+	static int previous;
+
+	/* Reads are simple in principle. Pick a disk and go. 
+	   Initially I cheat by just picking the one which the last known
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			dist = -dist;
+		if (dist>4095)
+			dist=4095;
+		
+		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
+			if ((previous>bestsofar)&&(previous<=i))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	bh->b_rsector += bestsofar?10:0;
+	bh->b_rdev = raid[device].disk[bestsofar].device; 
+	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+static int hptraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* dupe the bufferhead and update the parts that need to be different */
+		memcpy(bh1, bh, sizeof(*bh));
+		
+		bh1->b_end_io = ataraid_end_request;
+		bh1->b_private = private;
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect+(i==0?0:10); /* partition offset */
+		bh1->b_rdev = raid[device].disk[i].device;
+
+		/* update the last known head position for the drive */
+		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
+
+		generic_make_request(rw,bh1);
+	}
+	return 0;
+}
+
+static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh) {
+	/* Read and Write are totally different cases; split them totally here */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return hptraid1_read_request(q,rw,bh);
+	else
+		return hptraid1_write_request(q,rw,bh);
+}
+
+#include "hptraid.h"
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	
+	if (blksize_size[major]==NULL)	 /* device doesn't exist */
+		return -EINVAL;
+	
+
+	/* Superblock is at 4096+412 bytes */
+	set_blocksize (dev, 4096);
+	bh = bread (dev, 1, 4096);
+
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "hptraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned long maxsectors (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity);
+
+	return lba;
+}
+
+static void __init probedisk(struct hptraid_dev *disk, int device, u_int8_t type)
+{
+	int i;
+        struct highpoint_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+	
+ 	if (disk->device != -1)	/* disk is occupied? */
+ 		return;
+ 
+ 	if (maxsectors(disk->major,disk->minor)==0)
+		return;
+	
+        if (read_disk_sb(disk->major,disk->minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct highpoint_raid_conf*)&block[512];
+                
+        if (prom->magic!=  0x5a7816f0)
+        	return;
+        switch (prom->type) {
+		case HPT_T_SPAN:
+		case HPT_T_RAID_0:
+		case HPT_T_RAID_1:
+			if(prom->type != type)
+				return;
+			break;
+		default:
+			printk(KERN_INFO "hptraid: only SPAN, RAID0 and RAID1 is currently supported \n");
+			return;
+        }
+
+ 		/* disk from another array? */
+ 	if(raid[device].disks && prom->magic_0 != raid[device].magic_0)
+ 		return;
+
+	i = prom->disk_number;
+	if (i<0)
+		return;
+	if (i>8) 
+		return;
+
+	bdev = bdget(MKDEV(disk->major,disk->minor));
+	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
+        	int j=0;
+        	struct gendisk *gd;
+		raid[device].disk[i].bdev = bdev;
+        	/* This is supposed to prevent others from stealing our underlying disks */
+		/* now blank the /proc/partitions table for the wrong partition table,
+		   so that scripts don't accidentally mount it and crash the kernel */
+		 /* XXX: the 0 is an utter hack  --hch */
+		gd=get_gendisk(MKDEV(disk->major, 0));
+		if (gd!=NULL) {
+ 			if (gd->major==disk->major)
+ 				for (j=1+(disk->minor<<gd->minor_shift);
+					j<((disk->minor+1)<<gd->minor_shift);
+					j++) gd->part[j].nr_sects=0;					
+		}
+        }
+	raid[device].disk[i].device = MKDEV(disk->major,disk->minor);
+	raid[device].disk[i].sectors = maxsectors(disk->major,disk->minor);
+	raid[device].stride = (1<<prom->raid0_shift);
+	raid[device].disks = prom->raid_disks;
+	raid[device].sectors = prom->total_secs-(prom->total_secs%(255*63));
+	raid[device].sectors += raid[device].sectors&1?1:0;
+	raid[device].magic_0=prom->magic_0;
+	disk->device=device;
+			
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+		
+		smallest = smallest * count;		
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+		
+	}
+}
+
+
+static __init int hptraid_init_one(int device, u_int8_t type)
+{
+	int i,count;
+
+	memset(raid+device, 0, sizeof(struct hptraid));
+	for(i=0; i < 14; i++) {
+		probedisk(devlist+i, device, type);
+	}
+
+	if(type == HPT_T_RAID_0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);
+
+	count=0;
+		
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb \n",
+				i,raid[device].disk[i].sectors/2048);
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+		return 0;
+	} else {
+		printk(KERN_INFO "No raid array found\n");
+		return -ENODEV;
+	}
+	
+}
+
+static __init int hptraid_init(void)
+{
+ 	int retval,device,count=0;
+  	
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01-ww1\n");
+
+ 	do
+ 	{
+ 		device=ataraid_get_device(&hptraid0_ops);
+ 		if (device<0)
+ 			return (count?0:-ENODEV);
+ 		retval = hptraid_init_one(device, HPT_T_RAID_0);
+ 		if (retval)
+ 			ataraid_release_device(device);
+ 		else
+ 			count++;
+ 	} while(!retval);
+ 	do
+ 	{
+ 		device=ataraid_get_device(&hptraid1_ops);
+ 		if (device<0)
+ 			return (count?0:-ENODEV);
+ 		retval = hptraid_init_one(device, HPT_T_RAID_1);
+ 		if (retval)
+ 			ataraid_release_device(device);
+ 		else
+ 			count++;
+ 	} while(!retval);
+ 	do
+ 	{
+ 		device=ataraid_get_device(&hptraidspan_ops);
+ 		if (device<0)
+ 			return (count?0:-ENODEV);
+ 		retval = hptraid_init_one(device, HPT_T_SPAN);
+ 		if (retval)
+ 			ataraid_release_device(device);
+ 		else
+ 			count++;
+ 	} while(!retval);
+ 	return (count?0:retval);
+}
+
+static void __exit hptraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++)  {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}       
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int hptraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int hptraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(hptraid_init);
+module_exit(hptraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.h linux-2.4.21-rc3/drivers/ide/raid/hptraid.h
--- linux-2.4.20/drivers/ide/raid/hptraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/hptraid.h	2003-05-22 22:06:48.000000000 +0000
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                            
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.c linux-2.4.21-rc3/drivers/ide/raid/pdcraid.c
--- linux-2.4.20/drivers/ide/raid/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/pdcraid.c	2003-05-22 22:06:42.000000000 +0000
@@ -0,0 +1,602 @@
+/*
+   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   Based on work done by Søren Schmidt for FreeBSD  
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int pdcraid_open(struct inode * inode, struct file * filp);
+static int pdcraid_release(struct inode * inode, struct file * filp);
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct pdcdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct pdcraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct pdcdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations pdcraid0_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid0_make_request
+};
+
+static struct raid_device_operations pdcraid1_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid1_make_request
+};
+
+static struct pdcraid raid[16];
+
+
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	};
+
+	return 0;
+}
+
+
+static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct pdcraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* dupe the bufferhead and update the parts that need to be different */
+		memcpy(bh1, bh, sizeof(*bh));
+		
+		bh1->b_end_io = ataraid_end_request;
+		bh1->b_private = private;
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
+		bh1->b_rdev = raid[device].disk[i].device;
+
+		/* update the last known head position for the drive */
+		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
+
+		generic_make_request(rw,bh1);
+	}
+	return 0;
+}
+
+static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int device;
+	int dist;
+	int bestsofar,bestdist,i;
+	static int previous;
+
+	/* Reads are simple in principle. Pick a disk and go. 
+	   Initially I cheat by just picking the one which the last known
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			dist = -dist;
+		if (dist>4095)
+			dist=4095;
+		
+		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
+			if ((previous>bestsofar)&&(previous<=i))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	bh->b_rdev = raid[device].disk[bestsofar].device; 
+	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	/* Read and Write are totally different cases; split them totally here */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return pdcraid1_read_request(q,rw,bh);
+	else
+		return pdcraid1_write_request(q,rw,bh);
+}
+
+#include "pdcraid.h"
+
+static unsigned long calc_pdcblock_offset (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = lba * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->sect;
+
+	return lba;
+}
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+	
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_pdcblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned int calc_sb_csum (unsigned int* ptr)
+{	
+	unsigned int sum;
+	int count;
+	
+	sum = 0;
+	for (count=0;count<511;count++)
+		sum += *ptr++;
+	
+	return sum;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct promise_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct promise_raid_conf*)&block[512];
+
+        /* the checksums must match */
+	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
+		return;
+	if (prom->raid.type!=raidlevel) /* different raidlevel */
+		return;
+
+	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
+		return;
+	
+	cookie = prom->raid.magic_1;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
+        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
+        	     (prom->raid.disk[i].device == prom->raid.device) ) {
+
+        	        bdev = bdget(MKDEV(major,minor));
+        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+				raid[device].disk[i].bdev = bdev;
+			}
+			raid[device].disk[i].device = MKDEV(major,minor);
+			raid[device].disk[i].sectors = prom->raid.disk_secs;
+			raid[device].stride = (1<<prom->raid.raid0_shift);
+			raid[device].disks = prom->raid.total_disks;
+			raid[device].sectors = prom->raid.total_secs;
+			raid[device].geom.heads = prom->raid.heads+1;
+			raid[device].geom.sectors = prom->raid.sectors;
+			raid[device].geom.cylinders = prom->raid.cylinders+1;
+			devlist[devindex].device=device;
+        	     }
+        }
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int pdcraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++)
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int pdcraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid0_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	do {
+	
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid1_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,1);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit pdcraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int pdcraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int pdcraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(pdcraid_init);
+module_exit(pdcraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.h linux-2.4.21-rc3/drivers/ide/raid/pdcraid.h
--- linux-2.4.20/drivers/ide/raid/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/pdcraid.h	2003-05-22 22:06:51.000000000 +0000
@@ -0,0 +1,47 @@
+struct promise_raid_conf {
+    char                promise_id[24];
+
+    u32             dummy_0;
+    u32             magic_0;
+    u32             dummy_1;
+    u32             magic_1;
+    u16             dummy_2;
+    u8              filler1[470];
+    struct {
+        u32 flags;                          /* 0x200 */
+        u8          dummy_0;
+        u8          disk_number;
+        u8          channel;
+        u8          device;
+        u32         magic_0;
+        u32         dummy_1;
+        u32         dummy_2;                /* 0x210 */
+        u32         disk_secs;
+        u32         dummy_3;
+        u16         dummy_4;
+        u8          status;
+        u8          type;
+        u8        total_disks;            /* 0x220 */
+        u8        raid0_shift;
+        u8        raid0_disks;
+        u8        array_number;
+        u32       total_secs;
+        u16       cylinders;
+        u8        heads;
+        u8        sectors;
+        u32         magic_1;
+        u32         dummy_5;                /* 0x230 */
+        struct {
+            u16     dummy_0;
+            u8      channel;
+            u8      device;
+            u32     magic_0;
+            u32     disk_number;
+        } disk[8];
+    } raid;
+    u32             filler2[346];
+    u32            checksum;
+};
+
+#define PR_MAGIC        "Promise Technology, Inc."
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/silraid.c linux-2.4.21-rc3/drivers/ide/raid/silraid.c
--- linux-2.4.20/drivers/ide/raid/silraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/silraid.c	2003-05-22 22:06:38.000000000 +0000
@@ -0,0 +1,487 @@
+/*
+   silraid.c  Copyright (C) 2002 Red Hat, Inc. All rights reserved.
+
+   The contents of this file are subject to the Open Software License version 1.1
+   that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is 
+   included herein by reference. 
+   
+   Alternatively, the contents of this file may be used under the
+   terms of the GNU General Public License version 2 (the "GPL") as 
+   distributed in the kernel source COPYING file, in which
+   case the provisions of the GPL are applicable instead of the
+   above.  If you wish to allow the use of your version of this file
+   only under the terms of the GPL and not to allow others to use
+   your version of this file under the OSL, indicate your decision
+   by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL.  If you do not delete
+   the provisions above, a recipient may use your version of this
+   file under either the OSL or the GPL.
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int silraid_open(struct inode * inode, struct file * filp);
+static int silraid_release(struct inode * inode, struct file * filp);
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct sildisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct silraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct sildisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations silraid0_ops = {
+        open:                   silraid_open,
+	release:                silraid_release,
+	ioctl:			silraid_ioctl,
+	make_request:		silraid0_make_request
+};
+
+static struct silraid raid[16];
+
+
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct silraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+#include "silraid.h"
+
+static unsigned long calc_silblock_offset (int major,int minor)
+{
+	unsigned long lba = 0, cylinders;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* last sector second to last cylinder */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	cylinders = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = (cylinders - 1) * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->head -1;
+	
+//	return 80417215;  
+	printk("Guestimating sector %li for superblock\n",lba);
+	return lba;
+
+}
+
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+	
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_silblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "silraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh); return ret;
+}
+
+static unsigned short checksum1(unsigned short *buffer)
+{
+	int i;
+	int sum = 0;
+	for (i=0; i<0x13f/2; i++)
+		sum += buffer[i];	
+	return (-sum)&0xFFFF;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct signature *superblock;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        superblock = (struct signature*)&block[4096-512];
+        
+        if (superblock->unknown[0] != 'Z') /* Need better check here */
+        	return;
+        	
+        if (superblock->checksum1 != checksum1((unsigned short*)superblock))
+        	return;  
+        
+        
+
+	if (superblock->raidlevel!=raidlevel) /* different raidlevel */
+		return;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+	 i = superblock->disk_in_set;
+
+	bdev = bdget(MKDEV(major,minor));
+        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+		raid[device].disk[i].bdev = bdev;
+	}
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = superblock->thisdisk_sectors; 
+	raid[device].stride = superblock->raid0_sectors_per_stride;
+	raid[device].disks = superblock->disks_in_set;
+	raid[device].sectors = superblock->array_sectors;
+	raid[device].geom.heads = 255;
+	raid[device].geom.sectors = 63;
+	raid[device].geom.cylinders =  raid[device].sectors / raid[device].geom.heads / raid[device].geom.sectors; 
+	
+	devlist[devindex].device=device;
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int silraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++) 
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int silraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&silraid0_ops);
+		if (device<0)
+			break;
+		retval = silraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit silraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int silraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int silraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(silraid_init);
+module_exit(silraid_exit);
+MODULE_LICENSE("GPL and additional rights");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/silraid.h linux-2.4.21-rc3/drivers/ide/raid/silraid.h
--- linux-2.4.20/drivers/ide/raid/silraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/raid/silraid.h	2003-05-22 22:06:28.000000000 +0000
@@ -0,0 +1,30 @@
+struct signature {
+	char unknown[0x36];  		/* 0x00 to 0x35 */
+	char diskname[32];	     	/* 0x36 to 0x56 */
+	char unknown2[0x6c-86];		/* 0x57 to 0x6B */	
+	unsigned int array_sectors;	/* 0x6C to 0x6F */
+	char unknown2b[8];		/* 0x70 to 0x77 */
+	unsigned int thisdisk_sectors;	/* 0x78 to 0x7B */
+	char unknown2c[0xFF-0x7B];	/* 0x7C to 0xFF */
+	char unknown3[4];		/* 0x100 to 0x103 */
+	unsigned short PCI_DEV_ID;	/* 0x104 and 0x105 */
+	unsigned short PCI_VEND_ID;	/* 0x106 and 0x107 */
+	char unknown4[4];		/* 0x108 to 0x10B */
+	unsigned char seconds;		/* 0x10C */
+	unsigned char minutes;		/* 0x10D */
+	unsigned char hour;		/* 0x10E */
+	unsigned char day;		/* 0x10F */
+	unsigned char month;		/* 0x110 */
+	unsigned char year;		/* 0x111 */
+	unsigned short raid0_sectors_per_stride; /* 0x112 */
+	char unknown6[2];		/* 0x113 - 0x115 */
+	unsigned char disk_in_set;	/* 0x116 */
+	unsigned char raidlevel;	/* 0x117 */
+	unsigned char disks_in_set;	/* 0x118 */
+	char unknown7[0x12a - 0x118];   /* 0x118 - 0x12a */
+	unsigned char idechannel;	/* 0x12b */
+	char unknown8[0x13D-0x12B];	/* 0x12c - 0x13d */
+	unsigned short checksum1;	/* 0x13e and 0x13f */	
+	char assumed_zeros[509-0x13f];
+	unsigned short checksum2;	/* 0x1FE and 0x1FF */
+} __attribute__((packed));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rapide.c linux-2.4.21-rc3/drivers/ide/rapide.c
--- linux-2.4.20/drivers/ide/rapide.c	2001-10-11 16:14:32.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/rapide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,94 +0,0 @@
-/*
- * linux/drivers/ide/rapide.c
- *
- * Copyright (c) 1996-1998 Russell King.
- *
- * Changelog:
- *  08-06-1996	RMK	Created
- *  13-04-1998	RMK	Added manufacturer and product IDs
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static card_ids __init rapide_cids[] = {
-	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-	{ 0xffff, 0xffff }
-};
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS];
-
-static inline int rapide_register(struct expansion_card *ec)
-{
-	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-	hw_regs_t hw;
-
-	int i;
-
-	memset(&hw, 0, sizeof(hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw.io_ports[i] = (ide_ioreg_t)port;
-		port += 1 << 4;
-	}
-	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
-	hw.irq = ec->irq;
-
-	return ide_register_hw(&hw, NULL);
-}
-
-int __init rapide_init(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		ec[i] = NULL;
-
-	ecard_startfind();
-
-	for (i = 0; ; i++) {
-		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
-			break;
-
-		ecard_claim(ec[i]);
-		result[i] = rapide_register(ec[i]);
-	}
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i] && result[i] < 0) {
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module (void)
-{
-	return rapide_init();
-}
-
-void cleanup_module (void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i]) {
-			unsigned long port;
-			port = ecard_address(ec[i], ECARD_MEMC, 0);
-
-			ide_unregister_port(port, ec[i]->irq, 16);
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-		}
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rz1000.c linux-2.4.21-rc3/drivers/ide/rz1000.c
--- linux-2.4.20/drivers/ide/rz1000.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/rz1000.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,97 +0,0 @@
-/*
- *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author:  mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for disabling the buggy read-ahead
- *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- *  Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
-#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/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-
-void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
-{
-	unsigned short reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_rz1000;
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
-	} else {
-		hwif->serialized = 1;
-		hwif->drives[0].no_unmask = 1;
-		hwif->drives[1].no_unmask = 1;
-		printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
-	}
-}
-
-#else
-
-static void __init init_rz1000 (struct pci_dev *dev, const char *name)
-{
-	unsigned short reg, h;
-
-	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) && !(reg & PCI_COMMAND_IO)) {
-		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
-		return;
-	}
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
-	} else {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ide_hwif_t *hwif = &ide_hwifs[h];
-			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-			 && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
-			{
-				hwif->chipset = ide_rz1000;
-				hwif->serialized = 1;
-				hwif->drives[0].no_unmask = 1;
-				hwif->drives[1].no_unmask = 1;
-				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->channel = 1;
-				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
-			}
-		}
-	}
-}
-
-void __init ide_probe_for_rz100x (void)	/* called from ide.c */
-{
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		init_rz1000 (dev, "RZ1000");
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		init_rz1000 (dev, "RZ1001");
-}
-
-#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/serverworks.c linux-2.4.21-rc3/drivers/ide/serverworks.c
--- linux-2.4.20/drivers/ide/serverworks.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/serverworks.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,675 +0,0 @@
-/*
- * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * 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
- *
- *
- * 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:
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP])
- *	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
- *	Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *	Latency: 255
- *	Region 4: I/O ports at c200
- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 01 c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
- *         Subsystem: ServerWorks: Unknown device 0212
- *         Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
- *         Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *         Latency: 64, cache line size 08
- *         Region 0: I/O ports at 01f0
- *         Region 1: I/O ports at 03f4
- *         Region 2: I/O ports at 0170
- *         Region 3: I/O ports at 0374
- *         Region 4: I/O ports at 08b0
- *         Region 5: I/O ports at 1000
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
- * 50: 00 00 00 00 07 00 44 02 0f 04 03 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#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 */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u32 reg40, reg44;
-	u16 reg48, reg56;
-	u8  reg54, c0=0, c1=0;
-
-	pci_read_config_dword(bmide_dev, 0x40, &reg40);
-	pci_read_config_dword(bmide_dev, 0x44, &reg44);
-	pci_read_config_word(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_word(bmide_dev, 0x56, &reg56);
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks CSB5 Chipset (rev %02x)\n",
-				     svwks_revision);
-			break;
-		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 %04x Chipset (rev %02x)\n",
-				     bmide_dev->device, svwks_revision);
-			break;
-	}
-
-	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-	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 enabled:   %s              %s             %s               %s\n",
-			(reg54 & 0x01) ? "yes" : "no ",
-			(reg54 & 0x02) ? "yes" : "no ",
-			(reg54 & 0x04) ? "yes" : "no ",
-			(reg54 & 0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg56&0x0005)==0x0005)?"5":
-				((reg56&0x0004)==0x0004)?"4":
-				((reg56&0x0003)==0x0003)?"3":
-				((reg56&0x0002)==0x0002)?"2":
-				((reg56&0x0001)==0x0001)?"1":
-				((reg56&0x000F))?"?":"0",
-			((reg56&0x0050)==0x0050)?"5":
-				((reg56&0x0040)==0x0040)?"4":
-				((reg56&0x0030)==0x0030)?"3":
-				((reg56&0x0020)==0x0020)?"2":
-				((reg56&0x0010)==0x0010)?"1":
-				((reg56&0x00F0))?"?":"0",
-			((reg56&0x0500)==0x0500)?"5":
-				((reg56&0x0400)==0x0400)?"4":
-				((reg56&0x0300)==0x0300)?"3":
-				((reg56&0x0200)==0x0200)?"2":
-				((reg56&0x0100)==0x0100)?"1":
-				((reg56&0x0F00))?"?":"0",
-			((reg56&0x5000)==0x5000)?"5":
-				((reg56&0x4000)==0x4000)?"4":
-				((reg56&0x3000)==0x3000)?"3":
-				((reg56&0x2000)==0x2000)?"2":
-				((reg56&0x1000)==0x1000)?"1":
-				((reg56&0xF000))?"?":"0");
-	p += sprintf(p, "DMA enabled:    %s                %s               %s                 %s\n",
-			((reg44&0x00002000)==0x00002000)?"2":
-				((reg44&0x00002100)==0x00002100)?"1":
-				((reg44&0x00007700)==0x00007700)?"0":
-				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
-			((reg44&0x00000020)==0x00000020)?"2":
-				((reg44&0x00000021)==0x00000021)?"1":
-				((reg44&0x00000077)==0x00000077)?"0":
-				((reg44&0x000000FF)==0x000000FF)?"X":"?",
-			((reg44&0x20000000)==0x20000000)?"2":
-				((reg44&0x21000000)==0x21000000)?"1":
-				((reg44&0x77000000)==0x77000000)?"0":
-				((reg44&0xFF000000)==0xFF000000)?"X":"?",
-			((reg44&0x00200000)==0x00200000)?"2":
-				((reg44&0x00210000)==0x00210000)?"1":
-				((reg44&0x00770000)==0x00770000)?"0":
-				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-			((reg40&0x00002000)==0x00002000)?"4":
-				((reg40&0x00002200)==0x00002200)?"3":
-				((reg40&0x00003400)==0x00003400)?"2":
-				((reg40&0x00004700)==0x00004700)?"1":
-				((reg40&0x00005D00)==0x00005D00)?"0":"?",
-			((reg40&0x00000020)==0x00000020)?"4":
-				((reg40&0x00000022)==0x00000022)?"3":
-				((reg40&0x00000034)==0x00000034)?"2":
-				((reg40&0x00000047)==0x00000047)?"1":
-				((reg40&0x0000005D)==0x0000005D)?"0":"?",
-			((reg40&0x20000000)==0x20000000)?"4":
-				((reg40&0x22000000)==0x22000000)?"3":
-				((reg40&0x34000000)==0x34000000)?"2":
-				((reg40&0x47000000)==0x47000000)?"1":
-				((reg40&0x5D000000)==0x5D000000)?"0":"?",
-			((reg40&0x00200000)==0x00200000)?"4":
-				((reg40&0x00220000)==0x00220000)?"3":
-				((reg40&0x00340000)==0x00340000)?"2":
-				((reg40&0x00470000)==0x00470000)?"1":
-				((reg40&0x005D0000)==0x005D0000)?"0":"?");
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-
-byte svwks_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static struct pci_dev *isa_dev;
-
-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
-	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte csb5		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	int err;
-
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
-
-	byte ultra_enable	= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_timing		= 0x00;
-	byte pio_timing		= 0x00;
-	unsigned short csb5_pio	= 0x00;
-
-	byte pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
-		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
-		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
-		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
-		default:
-			return -1;
-	}
-
-	pci_read_config_byte(dev, drive_pci, &pio_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_timing);
-	pci_read_config_byte(dev, drive_pci3, &ultra_timing);
-	pci_read_config_word(dev, 0x4A, &csb5_pio);
-	pci_read_config_byte(dev, 0x54, &ultra_enable);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-	pio_timing	&= ~0xFF;
-	dma_timing	&= ~0xFF;
-	ultra_timing	&= ~(0x0F << (4*unit));
-	ultra_enable	&= ~(0x01 << drive->dn);
-	csb5_pio	&= ~(0x0F << (4*drive->dn));
-
-	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			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:
-		case XFER_MW_DMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		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];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-#endif
-		default:
-			break;
-	}
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-#if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SVWKS_DEBUG_DRIVE_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	pci_write_config_byte(dev, drive_pci, pio_timing);
-	if (csb5)
-		pci_write_config_word(dev, 0x4A, csb5_pio);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci2, dma_timing);
-	pci_write_config_byte(dev, drive_pci3, ultra_timing);
-	pci_write_config_byte(dev, 0x54, ultra_enable);
-	
-	if (speed > XFER_PIO_4)
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	else
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	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;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 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
-		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;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void svwks_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	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;
-	} else if (id->dma_ultra & 0x0010) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0008) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} 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_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) svwks_tune_chipset(drive, speed);
-
-	return ((int)	((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);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		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. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
-{
-	unsigned int reg;
-	byte btr;
-
-	/* save revision id to determine DMA capability */
-	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
-	/* force Master Latency Timer value to 64 PCICLKs */
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
-	/* 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);
-		}
-	}
-
-	/* 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);
-	}
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!svwks_proc) {
-		svwks_proc = 1;
-		bmide_dev = dev;
-		svwks_display_info = &svwks_get_info;
-	}
-#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem
- * device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set   = secondary IDE channel has 80-pin cable.
- * 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)
-		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;
-
-	/* 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;
-}
-
-void __init ide_init_svwks (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &svwks_tune_drive;
-	hwif->speedproc = &svwks_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-	if (hwif->dma_base) {
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif	
-		hwif->dmaproc = &svwks_dmaproc;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/setup-pci.c linux-2.4.21-rc3/drivers/ide/setup-pci.c
--- linux-2.4.20/drivers/ide/setup-pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/setup-pci.c	2003-05-22 22:06:47.000000000 +0000
@@ -0,0 +1,832 @@
+/*
+ *  linux/drivers/ide/setup-pci.c		Version 1.10	2002/08/19
+ *
+ *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  Recent Changes
+ *	Split the set up function into multiple functions
+ *	Use pci_set_master
+ *	Fix misreporting of I/O v MMIO problems
+ *	Initial fixups for simplex devices
+ */
+
+/*
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+/**
+ *	ide_match_hwif	-	match a PCI IDE against an ide_hwif
+ *	@io_base: I/O base of device
+ *	@bootable: set if its bootable
+ *	@name: name of device
+ *
+ *	Match a PCI IDE port against an entry in ide_hwifs[],
+ *	based on io_base port if possible. Return the matching hwif,
+ *	or a new hwif. If we find an error (clashing, out of devices, etc)
+ *	return NULL
+ *
+ *	FIXME: we need to handle mmio matches here too
+ */
+
+static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
+{
+	int h;
+	ide_hwif_t *hwif;
+
+	/*
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
+				name, io_base, hwif->name);
+			return NULL;	/* already claimed */
+		}
+	}
+	/*
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
+	 * Give preference to claiming other slots before claiming ide0/ide1,
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 *
+	 * Unless there is a bootable card that does not use the standard
+	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 */
+	if (bootable) {
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			hwif = &ide_hwifs[h];
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	} else {
+		for (h = 2; h < MAX_HWIFS; ++h) {
+			hwif = ide_hwifs + h;
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	}
+	for (h = 0; h < 2; ++h) {
+		hwif = ide_hwifs + h;
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
+	}
+	printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
+	return NULL;
+}
+
+/**
+ *	ide_setup_pci_baseregs	-	place a PCI IDE controller native
+ *	@dev: PCI device of interface to switch native
+ *	@name: Name of interface
+ *
+ *	We attempt to place the PCI interface into PCI native mode. If
+ *	we succeed the BARs are ok and the controller is in PCI mode.
+ *	Returns 0 on success or an errno code. 
+ *
+ *	FIXME: if we program the interface and then fail to set the BARS
+ *	we don't switch it back to legacy mode. Do we actually care ??
+ */
+ 
+static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+{
+	u8 progif = 0;
+
+	/*
+	 * Place both IDE interfaces into PCI "native" mode:
+	 */
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+			 (progif & 5) != 5) {
+		if ((progif & 0xa) != 0xa) {
+			printk(KERN_INFO "%s: device not capable of full "
+				"native PCI mode\n", name);
+			return -EOPNOTSUPP;
+		}
+		printk("%s: placing both ports into native PCI mode\n", name);
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+		    (progif & 5) != 5) {
+			printk(KERN_ERR "%s: rewrite of PROGIF failed, wanted "
+				"0x%04x, got 0x%04x\n",
+				name, progif|5, progif);
+			return -EOPNOTSUPP;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed.  Oh the things we forget.  I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+/**
+ *	ide_get_or_set_dma_base		-	setup BMIBA
+ *	@hwif: Interface
+ *
+ *	Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ *	If need be we set up the DMA base. Where a device has a partner that
+ *	is already in DMA mode we check and enforce IDE simplex rules.
+ */
+
+static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if ((hwif->mmio) && (hwif->dma_base))
+		return hwif->dma_base;
+
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else {
+		dma_base = (hwif->mmio) ?
+			((unsigned long) hwif->hwif_data) :
+			(pci_resource_start(dev, 4));
+		if (!dma_base) {
+			printk(KERN_ERR "%s: dma_base is invalid (0x%04lx)\n",
+				hwif->cds->name, dma_base);
+			dma_base = 0;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	/* FIXME - should use pci_assign_resource surely */
+	if ((!dma_base) && (!second_chance)) {
+		unsigned long set_bmiba = 0;
+		second_chance++;
+		switch(dev->vendor) {
+			case PCI_VENDOR_ID_AL:
+				set_bmiba = DEFAULT_BMALIBA; break;
+			case PCI_VENDOR_ID_VIA:
+				set_bmiba = DEFAULT_BMCRBA; break;
+			case PCI_VENDOR_ID_INTEL:
+				set_bmiba = DEFAULT_BMIBA; break;
+			default:
+				return dma_base;
+		}
+		pci_write_config_dword(dev, 0x20, set_bmiba|1);
+		goto second_chance_to_dma;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (dma_base) {
+		u8 simplex_stat = 0;
+		dma_base += hwif->channel ? 8 : 0;
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_AL_M5219:
+			case PCI_DEVICE_ID_AL_M5229:
+			case PCI_DEVICE_ID_AMD_VIPER_7409:
+			case PCI_DEVICE_ID_CMD_643:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				simplex_stat = hwif->INB(dma_base + 2);
+				hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					printk(KERN_INFO "%s: simplex device: "
+						"DMA forced\n",
+						hwif->cds->name);
+				}
+				break;
+			default:
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					/* simplex device? */
+#if 0					
+/*
+ *	At this point we haven't probed the drives so we can't make the
+ *	appropriate decision. Really we should defer this problem
+ *	until we tune the drive then try to grab DMA ownership if we want
+ *	to be the DMA end. This has to be become dynamic to handle hot
+ *	plug.
+ */
+					/* Don't enable DMA on a simplex channel with no drives */
+					if (!hwif->drives[0].present && !hwif->drives[1].present)
+					{
+						printk(KERN_INFO "%s: simplex device with no drives: DMA disabled\n",
+								hwif->cds->name);
+						dma_base = 0;
+					}
+					/* If our other channel has DMA then we cannot */
+					else 
+#endif					
+					if(hwif->mate && hwif->mate->dma_base) 
+					{
+						printk(KERN_INFO "%s: simplex device: "
+							"DMA disabled\n",
+							hwif->cds->name);
+						dma_base = 0;
+					}
+				}
+		}
+	}
+	return dma_base;
+}
+
+static void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((d->vendor != dev->vendor) && (d->device != dev->device)) {
+		printk(KERN_INFO "%s: unknown IDE controller at PCI slot "
+			"%s, VID=%04x, DID=%04x\n",
+			d->name, dev->slot_name, dev->vendor, dev->device);
+        } else {
+		printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
+			d->name, dev->slot_name);
+	}
+}
+
+/**
+ *	ide_pci_enable	-	do PCI enables
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable the IDE PCI device. We attempt to enable the device in full
+ *	but if that fails then we only need BAR4 so we will enable that.
+ *	
+ *	Returns zero on success or an error code
+ */
+ 
+static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	
+	if (pci_enable_device(dev)) {
+		if (pci_enable_device_bars(dev, 1 << 4)) {
+			printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+				"Could not enable device.\n", d->name);
+			return -EBUSY;
+		} else
+			printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name);
+	}
+
+	/*
+	 * assume all devices can do 32-bit dma for now. we can add a
+	 * dma mask field to the ide_pci_device_t if we need it (or let
+	 * lower level driver set the dma mask)
+	 */
+	if (pci_set_dma_mask(dev, 0xffffffff)) {
+		printk(KERN_ERR "%s: can't set dma mask\n", d->name);
+		return -EBUSY;
+	}
+	 
+	/* FIXME: Temporary - until we put in the hotplug interface logic
+	   Check that the bits we want are not in use by someone else */
+	if (pci_request_region(dev, 4, "ide_tmp"))
+		return -EBUSY;
+	pci_release_region(dev, 4);
+	
+	return 0;	
+}
+
+/**
+ *	ide_pci_configure	-	configure an unconfigured device
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable and configure the PCI device we have been passed.
+ *	Returns zero on success or an error code.
+ */
+ 
+static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u16 pcicmd = 0;
+	/*
+	 * PnP BIOS was *supposed* to have setup this device, but we
+	 * can do it ourselves, so long as the BIOS has assigned an IRQ
+	 * (or possibly the device is using a "legacy header" for IRQs).
+	 * Maybe the user deliberately *disabled* the device,
+	 * but we'll eventually ignore it again if no drives respond.
+	 */
+	if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO)) 
+	{
+		printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name);
+		return -ENODEV;
+	}
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {
+		printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name);
+		return -ENXIO;
+	}
+	return 0;
+}
+
+/**
+ *	ide_pci_check_iomem	-	check a register is I/O
+ *	@dev: pci device
+ *	@d: ide_pci_device
+ *	@bar: bar number
+ *
+ *	Checks if a BAR is configured and points to MMIO space. If so
+ *	print an error and return an error code. Otherwise return 0
+ */
+ 
+static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar)
+{
+	ulong flags = pci_resource_flags(dev, bar);
+	
+	/* Unconfigured ? */
+	if (!flags || pci_resource_len(dev, bar) == 0)
+		return 0;
+
+	/* I/O space */		
+	if(flags & PCI_BASE_ADDRESS_IO_MASK)
+		return 0;
+		
+	/* Bad */
+	printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
+			"as MEM, report to "
+			"<andre@linux-ide.org>.\n", d->name);
+	return -EINVAL;
+}
+	
+		
+/**
+ *	ide_hwif_configure	-	configure an IDE interface
+ *	@dev: PCI device holding interface
+ *	@d: IDE pci data
+ *	@mate: Paired interface if any
+ *
+ *	Perform the initial set up for the hardware interface structure. This
+ *	is done per interface port rather than per PCI device. There may be
+ *	more than one port per device.
+ *
+ *	Returns the new hardware interface structure, or NULL on a failure
+ */
+ 
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+{
+	unsigned long ctl = 0, base = 0;
+	ide_hwif_t *hwif;
+
+	/*  Possibly we should fail if these checks report true */
+	ide_pci_check_iomem(dev, d, 2*port);
+	ide_pci_check_iomem(dev, d, 2*port+1);
+ 
+	ctl  = pci_resource_start(dev, 2*port+1);
+	base = pci_resource_start(dev, 2*port);
+	if ((ctl && !base) || (base && !ctl)) {
+		printk(KERN_ERR "%s: inconsistent baseregs (BIOS) "
+			"for port %d, skipping\n", d->name, port);
+		return NULL;
+	}
+	if (!ctl)
+	{
+		/* Use default values */
+		ctl = port ? 0x374 : 0x3f4;
+		base = port ? 0x170 : 0x1f0;
+	}
+	if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+		return NULL;	/* no room in ide_hwifs[] */
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+fixup_address:
+		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	} else if (hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+		goto fixup_address;
+	}
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->cds = (struct ide_pci_device_s *) d;
+	hwif->channel = port;
+
+	if (!hwif->irq)
+		hwif->irq = irq;
+	if (mate) {
+		hwif->mate = mate;
+		mate->mate = hwif;
+	}
+	return hwif;
+}
+
+/**
+ *	ide_hwif_setup_dma	-	configure DMA interface
+ *	@dev: PCI device
+ *	@d: IDE pci data
+ *	@hwif: Hardware interface we are configuring
+ *
+ *	Set up the DMA base for the interface. Enable the master bits as
+ *	neccessary and attempt to bring the device DMA into a ready to use
+ *	state
+ */
+ 
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+	u16 pcicmd;
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	if ((d->autodma == AUTODMA) ||
+	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	     (dev->class & 0x80))) {
+		unsigned long dma_base = ide_get_or_set_dma_base(hwif);
+		if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+			/*
+ 			 * Set up BM-DMA capability
+			 * (PnP BIOS should have done this)
+ 			 */
+			if (!((d->device == PCI_DEVICE_ID_CYRIX_5530_IDE && d->vendor == PCI_VENDOR_ID_CYRIX)
+			    ||(d->device == PCI_DEVICE_ID_NS_SCx200_IDE && d->vendor == PCI_VENDOR_ID_NS)))
+			{
+				/*
+				 * default DMA off if we had to
+				 * configure it here
+				 */
+				hwif->autodma = 0;
+			}
+			pci_set_master(dev);
+			if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+				printk(KERN_ERR "%s: %s error updating PCICMD\n",
+					hwif->name, d->name);
+				dma_base = 0;
+			}
+		}
+		if (dma_base) {
+			if (d->init_dma) {
+				d->init_dma(hwif, dma_base);
+			} else {
+				ide_setup_dma(hwif, dma_base, 8);
+			}
+		} else {
+			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+				"(BIOS)\n", hwif->name, d->name);
+		}
+	}
+}
+
+/**
+ *	ide_setup_pci_controller	-	set up IDE PCI
+ *	@dev: PCI device
+ *	@d: IDE PCI data
+ *	@noisy: verbose flag
+ *	@config: returned as 1 if we configured the hardware
+ *
+ *	Set up the PCI and controller side of the IDE interface. This brings
+ *	up the PCI side of the device, checks that the device is enabled
+ *	and enables it if need be
+ */
+ 
+static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config)
+{
+	int ret = 0;
+	u32 class_rev;
+	u16 pcicmd;
+
+	if (!noautodma)
+		ret = 1;
+
+	if (noisy)
+		ide_setup_pci_noise(dev, d);
+
+	if (ide_pci_enable(dev, d))
+		return -EBUSY;
+		
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
+		if (ide_pci_configure(dev, d))
+			return -ENODEV;
+		/* default DMA off if we had to configure it here */
+		ret = 0;
+		*config = 1;
+		printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
+	}
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	if (noisy)
+		printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
+	return ret;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy)
+{
+	u32 port, at_least_one_hwif_enabled = 0, autodma = 0;
+	unsigned int pciirq = 0;
+	int tried_config = 0;
+	int drive0_tune, drive1_tune;
+	ata_index_t index;
+	u8 tmp = 0;
+	ide_hwif_t *hwif, *mate = NULL;
+	static int secondpdc = 0;
+
+	index.all = 0xf0f0;
+
+	if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0)
+		return index;
+
+	/*
+	 * Can we trust the reported IRQ?
+	 */
+	pciirq = dev->irq;
+	
+	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
+		if (noisy)
+			printk(KERN_INFO "%s: not 100%% native mode: "
+				"will probe irqs later\n", d->name);
+		/*
+		 * This allows offboard ide-pci cards the enable a BIOS,
+		 * verify interrupt settings of split-mirror pci-config
+		 * space, place chipset into init-mode, and/or preserve
+		 * an interrupt if the card is not native ide support.
+		 */
+		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0;
+	} else if (tried_config) {
+		if (noisy)
+			printk(KERN_INFO "%s: will probe irqs later\n", d->name);
+		pciirq = 0;
+	} else if (!pciirq) {
+		if (noisy)
+			printk(KERN_WARNING "%s: bad irq (%d): will probe later\n",
+				d->name, pciirq);
+		pciirq = 0;
+	} else {
+		if (d->init_chipset)
+			d->init_chipset(dev, d->name);
+
+		if (noisy)
+#ifdef __sparc__
+			printk(KERN_INFO "%s: 100%% native mode on irq %s\n",
+			       d->name, __irq_itoa(pciirq));
+#else
+			printk(KERN_INFO "%s: 100%% native mode on irq %d\n",
+				d->name, pciirq);
+#endif
+	}
+	
+	/*
+	 * Set up the IDE ports
+	 */
+	 
+	for (port = 0; port <= 1; ++port) {
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	
+		/* 
+		 * If this is a Promise FakeRaid controller,
+		 * the 2nd controller will be marked as 
+		 * disabled while it is actually there and enabled
+		 * by the bios for raid purposes. 
+		 * Skip the normal "is it enabled" test for those.
+		 */
+		if (((d->vendor == PCI_VENDOR_ID_PROMISE) &&
+		     ((d->device == PCI_DEVICE_ID_PROMISE_20262) ||
+		      (d->device == PCI_DEVICE_ID_PROMISE_20265))) &&
+		    (secondpdc++==1) && (port==1))
+			goto controller_ok;
+			
+		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+		    (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+controller_ok:
+
+		if (d->channels	<= port)
+			return index;
+	
+		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+			continue;
+
+		/* setup proper ancestral information */
+		// 2.5 only hwif->gendev.parent = &dev->dev;
+
+		if (hwif->channel) {
+			index.b.high = hwif->index;
+		} else {
+			index.b.low = hwif->index;
+		}
+
+		
+		if (d->init_iops)
+			d->init_iops(hwif);
+
+		if (d->autodma == NODMA)
+			goto bypass_legacy_dma;
+		if (d->autodma == NOAUTODMA)
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
+		ide_hwif_setup_dma(dev, d, hwif);
+bypass_legacy_dma:
+
+		drive0_tune = hwif->drives[0].autotune;
+		drive1_tune = hwif->drives[1].autotune;
+
+		if (d->init_hwif)
+			/* Call chipset-specific routine
+			 * for each enabled hwif
+			 */
+			d->init_hwif(hwif);
+
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
+	}
+	if (!at_least_one_hwif_enabled)
+		printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
+	return index;
+}
+
+void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_device);
+
+void ide_setup_pci_devices (struct pci_dev *dev, struct pci_dev *dev2, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+	do_ide_setup_pci_device(dev2, d, 0);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
+
+/*
+ *	Module interfaces
+ */
+ 
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	ide_register_pci_driver		-	attach IDE driver
+ *	@driver: pci driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then 
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	The driver_data of the driver table must point to an ide_pci_device_t
+ *	describing the interface.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int ide_pci_register_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		return pci_module_init(driver);
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_register_driver);
+
+/**
+ *	ide_unregister_pci_driver	-	unregister an IDE driver
+ *	@driver: driver to remove
+ *
+ *	Unregister a currently installed IDE driver. Returns are the same
+ *	as for pci_unregister_driver
+ */
+ 
+void ide_pci_unregister_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		pci_unregister_driver(driver);
+	else
+		list_del(&driver->node);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+ 
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+	
+	list_for_each(l, &ide_pci_drivers)
+	{
+		d = list_entry(l, struct pci_driver, node);
+		if(d->id_table)
+		{
+			const struct pci_device_id *id = pci_match_device(d->id_table, dev);
+			if(id != NULL)
+			{
+				if(d->probe(dev, id) >= 0)
+				{
+					dev->driver = d;
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *	@scan_direction: set for reverse order scanning
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+ 	
+void __init ide_scan_pcibus (int scan_direction)
+{
+	struct pci_dev *dev;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	pre_init = 0;
+	if (!scan_direction) {
+		pci_for_each_dev(dev) {
+			ide_scan_pcidev(dev);
+		}
+	} else {
+		pci_for_each_dev_reverse(dev) {
+			ide_scan_pcidev(dev);
+		}
+	}
+	
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers)
+	{
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		pci_register_driver(d);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sis5513.c linux-2.4.21-rc3/drivers/ide/sis5513.c
--- linux-2.4.20/drivers/ide/sis5513.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/sis5513.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,861 +0,0 @@
-/*
- * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
- *
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan		: for direct support and hardware.
- * Daniela Engert	: for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul :
- *			  for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620/5513 chipset.
- * ATA100 tests and design on the SiS735/5513 chipset.
- * ATA16/33 design from specs
- */
-
-/*
- * TODO:
- *	- Get ridden of SisHostChipInfo[] completness dependancy.
- *	- Get ATA-133 datasheets, implement ATA-133 init code.
- *	- Study drivers/ide/ide-timing.h.
- *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
- *	  or remove ATA_00 define
- *	- More checks in the config registers (force values instead of
- *	  relying on the BIOS setting them correctly).
- *	- Further optimisations ?
- *	  . for example ATA66+ regs 0x48 & 0x4A
- */
-
-#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/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-/* When DEBUG is defined it outputs initial PCI config register
-   values and changes made to them by the driver */   
-// #define DEBUG
-/* When BROKEN_LEVEL is defined it limits the DMA mode
-   at boot time to its value */
-// #define BROKEN_LEVEL XFER_SW_DMA_0
-#define DISPLAY_SIS_TIMINGS
-
-/* Miscellaneaous flags */
-#define SIS5513_LATENCY		0x01
-
-/* registers layout and init values are chipset family dependant */
-/* 1/ define families */
-#define ATA_00		0x00
-#define ATA_16		0x01
-#define ATA_33		0x02
-#define ATA_66		0x03
-#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
-#define ATA_100		0x05
-#define ATA_133		0x06
-/* 2/ variable holding the controller chipset family value */
-static unsigned char chipset_family;
-
-
-/*
- * Debug code: following IDE config registers' changes
- */
-#ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x57
-   Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[0x58];
-
-static byte sis5513_max_config_register(void) {
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:	return 0x4f;
-		case ATA_33:	return 0x52;
-		case ATA_66:
-		case ATA_100a:
-		case ATA_100:
-		case ATA_133:
-		default:	return 0x57;
-	}
-}
-
-/* Read config registers, print differences from previous read */
-static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
-	int i;
-	byte reg_val;
-	byte changed=0;
-	byte max = sis5513_max_config_register();
-
-	printk("SIS5513: %s, changed registers:\n", info);
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &reg_val);
-		if (reg_val != ide_regs_copy[i]) {
-			printk("%0#x: %0#x -> %0#x\n",
-			       i, ide_regs_copy[i], reg_val);
-			ide_regs_copy[i]=reg_val;
-			changed=1;
-		}
-	}
-
-	if (!changed) {
-		printk("none\n");
-	}
-}
-
-/* Load config registers, no printing */
-static void sis5513_load_registers(struct pci_dev* dev) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
-	}
-}
-
-/* Print a register */
-static void sis5513_print_register(int reg) {
-	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
-}
-
-/* Print valuable registers */
-static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	sis5513_load_registers(dev);
-	printk("SIS5513 %s\n", marker);
-	printk("SIS5513 dump:");
-	for(i=0x00; i<0x40; i++) {
-		if ((i % 0x10)==0) printk("\n             ");
-		sis5513_print_register(i);
-	}
-	for(; i<49; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n             ");
-
-	for(; i<=max; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n");
-}
-#endif
-
-
-/*
- * Devices supported
- */
-static const struct {
-	const char *name;
-	unsigned short host_id;
-	unsigned char chipset_family;
-	unsigned char flags;
-} SiSHostChipInfo[] = {
-//	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
-//	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
-	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
-	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
-};
-
-/* Cycle time bits and values vary accross chip dma capabilities
-   These three arrays hold the register layout and the values to set.
-   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
-static byte cycle_time_range[] = {0,0,2,3,3,4,4};
-static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
-	{0,0,0,0,0,0}, /* no udma */
-	{0,0,0,0,0,0}, /* no udma */
-	{3,2,1,0,0,0},
-	{7,5,3,2,1,0},
-	{7,5,3,2,1,0},
-	{11,7,5,4,2,1},
-	{0,0,0,0,0,0} /* not yet known, ask SiS */
-};
-
-static struct pci_dev *host_dev = NULL;
-
-
-/*
- * Printing configuration
- */
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int sis_get_info(char *, char **, off_t, int);
-extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static char* cable_type[] = {
-	"80 pins",
-	"40 pins"
-};
-
-static char* recovery_time[] ={
-	"12 PCICLK", "1 PCICLK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLCK",
-	"6 PCICLK", "7 PCICLCK",
-	"8 PCICLK", "9 PCICLCK",
-	"10 PCICLK", "11 PCICLK",
-	"13 PCICLK", "14 PCICLK",
-	"15 PCICLK", "15 PCICLK"
-};
-
-static char* active_time[] = {
-	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLK",
-	"6 PCICLK", "12 PCICLK"
-};
-
-static char* cycle_time[] = {
-	"Reserved", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK",
-	"9 CLK", "10 CLK",
-	"11 CLK", "12 CLK",
-	"Reserved", "Reserved",
-	"Reserved", "Reserved"
-};
-
-/* Generic add master or slave info function */
-static char* get_drives_info (char *buffer, byte pos)
-{
-	byte reg00, reg01, reg10, reg11; /* timing registers */
-	char* p = buffer;
-
-/* Postwrite/Prefetch */
-	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
-	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
-		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
-
-	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
-	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
-	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
-	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
-
-/* UDMA */
-	if (chipset_family >= ATA_33) {
-		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
-			     (reg11 & 0x80) ? "Enabled" : "Disabled");
-
-		p += sprintf(p, "                UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, " \t UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, "\n");
-	}
-
-/* Data Active */
-	p += sprintf(p, "                Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16: /* confirmed */
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, " \t Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, "\n");
-
-/* Data Recovery */
-	/* warning: may need (reg&0x07) for pre ATA66 chips */
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
-
-	return p;
-}
-
-static char* get_masters_info(char* buffer)
-{
-	return get_drives_info(buffer, 0);
-}
-
-static char* get_slaves_info(char* buffer)
-{
-	return get_drives_info(buffer, 1);
-}
-
-/* Main get_info, called on /proc/ide/sis reads */
-static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	byte reg;
-	u16 reg2, reg3;
-
-	p += sprintf(p, "\nSiS 5513 ");
-	switch(chipset_family) {
-		case ATA_00: p += sprintf(p, "Unknown???"); break;
-		case ATA_16: p += sprintf(p, "DMA 16"); break;
-		case ATA_33: p += sprintf(p, "Ultra 33"); break;
-		case ATA_66: p += sprintf(p, "Ultra 66"); break;
-		case ATA_100a:
-		case ATA_100: p += sprintf(p, "Ultra 100"); break;
-		case ATA_133:
-		default: p+= sprintf(p, "Ultra 133+"); break;
-	}
-	p += sprintf(p, " chipset\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-
-/* Status */
-	pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: ");
-	if (chipset_family < ATA_66) {
-		p += sprintf(p, "%s \t \t \t \t %s\n",
-			     (reg & 0x04) ? "On" : "Off",
-			     (reg & 0x02) ? "On" : "Off");
-	} else {
-		p += sprintf(p, "%s \t \t \t \t %s \n",
-			     (reg & 0x02) ? "On" : "Off",
-			     (reg & 0x04) ? "On" : "Off");
-	}
-
-/* Operation Mode */
-	pci_read_config_byte(bmide_dev, 0x09, &reg);
-	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
-		     (reg & 0x01) ? "Native" : "Compatible",
-		     (reg & 0x04) ? "Native" : "Compatible");
-
-/* 80-pin cable ? */
-	if (chipset_family > ATA_33) {
-		pci_read_config_byte(bmide_dev, 0x48, &reg);
-		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-			     (reg & 0x10) ? cable_type[1] : cable_type[0],
-			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-	}
-
-/* Prefetch Count */
-	pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	p = get_masters_info(p);
-	p = get_slaves_info(p);
-
-	return p-buffer;
-}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-
-byte sis_proc = 0;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-
-/*
- * Configuration functions
- */
-/* Enables per-drive prefetch and postwrite */
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte reg4bh		= 0;
-	byte rw_prefetch	= (0x11 << drive->dn);
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
-#endif
-
-	if (drive->media != ide_disk)
-		return;
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
-
-	if ((reg4bh & rw_prefetch) != rw_prefetch)
-		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
-#endif
-}
-
-
-/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			timing, drive_pci, test1, test2;
-
-	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-
-	config_drive_art_rwp(drive);
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 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 {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
-	       drive->dn, pio, timing);
-#endif
-
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return;
-	}
-
-	/* register layout changed with newer ATA100 chips */
-	if (chipset_family < ATA_100) {
-		pci_read_config_byte(dev, drive_pci, &test1);
-		pci_read_config_byte(dev, drive_pci+1, &test2);
-
-		/* Clear active and recovery timings */
-		test1 &= ~0x0F;
-		test2 &= ~0x07;
-
-		switch(timing) {
-			case 4:		test1 |= 0x01; test2 |= 0x03; break;
-			case 3:		test1 |= 0x03; test2 |= 0x03; break;
-			case 2:		test1 |= 0x04; test2 |= 0x04; break;
-			case 1:		test1 |= 0x07; test2 |= 0x06; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-		pci_write_config_byte(dev, drive_pci+1, test2);
-	} else {
-		switch(timing) { /*   active  recovery
-					  v     v */
-			case 4:		test1 = 0x30|0x01; break;
-			case 3:		test1 = 0x30|0x03; break;
-			case 2:		test1 = 0x40|0x04; break;
-			case 1:		test1 = 0x60|0x07; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-	}
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-}
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	config_art_rwp_pio(drive, pio);
-	drive->current_speed = speed;
-	return ide_config_drive_speed(drive, speed);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			drive_pci, reg;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
-	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
-	       drive->dn, speed);
-#endif
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return ide_dma_off;
-	}
-
-#ifdef BROKEN_LEVEL
-#ifdef DEBUG
-	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
-#endif
-	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
-#endif
-
-	pci_read_config_byte(dev, drive_pci+1, &reg);
-	/* Disable UDMA bit for non UDMA modes on UDMA chips */
-	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
-		reg &= 0x7F;
-		pci_write_config_byte(dev, drive_pci+1, reg);
-	}
-
-	/* Config chip for mode */
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			/* Force the UDMA bit on if we want to use UDMA */
-			reg |= 0x80;
-			/* clean reg cycle time bits */
-			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-				 << cycle_time_offset[chipset_family]);
-			/* set reg cycle time bits */
-			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
-				<< cycle_time_offset[chipset_family];
-			pci_write_config_byte(dev, drive_pci+1, reg);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
-		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
-		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
-		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
-		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));	
-	}
-	drive->current_speed = speed;
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
-#endif
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	byte			speed = 0;
-
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte udma_66		= eighty_ninty_three(drive);
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
-	       drive->dn, ultra);
-#endif
-
-	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
-		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_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
-		return ((int) ide_dma_off_quietly);
-
-	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-
-	sis5513_tune_chipset(drive, speed);
-
-	return ((int)	((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);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_dma_action_t dma_func	= ide_dma_off_quietly;
-
-	(void) config_chipset_for_pio(drive, 5);
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
-			   (id->eide_dma_time > 150)) {
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/* initiates/aborts (U)DMA read/write operations on a drive. */
-int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			config_drive_art_rwp(drive);
-			config_art_rwp_pio(drive, 5);
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/* Chip detection and general config */
-unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *host;
-	int i = 0;
-
-	/* Find the chip */
-	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
-		host = pci_find_device (PCI_VENDOR_ID_SI,
-					SiSHostChipInfo[i].host_id,
-					NULL);
-		if (!host)
-			continue;
-
-		host_dev = host;
-		chipset_family = SiSHostChipInfo[i].chipset_family;
-		printk(SiSHostChipInfo[i].name);
-		printk("\n");
-
-#ifdef DEBUG
-		sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
-		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
-			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
-		}
-	}
-
-	/* Make general config ops here
-	   1/ tell IDE channels to operate in Compabitility mode only
-	   2/ tell old chips to allow per drive IDE timings */
-	if (host_dev) {
-		byte reg;
-		switch(chipset_family) {
-			case ATA_133:
-			case ATA_100:
-				/* Set compatibility bit */
-				pci_read_config_byte(dev, 0x49, &reg);
-				if (!(reg & 0x01)) {
-					pci_write_config_byte(dev, 0x49, reg|0x01);
-				}
-				break;
-			case ATA_100a:
-			case ATA_66:
-				/* On ATA_66 chips the bit was elsewhere */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x04)) {
-					pci_write_config_byte(dev, 0x52, reg|0x04);
-				}
-				break;
-			case ATA_33:
-				/* On ATA_33 we didn't have a single bit to set */
-				pci_read_config_byte(dev, 0x09, &reg);
-				if ((reg & 0x0f) != 0x00) {
-					pci_write_config_byte(dev, 0x09, reg&0xf0);
-				}
-			case ATA_16:
-				/* force per drive recovery and active timings
-				   needed on ATA_33 and below chips */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x08)) {
-					pci_write_config_byte(dev, 0x52, reg|0x08);
-				}
-				break;
-			case ATA_00:
-			default: break;
-		}
-
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-		if (!sis_proc) {
-			sis_proc = 1;
-			bmide_dev = dev;
-			sis_display_info = &sis_get_info;
-		}
-#endif
-	}
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
-#endif
-	return 0;
-}
-
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
-{
-	byte reg48h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x20 : 0x10;
-	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
-
-	if (chipset_family >= ATA_66) {
-		ata66 = (reg48h & mask) ? 0 : 1;
-	}
-        return ata66;
-}
-
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
-{
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &sis5513_tune_drive;
-	hwif->speedproc = &sis5513_tune_chipset;
-
-	if (!(hwif->dma_base))
-		return;
-
-	if (host_dev) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (chipset_family > ATA_16) {
-			hwif->autodma = noautodma ? 0 : 1;
-			hwif->dmaproc = &sis5513_dmaproc;
-		} else {
-#endif
-			hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		}
-#endif
-	}
-	return;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sl82c105.c linux-2.4.21-rc3/drivers/ide/sl82c105.c
--- linux-2.4.20/drivers/ide/sl82c105.c	2001-09-07 17:45:30.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,274 +0,0 @@
-/*
- * linux/drivers/ide/sl82c105.c
- *
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- *  -- Russell King (15/11/98) linux@arm.linux.org.uk
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "ide_modes.h"
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface.  This has protection against run-away
- * timings.
- */
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
-{
-	unsigned int cmd_on;
-	unsigned int cmd_off;
-
-	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
-
-	if (cmd_on > 32)
-		cmd_on = 32;
-	if (cmd_on == 0)
-		cmd_on = 1;
-
-	if (cmd_off > 32)
-		cmd_off = 32;
-	if (cmd_off == 0)
-		cmd_off = 1;
-
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
-}
-
-/*
- * Configure the drive and chipset for PIO
- */
-static void config_for_pio(ide_drive_t *drive, int pio, int report)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	ide_pio_data_t p;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int xfer_mode, reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
-	switch (pio) {
-	default:
-	case 0:		xfer_mode = XFER_PIO_0;		break;
-	case 1:		xfer_mode = XFER_PIO_1;		break;
-	case 2:		xfer_mode = XFER_PIO_2;		break;
-	case 3:		xfer_mode = XFER_PIO_3;		break;
-	case 4:		xfer_mode = XFER_PIO_4;		break;
-	}
-
-	if (ide_config_drive_speed(drive, xfer_mode) == 0)
-		drv_ctrl = get_timing_sl82c105(&p);
-
-	if (drive->using_dma == 0) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg, drv_ctrl);
-		pci_read_config_word(dev, reg, &drv_ctrl);
-
-		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
-		}
-	}
-}
-
-/*
- * Configure the drive and the chipset for DMA
- */
-static int config_for_dma(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
-		drv_ctrl = 0x0240;
-
-	pci_write_config_word(dev, reg, drv_ctrl);
-
-	return 0;
-}
-
-/*
- * Check to see if the drive and
- * chipset is capable of DMA mode
- */
-static int sl82c105_check_drive(ide_drive_t *drive)
-{
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	do {
-		struct hd_driveid *id = drive->id;
-		ide_hwif_t *hwif = HWIF(drive);
-
-		if (!hwif->autodma)
-			break;
-
-		if (!id || !(id->capability & 1))
-			break;
-
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			break;
-		}
-
-		if (id->field_valid & 2) {
-			if  (id->dma_mword & 7 || id->dma_1word & 7)
-				dma_func = ide_dma_on;
-			break;
-		}
-
-		if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			dma_func = ide_dma_on;
-			break;
-		}
-	} while (0);
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * Our own dmaproc, only to intercept ide_dma_check
- */
-static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-	case ide_dma_check:
-		return sl82c105_check_drive(drive);
-	case ide_dma_on:
-		if (config_for_dma(drive))
-			func = ide_dma_off;
-		/* fall through */
-	case ide_dma_off_quietly:
-	case ide_dma_off:
-		config_for_pio(drive, 4, 0);
-		break;
-	default:
-		break;
-	}
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
-{
-	config_for_pio(drive, pio, 1);
-
-	/*
-	 * We support 32-bit I/O on this interface, and it
-	 * doesn't have problems with interrupts.
-	 */
-	drive->io_32bit = 1;
-	drive->unmask = 1;
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
-{
-	struct pci_dev *bridge;
-	unsigned char rev;
-
-	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
-
-	/*
-	 * If we are part of a Winbond 553
-	 */
-	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
-		return -1;
-
-	if (bridge->bus != dev->bus ||
-	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
-		return -1;
-
-	/*
-	 * We need to find function 0's revision, not function 1
-	 */
-	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
-
-	return rev;
-}
-
-/*
- * Enable the PCI device
- */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
-{
-	unsigned char ctrl_stat;
-
-	/*
-	 * Enable the ports
-	 */
-	pci_read_config_byte(dev, 0x40, &ctrl_stat);
-	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
-
-	return dev->irq;
-}
-
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
-	unsigned int rev;
-	byte dma_state;
-
-	dma_state = inb(dma_base + 2);
-	rev = sl82c105_bridge_revision(hwif->pci_dev);
-	if (rev <= 5) {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-		dma_state &= ~0x60;
-	} else {
-		dma_state |= 0x60;
-		hwif->autodma = 1;
-	}
-	outb(dma_state, dma_base + 2);
-
-	hwif->dmaproc = NULL;
-	ide_setup_dma(hwif, dma_base, 8);
-	if (hwif->dmaproc)
-		hwif->dmaproc = sl82c105_dmaproc;
-}
-
-/*
- * Initialise the chip
- */
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
-{
-	hwif->tuneproc = tune_sl82c105;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/slc90e66.c linux-2.4.21-rc3/drivers/ide/slc90e66.c
--- linux-2.4.20/drivers/ide/slc90e66.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,396 +0,0 @@
-/*
- *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
- *
- *  Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- * 00:07.1 IDE interface: EFAR Microsystems:
- * 		Unknown device 9130 (prog-if 8a [Master SecP PriP])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV-
- * 		VGASnoop- ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium
- * 		>TAbort- <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 64
- * Interrupt: pin A routed to IRQ 255
- * Region 4: I/O ports at 1050
- *
- * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00
- * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00
- * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define SLC90E66_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SLC90E66_TIMINGS
-
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int slc90e66_get_info(char *, char **, off_t, int);
-extern int (*slc90e66_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 slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x47, &reg47);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-        /*
-         * 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");
-	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 enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg4a&0x04)==0x04) ? "4" :
-			((reg4a&0x03)==0x03) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4a&0x40)==0x40) ? "4" :
-			((reg4a&0x30)==0x30) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4b&0x04)==0x04) ? "4" :
-			((reg4b&0x03)==0x03) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg4b&0x40)==0x40) ? "4" :
-			((reg4b&0x30)==0x30) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte slc90e66_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *
- */
-static byte slc90e66_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
-					   << (HWIF(drive)->index ? 4 : 0)));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 7 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-
-	switch(speed) {
-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		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) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if ((reg4a & u_speed) != u_speed) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_read_config_word(dev, 0x4a, &reg4a);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-	}
-
-	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
-
-#if SLC90E66_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SLC90E66_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	int ultra		= 1;
-	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)) {
-		speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) slc90e66_tune_chipset(drive, speed);
-
-	return ((int)	((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);
-}
-
-static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			 return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!slc90e66_proc) {
-		slc90e66_proc = 1;
-		bmide_dev = dev;
-		slc90e66_display_info = &slc90e66_get_info;
-	}
-#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
-{
-#if 1
-	byte reg47 = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x01 : 0x02;	/* bit0:Primary */
-
-	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
-
-	ata66 = (reg47 & mask) ? 0 : 1;	/* bit[0(1)]: 0:80, 1:40 */
-#else
-	byte ata66 = 0;
-#endif
-	return ata66;
-}
-
-void __init ide_init_slc90e66 (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &slc90e66_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-	hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA 
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &slc90e66_dmaproc;
-	hwif->speedproc = &slc90e66_tune_chipset;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/trm290.c linux-2.4.21-rc3/drivers/ide/trm290.c
--- linux-2.4.20/drivers/ide/trm290.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/trm290.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,289 +0,0 @@
-/*
- *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
- *
- *  Copyright (c) 1997-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- * This module provides support for the bus-master IDE DMA function
- * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board.  The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL!  It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- *	bit7 must always be written as "1"
- *	bits6-2 undefined
- *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
- *	bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- *	bits7-2 undefined
- *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- *	bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- *	bits7-5 undefined
- *	bit4 legacy_header: 1=present, 0=absent
- *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- *	bit5 0=enabled master burst access (default), 1=disable  (write only)
- *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- *	bit3 0=primary IDE channel, 1=secondary IDE channel
- *	bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- *	two sets of seven config registers,
- *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- *	each index defined below:
- *
- * Index-0 Base address register for command block (word)
- *	defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- *	bit7 1=DMA enable, 0=DMA disable
- *	bit6 1=activate IDE_RESET, 0=no action (default)
- *	bit5 1=enable IORDY, 0=disable IORDY (default)
- *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- *	bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- *	bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- *	bit7 1=enable_readahead, 0=disable_readahead(default)
- *	bit6 1=clear_FIFO, 0=no_action
- *	bit5 undefined
- *	bit4 mode4 timing control: 1=enable, 0=disable(default)
- *	bit3 undefined
- *	bit2 undefined
- *	bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- *	defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- *	standard PCI "clk" (clock) counts, default value = 0xf5
- *
- *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
- *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
- *				011=4clk, 100=5clk, 101=6clk,
- *				110=8clk, 111=12clk
- *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
- *				011=5clk, 100=6clk, 101=8clk,
- *				110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- *	same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int reg;
-	unsigned long flags;
-
-	/* select PIO or DMA */
-	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	if (reg != hwif->select_data) {
-		hwif->select_data = reg;
-		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
-		outw(reg & 0xff, hwif->config_data);
-	}
-
-	/* enable IRQ if not probing */
-	if (drive->present) {
-		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
-		outw(reg, hwif->config_data+3);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void trm290_selectproc (ide_drive_t *drive)
-{
-	trm290_prepare_drive(drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int count, reading = 2, writing = 0;
-
-	switch (func) {
-		case ide_dma_write:
-			reading = 0;
-			writing = 1;
-#ifdef TRM290_NO_DMA_WRITES
-			break;	/* always use PIO for writes */
-#endif
-		case ide_dma_read:
-			if (!(count = ide_build_dmatable(drive, func)))
-				break;		/* try PIO instead of DMA */
-			trm290_prepare_drive(drive, 1);	/* select DMA xfer */
-			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
-			drive->waiting_for_dma = 1;
-			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_begin:
-			return 0;
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (inw(hwif->dma_base+2) != 0x00ff);
-		case ide_dma_test_irq:
-			return (inw(hwif->dma_base+2) == 0x00ff);
-		default:
-			return ide_dmaproc(func, drive);
-	}
-	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-	return 1;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Invoked from ide-dma.c at boot time.
- */
-void __init ide_init_trm290 (ide_hwif_t *hwif)
-{
-	unsigned int cfgbase = 0;
-	unsigned long flags;
-	byte reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_trm290;
-	cfgbase = pci_resource_start(dev, 4);
-	if ((dev->class & 5) && cfgbase)
-	{
-		hwif->config_data = cfgbase;
-		printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
-	} else {
-		hwif->config_data = 0x3df0;
-		printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
-	}
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
-	hwif->select_data = 0x21;			/* select PIO as default */
-	outb(hwif->select_data, hwif->config_data);
-	reg = inb(hwif->config_data+3);			/* get IRQ info */
-	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
-	outb(reg, hwif->config_data+3);
-	__restore_flags(flags);	/* local CPU only */
-
-	if ((reg & 0x10))
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &trm290_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &trm290_selectproc;
-	hwif->autodma = 0;				/* play it safe for now */
-#if 1
-	{
-		/*
-		 * My trm290-based card doesn't seem to work with all possible values
-		 * for the control basereg, so this kludge ensures that we use only
-		 * values that are known to work.  Ugh.		-ml
-		 */
-		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
-		static unsigned short next_offset = 0;
-
-		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
-		old = inw(hwif->config_data) & ~1;
-		if (old != compat && inb(old+2) == 0xff) {
-			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
-#if 1
-			if (ide_check_region(compat + 2, 1))
-				printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2));
-			/*
-			 * The region check is not needed; however.........
-			 * Since this is the checked in ide-probe.c,
-			 * this is only an assignment.
-			 */
-#endif
-			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
-			outw(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
-		}
-	}
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/umc8672.c linux-2.4.21-rc3/drivers/ide/umc8672.c
--- linux-2.4.20/drivers/ide/umc8672.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/umc8672.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,160 +0,0 @@
-/*
- *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- *  This file provides support for the advanced features
- *  of the UMC 8672 IDE interface.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	now configs/compiles separate from ide.c  -ml
- *  Version 0.03	enhanced auto-tune, fix display bug
- *  Version 0.05	replace sti() with restore_flags()  -ml
- *			add detection of possible race condition  -ml
- */
-
-/*
- * VLB Controller Support from 
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the 
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO		/* some systems can safely undef this */
-
-#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/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0      1              /* DOS measured drive speeds */
-#define UMC_DRIVE1      1              /* 0 to 11 allowed */
-#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
-#define UMC_DRIVE3      1              /* In case of crash reduce speed */
-
-static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const byte pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
-
-/*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const byte speedtab [3][12] = {
-	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
-
-static void out_umc (char port,char wert)
-{
-	outb_p (port,0x108);
-	outb_p (wert,0x109);
-}
-
-static inline byte in_umc (char port)
-{
-	outb_p (port,0x108);
-	return inb_p (0x109);
-}
-
-static void umc_set_speeds (byte speeds[])
-{
-	int i, tmp;
-
-	outb_p (0x5A,0x108); /* enable umc */
-
-	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
-	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
-	tmp = 0;
-	for (i = 3; i >= 0; i--)
-	{
-		tmp = (tmp << 2) | speedtab[1][speeds[i]];
-	}
-	out_umc (0xdc,tmp);
-	for (i = 0;i < 4; i++)
-	{
-		out_umc (0xd0+i,speedtab[2][speeds[i]]);
-		out_umc (0xd8+i,speedtab[2][speeds[i]]);
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
-		speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void tune_umc (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	if (hwgroup && hwgroup->handler != NULL) {
-		printk("umc8672: other interface is busy: exiting tune_umc()\n");
-	} else {
-		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-		umc_set_speeds (current_speeds);
-	}
-	restore_flags(flags);	/* all CPUs */
-}
-
-void __init init_umc8672 (void)	/* called from ide.c */
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	if (check_region(0x108, 2)) {
-		__restore_flags(flags);
-		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
-		return;
-	}
-	outb_p (0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0)
-	{
-		__restore_flags(flags);	/* local CPU only */
-		printk ("umc8672: not found\n");
-		return;  
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	umc_set_speeds (current_speeds);
-	__restore_flags(flags);	/* local CPU only */
-
-	request_region(0x108, 2, "umc8672");
-	ide_hwifs[0].chipset = ide_umc8672;
-	ide_hwifs[1].chipset = ide_umc8672;
-	ide_hwifs[0].tuneproc = &tune_umc;
-	ide_hwifs[1].tuneproc = &tune_umc;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/via82cxxx.c linux-2.4.21-rc3/drivers/ide/via82cxxx.c
--- linux-2.4.20/drivers/ide/via82cxxx.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ide/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,532 +0,0 @@
-/*
- * Version 3.35
- *
- * VIA IDE driver for Linux. Supported southbridges:
- *
- *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- *   vt8235
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- *
- * Based on the work of:
- *	Michel Aubry
- *	Jeff Garzik
- *	Andre Hedrick
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-
-#include "ide-timing.h"
-
-#define VIA_IDE_ENABLE		0x40
-#define VIA_IDE_CONFIG		0x41
-#define VIA_FIFO_CONFIG		0x43
-#define VIA_MISC_1		0x44
-#define VIA_MISC_2		0x45
-#define VIA_MISC_3		0x46
-#define VIA_DRIVE_TIMING	0x48
-#define VIA_8BIT_TIMING		0x4e
-#define VIA_ADDRESS_SETUP	0x4c
-#define VIA_UDMA_TIMING		0x50
-
-#define VIA_UDMA		0x007
-#define VIA_UDMA_NONE		0x000
-#define VIA_UDMA_33		0x001
-#define VIA_UDMA_66		0x002
-#define VIA_UDMA_100		0x003
-#define VIA_UDMA_133		0x004
-#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
-#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
-
-#ifndef PCI_DEVICE_ID_VIA_8235
-#define PCI_DEVICE_ID_VIA_8235 0x3177
-#endif
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
-	char *name;
-	unsigned short id;
-	unsigned char rev_min;
-	unsigned char rev_max;
-	unsigned short flags;
-} via_isa_bridges[] = {
-#ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
-#endif
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-	{ NULL }
-};
-
-static struct via_isa_bridge *via_config;
-static unsigned char via_enabled;
-static unsigned int via_80w;
-static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
-
-/*
- * VIA /proc entry.
- */
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-int via_proc, via_base;
-static struct pci_dev *bmide_dev, *isa_dev;
-extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static char *via_control3[] = { "No limit", "64", "128", "192" };
-
-#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
-#define via_print_drive(name, format, arg...)\
-	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
-
-static int via_get_info(char *buffer, char **addr, off_t offset, int count)
-{
-	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
-		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
-	struct pci_dev *dev = bmide_dev;
-	unsigned int v, u, i;
-	unsigned short c, w;
-	unsigned char t, x;
-	char *p = buffer;
-
-	via_print("----------VIA BusMastering IDE Configuration----------------");
-
-	via_print("Driver Version:                     3.35");
-	via_print("South Bridge:                       VIA %s", via_config->name);
-
-	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
-	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
-	via_print("Revision:                           ISA %#x IDE %#x", t, x);
-	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
-
-	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
-
-	pci_read_config_byte(dev, VIA_MISC_1, &t);
-	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
-	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
-	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_MISC_3, &t);
-	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
-
-	via_print("-----------------------Primary IDE-------Secondary IDE------");
-	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
-	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
-	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
-	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
-	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
-
-	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
-	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
-
-	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
-
-	via_print("-------------------drive0----drive1----drive2----drive3-----");
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
-	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
-
-	if (via_config->flags & VIA_UDMA)
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-	else u = 0;
-
-	for (i = 0; i < 4; i++) {
-
-		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
-		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
-		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
-		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
-		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
-		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
-		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
-		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
-		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
-
-		speed[i] = 2 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
-
-		if (!uen[i] || !den[i])
-			continue;
-
-		switch (via_config->flags & VIA_UDMA) {
-
-			case VIA_UDMA_33:
-				speed[i] = 2 * via_clock / udma[i];
-				cycle[i] = 1000000 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_66:
-				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
-				break;
-
-			case VIA_UDMA_100:
-				speed[i] = 6 * via_clock / udma[i];
-				cycle[i] = 333333 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_133:
-				speed[i] = 8 * via_clock / udma[i];
-				cycle[i] = 250000 * udma[i] / via_clock;
-				break;
-		}
-	}
-
-	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
-
-	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
-	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
-	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
-	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
-	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
-	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
-
-	return p - buffer;	/* hoping it is less than 4K... */
-}
-
-#endif
-
-/*
- * via_set_speed() writes timing values to the chipset registers
- */
-
-static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
-{
-	unsigned char t;
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
-
-	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
-		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
-
-	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
-		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
-		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		default: return;
-	}
-
-	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
-}
-
-/*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
-
-static int via_set_drive(ide_drive_t *drive, unsigned char speed)
-{
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
-	struct ide_timing t, p;
-	unsigned int T, UT;
-
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
-
-	T = 1000000000 / via_clock;
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:   UT = T;   break;
-		case VIA_UDMA_66:   UT = T/2; break;
-		case VIA_UDMA_100:  UT = T/3; break;
-		case VIA_UDMA_133:  UT = T/4; break;
-		default: UT = T;
-	}
-
-	ide_timing_compute(drive, speed, &t, T, UT);
-
-	if (peer->present) {
-		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-	}
-
-	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-/*
- * via82cxxx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
- */
-
-static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
-{
-	if (!((via_enabled >> HWIF(drive)->channel) & 1))
-		return;
-
-	if (pio == 255) {
-		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
-	}
-
-	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-
-/*
- * via82cxxx_dmaproc() is a callback from upper layers that can do
- * a lot, but we use it for DMA/PIO tuning only, delegating everything
- * else to the default ide_dmaproc().
- */
-
-int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-
-	if (func == ide_dma_check) {
-
-		short w80 = HWIF(drive)->udma_four;
-
-		short speed = ide_find_best_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
-
-		via_set_drive(drive, speed);
-
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
-			? ide_dma_on : ide_dma_off_quietly;
-	}
-
-	return ide_dmaproc(func, drive);
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *isa = NULL;
-	unsigned char t, v;
-	unsigned int u;
-	int i;
-
-/*
- * Find the ISA bridge to see how good the IDE is.
- */
-
-	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
-			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
-
-			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-			if (t >= via_config->rev_min && t <= via_config->rev_max)
-				break;
-		}
-
-	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
-		return -ENODEV;
-	}
-
-/*
- * Check 80-wire cable presence and setup Clk66.
- */
-
-	switch (via_config->flags & VIA_UDMA) {
-
-		case VIA_UDMA_66:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
-			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
-					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
-			break;
-
-		case VIA_UDMA_100:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-		case VIA_UDMA_133:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-	}
-
-	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a and 686 */
-		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
-	}
-
-/*
- * Check whether interfaces are enabled.
- */
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
-
-/*
- * Set up FIFO sizes and thresholds.
- */
-
-	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
-	if (via_config->flags & VIA_BAD_PREQ)				/* Disable PREQ# till DDACK# */
-		t &= 0x7f;						/* Would crash on 586b rev 41 */
-
-	if (via_config->flags & VIA_SET_FIFO) {				/* Fix FIFO split between channels */
-		t &= (t & 0x9f);
-		switch (via_enabled) {
-			case 1: t |= 0x00; break;			/* 16 on primary */
-			case 2: t |= 0x60; break;			/* 16 on secondary */
-			case 3: t |= 0x20; break;			/* 8 pri 8 sec */
-		}
-	}
-
-	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
-/*
- * Determine system bus clock.
- */
-
-	via_clock = system_bus_clock() * 1000;
-
-	switch (via_clock) {
-		case 33000: via_clock = 33333; break;
-		case 37000: via_clock = 37500; break;
-		case 41000: via_clock = 41666; break;
-	}
-
-	if (via_clock < 20000 || via_clock > 50000) {
-		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
-		via_clock = 33333;
-	}
-
-/*
- * Print the boot message.
- */
-
-	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
-		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
-
-/*
- * Setup /proc/ide/via entry.
- */
-
-#ifdef CONFIG_PROC_FS
-	if (!via_proc) {
-		via_base = pci_resource_start(dev, 4);
-		bmide_dev = dev;
-		isa_dev = isa;
-		via_display_info = &via_get_info;
-		via_proc = 1;
-	}
-#endif
-
-	return 0;
-}
-
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
-{
-	return ((via_enabled & via_80w) >> hwif->channel) & 1;
-}
-
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
-{
-	int i;
-
-	hwif->tuneproc = &via82cxxx_tune_drive;
-	hwif->speedproc = &via_set_drive;
-	hwif->autodma = 0;
-
-	for (i = 0; i < 2; i++) {
-		hwif->drives[i].io_32bit = 1;
-		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &via82cxxx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((via_enabled >> hwif->channel) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/Makefile linux-2.4.21-rc3/drivers/ieee1394/Makefile
--- linux-2.4.20/drivers/ieee1394/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/Makefile	2003-05-22 22:06:53.000000000 +0000
@@ -4,11 +4,11 @@
 
 O_TARGET := ieee1394drv.o
 
-export-objs := ieee1394_core.o ohci1394.o cmp.o
+export-objs := ieee1394_core.o ohci1394.o cmp.o iso.o
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o nodemgr.o
+		 highlevel.o csr.o nodemgr.o dma.o iso.o
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/amdtp.c linux-2.4.21-rc3/drivers/ieee1394/amdtp.c
--- linux-2.4.20/drivers/ieee1394/amdtp.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/amdtp.c	2003-05-22 22:06:50.000000000 +0000
@@ -228,7 +228,7 @@
 	/* The cycle_count and cycle_offset fields are used for the
 	 * synchronization timestamps (syt) in the cip header.  They
 	 * are incremented by at least a cycle every time we put a
-	 * time stamp in a packet.  As we dont time stamp all
+	 * time stamp in a packet.  As we don't time stamp all
 	 * packages, cycle_count isn't updated in every cycle, and
 	 * sometimes it's incremented by 2.  Thus, we have
 	 * cycle_count2, which is simply incremented by one with each
@@ -263,13 +263,13 @@
 	struct hpsb_host *host;
 	struct ti_ohci *ohci;
 	struct list_head stream_list;
+	devfs_handle_t devfs;
 	spinlock_t stream_list_lock;
-	struct list_head link;
 };
 
-static struct hpsb_highlevel *amdtp_highlevel;
-static LIST_HEAD(host_list);
-static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+static devfs_handle_t devfs_handle;
+
+static struct hpsb_highlevel amdtp_highlevel;
 
 /* FIXME: This doesn't belong here... */
 
@@ -345,7 +345,7 @@
 {
 	u32 syt_cycle, cycle_count, start_cycle;
 
-	cycle_count = reg_read(s->host->host->hostdata,
+	cycle_count = reg_read(s->host->ohci,
 			       OHCI1394_IsochronousCycleTimer) >> 12;
 	syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f;
 
@@ -598,6 +598,8 @@
 	struct buffer *b;
 
 	b = kmalloc(sizeof *b + size, SLAB_KERNEL);
+	if (b == NULL)
+		return NULL;
 	b->head = 0;
 	b->tail = 0;
 	b->length = 0;
@@ -688,7 +690,7 @@
 		return get_iec958_header_bits(s, sub_frame, sample);
 		
 	case AMDTP_FORMAT_RAW:
-		return 0x40000000;
+		return 0x40;
 
 	default:
 		return 0;
@@ -746,7 +748,7 @@
 
 		/* This next addition should be modulo 8000 (0x1f40),
 		 * but we only use the lower 4 bits of cycle_count, so
-		 * we dont need the modulo. */
+		 * we don't need the modulo. */
 		atomic_add(s->cycle_offset.integer / 3072, &s->cycle_count);
 		s->cycle_offset.integer %= 3072;
 	}
@@ -834,7 +836,8 @@
 
 	max_packet_size = max_nevents * s->dimension * 4 + 8;
 	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
-					 max_packet_size, 0, 0, SLAB_KERNEL);
+					 max_packet_size, 0, 0 ,SLAB_KERNEL);
+
 	if (s->packet_pool == NULL)
 		return -1;
 
@@ -1021,6 +1024,7 @@
 	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
 					     sizeof(struct descriptor_block),
 					     16, 0, SLAB_KERNEL);
+
 	if (s->descriptor_pool == NULL) {
 		kfree(s->input);
 		kfree(s);
@@ -1107,7 +1111,7 @@
 	 */
 
 	for (i = 0; i < count; i += length) {
-		p = buffer_put_bytes(s->input, count, &length);
+		p = buffer_put_bytes(s->input, count - i, &length);
 		copy_from_user(p, buffer + i, length);
 		if (s->input->length < s->input->size)
 			continue;
@@ -1163,15 +1167,9 @@
 static int amdtp_open(struct inode *inode, struct file *file)
 {
 	struct amdtp_host *host;
+	int i = ieee1394_file_to_instance(file);
 
-	/* FIXME: We just grab the first registered host */
-	spin_lock(&host_list_lock);
-	if (!list_empty(&host_list))
-		host = list_entry(host_list.next, struct amdtp_host, link);
-	else
-		host = NULL;
-	spin_unlock(&host_list_lock);
-
+	host = hpsb_get_hostinfo_bykey(&amdtp_highlevel, i);
 	if (host == NULL)
 		return -ENODEV;
 
@@ -1206,44 +1204,49 @@
 static void amdtp_add_host(struct hpsb_host *host)
 {
 	struct amdtp_host *ah;
+	int minor;
+	char name[16];
 
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)
 		return;
 
-	ah = kmalloc(sizeof *ah, SLAB_KERNEL);
+	ah = hpsb_create_hostinfo(&amdtp_highlevel, host, sizeof(*ah));
+	if (!ah) {
+		HPSB_ERR("amdtp: Unable able to alloc hostinfo");
+		return;
+	}
+
 	ah->host = host;
 	ah->ohci = host->hostdata;
+
+	hpsb_set_hostinfo_key(&amdtp_highlevel, host, ah->ohci->id);
+
+	minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id;
+
+	sprintf(name, "%d", ah->ohci->id);
+
 	INIT_LIST_HEAD(&ah->stream_list);
 	spin_lock_init(&ah->stream_list_lock);
 
-	spin_lock_irq(&host_list_lock);
-	list_add_tail(&ah->link, &host_list);
-	spin_unlock_irq(&host_list_lock);
+	ah->devfs = devfs_register(devfs_handle, name,
+				   DEVFS_FL_AUTO_OWNER,
+				   IEEE1394_MAJOR, minor,
+				   S_IFCHR | S_IRUSR | S_IWUSR,
+				   &amdtp_fops, NULL);
 }
 
 static void amdtp_remove_host(struct hpsb_host *host)
 {
-	struct list_head *lh;
-	struct amdtp_host *ah;
+	struct amdtp_host *ah = hpsb_get_hostinfo(&amdtp_highlevel, host);
 
-	spin_lock_irq(&host_list_lock);
-	list_for_each(lh, &host_list) {
-		if (list_entry(lh, struct amdtp_host, link)->host == host) {
-			list_del(lh);
-			break;
-		}
-	}
-	spin_unlock_irq(&host_list_lock);
-	
-	if (lh != &host_list) {
-		ah = list_entry(lh, struct amdtp_host, link);
-		kfree(ah);
-	}
-	else
-		HPSB_ERR("remove_host: bogus ohci host: %p", host);
+	if (ah)
+		devfs_unregister(ah->devfs);
+
+	return;
 }
 
-static struct hpsb_highlevel_ops amdtp_highlevel_ops = {
+static struct hpsb_highlevel amdtp_highlevel = {
+	.name =		"amdtp",
 	.add_host =	amdtp_add_host,
 	.remove_host =	amdtp_remove_host,
 };
@@ -1264,13 +1267,9 @@
  		return -EIO;
  	}
 
-	amdtp_highlevel = hpsb_register_highlevel ("amdtp",
-						   &amdtp_highlevel_ops);
-	if (amdtp_highlevel == NULL) {
-		HPSB_ERR("amdtp: unable to register highlevel ops");
-		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
-		return -EIO;
-	}
+	devfs_handle = devfs_mk_dir(NULL, "amdtp", NULL);
+
+	hpsb_register_highlevel(&amdtp_highlevel);
 
 	HPSB_INFO("Loaded AMDTP driver");
 
@@ -1279,7 +1278,8 @@
 
 static void __exit amdtp_exit_module (void)
 {
-        hpsb_unregister_highlevel(amdtp_highlevel);
+        hpsb_unregister_highlevel(&amdtp_highlevel);
+	devfs_unregister(devfs_handle);
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
 
 	HPSB_INFO("Unloaded AMDTP driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/amdtp.h linux-2.4.21-rc3/drivers/ieee1394/amdtp.h
--- linux-2.4.20/drivers/ieee1394/amdtp.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/amdtp.h	2003-05-22 22:06:47.000000000 +0000
@@ -3,8 +3,8 @@
 #ifndef __AMDTP_H
 #define __AMDTP_H
 
-#include <asm/ioctl.h>
 #include <asm/types.h>
+#include "ieee1394-ioctl.h"
 
 /* The userspace interface for the Audio & Music Data Transmission
  * Protocol driver is really simple. First, open /dev/amdtp, use the
@@ -57,13 +57,6 @@
  *
  */
 
-/* We use '#' for our ioctl magic number because it's cool. */
-
-#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_PLUG    _IOW('#', 1, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_PING    _IOW('#', 2, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_ZAP     _IO('#', 3)
-
 enum {
 	AMDTP_FORMAT_RAW,
 	AMDTP_FORMAT_IEC958_PCM,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/cmp.c linux-2.4.21-rc3/drivers/ieee1394/cmp.c
--- linux-2.4.20/drivers/ieee1394/cmp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/cmp.c	2003-05-22 22:06:27.000000000 +0000
@@ -64,8 +64,6 @@
 		quadlet_t impr_quadlet;
 	} v;
 	struct plug ipcr[2];
-
-	struct list_head link;
 };
 
 enum {
@@ -76,32 +74,7 @@
 #define CSR_PCR_MAP      0x900
 #define CSR_PCR_MAP_END  0x9fc
 
-static struct hpsb_highlevel *cmp_highlevel;
-
-static LIST_HEAD(host_list);
-static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
-
-static struct cmp_host *
-lookup_cmp_host(struct hpsb_host *host)
-{
-	struct cmp_host *ch;
-	struct list_head *lh;
-	unsigned long flags;
-
-	ch = NULL;
-	spin_lock_irqsave(&host_list_lock, flags);
-	list_for_each(lh, &host_list) {
-		ch = list_entry(lh, struct cmp_host, link);
-		if (ch->host == host)
-			break;
-	}
-	spin_unlock_irqrestore(&host_list_lock, flags);
-
-	if (lh == &host_list)
-		return NULL;
-	else
-		return ch;
-}
+static struct hpsb_highlevel cmp_highlevel;
 
 struct cmp_pcr *
 cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
@@ -111,7 +84,7 @@
 	struct cmp_host *ch;
 	struct plug *plug;
 
-	ch = lookup_cmp_host(host);
+	ch = hpsb_get_hostinfo(&cmp_highlevel, host);
 
 	if (opcr_number >= ch->u.ompr.nplugs ||
 	    ch->opcr[opcr_number].update != NULL)
@@ -134,7 +107,7 @@
 	struct cmp_host *ch;
 	struct plug *plug;
 
-	ch = lookup_cmp_host(host);
+	ch = hpsb_get_hostinfo(&cmp_highlevel, host);
 	plug = (struct plug *)opcr;
 	if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
 
@@ -156,50 +129,36 @@
 
 static void cmp_add_host(struct hpsb_host *host)
 {
-	struct cmp_host *ch;
+	struct cmp_host *ch = hpsb_create_hostinfo(&cmp_highlevel, host, sizeof (*ch));
 
-	ch = kmalloc(sizeof *ch, SLAB_KERNEL);
 	if (ch == NULL) {
 		HPSB_ERR("Failed to allocate cmp_host");
 		return;
 	}
-	memset(ch, 0, sizeof *ch);
+
 	ch->host = host;
 	ch->u.ompr.rate = SPEED_100;
 	ch->u.ompr.bcast_channel_base = 63;
 	ch->u.ompr.nplugs = 2;
-	reset_plugs(ch);
 
-	spin_lock_irq(&host_list_lock);
-	list_add_tail(&ch->link, &host_list);
-	spin_unlock_irq(&host_list_lock);
-}
-
-static void cmp_host_reset(struct hpsb_host *host)
-{
-	struct cmp_host *ch;
-
-	ch = lookup_cmp_host(host);
-	if (ch == NULL) BUG();
 	reset_plugs(ch);
 }
 
-static void cmp_remove_host(struct hpsb_host *host)
+static void cmp_host_reset(struct hpsb_host *host)
 {
 	struct cmp_host *ch;
 
-	ch = lookup_cmp_host(host);
-	if (ch == NULL) BUG();
-
-	spin_lock_irq(&host_list_lock);
-	list_del(&ch->link);
-	spin_unlock_irq(&host_list_lock);
+	ch = hpsb_get_hostinfo(&cmp_highlevel, host);
+	if (ch == NULL) {
+		HPSB_ERR("cmp: Tried to reset unknown host");
+		return;
+	}
 
-	kfree(ch);
+	reset_plugs(ch);
 }
 
 static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		    u64 addr, unsigned int length)
+		    u64 addr, unsigned int length, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
@@ -208,7 +167,7 @@
 	if (length != 4)
 		return RCODE_TYPE_ERROR;
 
-	ch = lookup_cmp_host(host);
+	ch = hpsb_get_hostinfo(&cmp_highlevel, host);
 	if (csraddr == 0x900) {
 		*buf = cpu_to_be32(ch->u.ompr_quadlet);
 		return RCODE_COMPLETE;   
@@ -235,13 +194,13 @@
 }
 
 static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
 	struct cmp_host *ch;
 
-	ch = lookup_cmp_host(host);
+	ch = hpsb_get_hostinfo(&cmp_highlevel, host);
 	
 	if (extcode != EXTCODE_COMPARE_SWAP) 
 		return RCODE_TYPE_ERROR;
@@ -298,9 +257,9 @@
 }
 
 
-static struct hpsb_highlevel_ops cmp_highlevel_ops = {
+static struct hpsb_highlevel cmp_highlevel = {
+	.name =		"cmp",
 	.add_host =	cmp_add_host,
-	.remove_host =	cmp_remove_host,
         .host_reset =	cmp_host_reset,
 };
 
@@ -321,14 +280,9 @@
 
 static int __init cmp_init_module (void)
 {
-	cmp_highlevel = hpsb_register_highlevel ("cmp",
-						 &cmp_highlevel_ops);
-	if (cmp_highlevel == NULL) {
-		HPSB_ERR("cmp: unable to register highlevel ops");
-		return -EIO;
-	}
+	hpsb_register_highlevel (&cmp_highlevel);
 
-	hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
+	hpsb_register_addrspace(&cmp_highlevel, &pcr_ops,
 				CSR_REGISTER_BASE + CSR_PCR_MAP,
 				CSR_REGISTER_BASE + CSR_PCR_MAP_END);
 
@@ -339,7 +293,7 @@
 
 static void __exit cmp_exit_module (void)
 {
-        hpsb_unregister_highlevel(cmp_highlevel);
+        hpsb_unregister_highlevel(&cmp_highlevel);
 
 	HPSB_INFO("Unloaded CMP driver");
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.c linux-2.4.21-rc3/drivers/ieee1394/csr.c
--- linux-2.4.20/drivers/ieee1394/csr.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/csr.c	2003-05-22 22:06:38.000000000 +0000
@@ -4,20 +4,33 @@
  * CSR implementation, iso/bus manager implementation.
  *
  * Copyright (C) 1999 Andreas E. Bombe
+ *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *
  */
 
 #include <linux/string.h>
+#include <linux/module.h> /* needed for MODULE_PARM */
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
 
+/* Module Parameters */
+/* this module parameter can be used to disable mapping of the FCP registers */
+MODULE_PARM(fcp,"i");
+MODULE_PARM_DESC(fcp, "FCP-registers");
+static int fcp = 1;
 
-/* FIXME: this one won't work on little endian with big endian data */
 static u16 csr_crc16(unsigned *data, int length)
 {
         int check=0, i;
@@ -25,7 +38,7 @@
 
         for (i = length; i; i--) {
                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
                 }
                 check = next & 0xffff;
@@ -41,8 +54,15 @@
 
         host->csr.bus_manager_id = 0x3f;
         host->csr.bandwidth_available = 4915;
-        host->csr.channels_available_hi = ~0;
+	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
         host->csr.channels_available_lo = ~0;
+	host->csr.broadcast_channel = 0x80000000 | 31;
+
+	if (host->is_irm) {
+		if (host->driver->hw_csr_reg) {
+			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
+		}
+	}
 
         host->csr.node_ids = host->node_id << 16;
 
@@ -60,6 +80,8 @@
                             | csr_crc16(host->csr.topology_map + 1,
                                         host->selfid_count + 2));
 
+        host->csr.speed_map[1] = 
+                cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1);
         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
                                              | csr_crc16(host->csr.speed_map+1,
                                                          0x3f1));
@@ -71,7 +93,7 @@
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-
+        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -80,18 +102,68 @@
         host->csr.bus_time              = 0;
         host->csr.bus_manager_id        = 0x3f;
         host->csr.bandwidth_available   = 4915;
-        host->csr.channels_available_hi = ~0;
+	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
         host->csr.channels_available_lo = ~0;
+	host->csr.broadcast_channel = 0x80000000 | 31;
+
+	if (host->is_irm) {
+		if (host->driver->hw_csr_reg) {
+			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
+		}
+	}
+}
+
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t size, unsigned char rom_version)
+{
+	unsigned long flags;
+	int ret;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        if (rom_version != host->csr.rom_version)
+                 ret = -1;
+        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
+                 ret = -2;
+        else {
+                 memcpy(host->csr.rom,new_rom,size);
+                 host->csr.rom_size=size;
+                 host->csr.rom_version++;
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
+	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+{
+	unsigned long flags;
+	int ret;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        *rom_version=host->csr.rom_version;
+        *rom_size=host->csr.rom_size;
+        if (buffersize < host->csr.rom_size)
+                 ret = -1;
+        else {
+                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
 }
 
 
 /* Read topology / speed maps and configuration ROM */
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 fl)
 {
+	unsigned long flags;
         int csraddr = addr - CSR_REGISTER_BASE;
         const char *src;
 
+        spin_lock_irqsave(&host->csr.lock, flags); 
+
         if (csraddr < CSR_TOPOLOGY_MAP) {
                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
                         return RCODE_ADDRESS_ERROR;
@@ -105,6 +177,7 @@
         }
 
         memcpy(buffer, src, length);
+        spin_unlock_irqrestore(&host->csr.lock, flags);
         return RCODE_COMPLETE;
 }
 
@@ -112,7 +185,7 @@
 #define out if (--length == 0) break
 
 static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         int oldcycle;
@@ -213,6 +286,10 @@
                 *(buf++) = cpu_to_be32(ret);
                 out;
 
+	case CSR_BROADCAST_CHANNEL:
+		*(buf++) = cpu_to_be32(host->csr.broadcast_channel);
+		out;
+
                 /* address gap to end - fall through to default */
         default:
                 return RCODE_ADDRESS_ERROR;
@@ -222,7 +299,7 @@
 }
 
 static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length)
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         
@@ -290,6 +367,12 @@
                 /* these are not writable, only lockable */
                 return RCODE_TYPE_ERROR;
 
+	case CSR_BROADCAST_CHANNEL:
+		/* only the valid bit can be written */
+		host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
+                        | (be32_to_cpu(*data) & 0x40000000);
+		out;
+
                 /* address gap to end - fall through */
         default:
                 return RCODE_ADDRESS_ERROR;
@@ -302,7 +385,7 @@
 
 
 static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         unsigned long flags;
@@ -318,6 +401,18 @@
         data = be32_to_cpu(data);
         arg = be32_to_cpu(arg);
 
+	/* Is somebody releasing the broadcast_channel on us? */
+	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
+		/* Note: this is may not be the right way to handle
+		 * the problem, so we should look into the proper way
+		 * eventually. */
+		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
+			  "broadcast channel 31.  Ignoring.",
+			  NODE_BUS_ARGS(nodeid));
+
+		data &= ~0x1;	/* keep broadcast channel allocated */
+	}
+
         if (host->driver->hw_csr_reg) {
                 quadlet_t old;
 
@@ -334,23 +429,84 @@
         switch (csraddr) {
         case CSR_BUS_MANAGER_ID:
                 regptr = &host->csr.bus_manager_id;
+		*store = cpu_to_be32(*regptr);
+		if (*regptr == arg)
+			*regptr = data;
                 break;
 
         case CSR_BANDWIDTH_AVAILABLE:
+        {
+                quadlet_t bandwidth;
+                quadlet_t old;
+                quadlet_t new;
+
                 regptr = &host->csr.bandwidth_available;
+                old = *regptr;
+
+                /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
+                if (arg > 0x1fff) {
+                        *store = cpu_to_be32(old);	/* change nothing */
+			break;
+                }
+                data &= 0x1fff;
+                if (arg >= data) {
+                        /* allocate bandwidth */
+                        bandwidth = arg - data;
+                        if (old >= bandwidth) {
+                                new = old - bandwidth;
+                                *store = cpu_to_be32(arg);
+                                *regptr = new;
+                        } else {
+                                *store = cpu_to_be32(old);
+                        }
+                } else {
+                        /* deallocate bandwidth */
+                        bandwidth = data - arg;
+                        if (old + bandwidth < 0x2000) {
+                                new = old + bandwidth;
+                                *store = cpu_to_be32(arg);
+                                *regptr = new;
+                        } else {
+                                *store = cpu_to_be32(old);
+                        }
+                }
                 break;
+        }
 
         case CSR_CHANNELS_AVAILABLE_HI:
+        {
+                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
+                quadlet_t affected_channels = arg ^ data;
+
                 regptr = &host->csr.channels_available_hi;
+
+                if ((arg & affected_channels) == (*regptr & affected_channels)) {
+                        *regptr ^= affected_channels;
+                        *store = cpu_to_be32(arg);
+                } else {
+                        *store = cpu_to_be32(*regptr);
+                }
+
                 break;
+        }
 
         case CSR_CHANNELS_AVAILABLE_LO:
+        {
+                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
+                quadlet_t affected_channels = arg ^ data;
+
                 regptr = &host->csr.channels_available_lo;
+
+                if ((arg & affected_channels) == (*regptr & affected_channels)) {
+                        *regptr ^= affected_channels;
+                        *store = cpu_to_be32(arg);
+                } else {
+                        *store = cpu_to_be32(*regptr);
+                }
                 break;
         }
+        }
 
-        *store = cpu_to_be32(*regptr);
-        if (*regptr == arg) *regptr = data;
         spin_unlock_irqrestore(&host->csr.lock, flags);
 
         return RCODE_COMPLETE;
@@ -365,10 +521,7 @@
         case CSR_SPLIT_TIMEOUT_LO:
         case CSR_CYCLE_TIME:
         case CSR_BUS_TIME:
-        case CSR_BUS_MANAGER_ID:
-        case CSR_BANDWIDTH_AVAILABLE:
-        case CSR_CHANNELS_AVAILABLE_HI:
-        case CSR_CHANNELS_AVAILABLE_LO:
+	case CSR_BROADCAST_CHANNEL:
                 return RCODE_TYPE_ERROR;
 
         case CSR_BUSY_TIMEOUT:
@@ -378,8 +531,99 @@
         }
 }
 
+static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
+		       u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	unsigned long flags;
+
+	data = be64_to_cpu(data);
+	arg = be64_to_cpu(arg);
+
+	if (csraddr & 0x3)
+		return RCODE_TYPE_ERROR;
+
+	if (csraddr != CSR_CHANNELS_AVAILABLE
+	    || extcode != EXTCODE_COMPARE_SWAP)
+		goto unsupported_lock64req;
+
+	/* Is somebody releasing the broadcast_channel on us? */
+	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
+		/* Note: this is may not be the right way to handle
+		 * the problem, so we should look into the proper way
+                 * eventually. */
+		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
+			  "broadcast channel 31.  Ignoring.",
+			  NODE_BUS_ARGS(nodeid));
+
+		data &= ~0x100000000ULL;	/* keep broadcast channel allocated */
+	}
+
+	if (host->driver->hw_csr_reg) {
+		quadlet_t data_hi, data_lo;
+		quadlet_t arg_hi, arg_lo;
+		quadlet_t old_hi, old_lo;
+
+		data_hi = data >> 32;
+		data_lo = data & 0xFFFFFFFF;
+		arg_hi = arg >> 32;
+		arg_lo = arg & 0xFFFFFFFF;
+
+		old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
+                                                  data_hi, arg_hi);
+
+		old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
+                                                  data_lo, arg_lo);
+
+		*store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
+	} else {
+		octlet_t old;
+		octlet_t affected_channels = arg ^ data;
+
+		spin_lock_irqsave(&host->csr.lock, flags);
+
+		old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
+
+		if ((arg & affected_channels) == (old & affected_channels)) {
+			host->csr.channels_available_hi ^= (affected_channels >> 32);
+			host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
+			*store = cpu_to_be64(arg);
+		} else {
+			*store = cpu_to_be64(old);
+		}
+
+		spin_unlock_irqrestore(&host->csr.lock, flags);
+	}
+
+	/* Is somebody erroneously releasing the broadcast_channel on us? */
+	if (host->csr.channels_available_hi & 0x1)
+		host->csr.channels_available_hi &= ~0x1;
+
+	return RCODE_COMPLETE;
+
+ unsupported_lock64req:
+	switch (csraddr) {
+	case CSR_STATE_CLEAR:
+	case CSR_STATE_SET:
+	case CSR_RESET_START:
+	case CSR_NODE_IDS:
+	case CSR_SPLIT_TIMEOUT_HI:
+	case CSR_SPLIT_TIMEOUT_LO:
+	case CSR_CYCLE_TIME:
+	case CSR_BUS_TIME:
+	case CSR_BUS_MANAGER_ID:
+	case CSR_BROADCAST_CHANNEL:
+	case CSR_BUSY_TIMEOUT:
+	case CSR_BANDWIDTH_AVAILABLE:
+		return RCODE_TYPE_ERROR;
+
+	default:
+		return RCODE_ADDRESS_ERROR;
+	}
+}
+
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, unsigned int length)
+		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
 
@@ -401,7 +645,8 @@
 }
 
 
-static struct hpsb_highlevel_ops csr_ops = {
+static struct hpsb_highlevel csr_highlevel = {
+	.name =		"standard registers",
 	.add_host =	add_host,
         .host_reset =	host_reset,
 };
@@ -419,35 +664,32 @@
         .read = read_regs,
         .write = write_regs,
         .lock = lock_regs,
+	.lock64 = lock64_regs,
 };
 
-static struct hpsb_highlevel *hl;
-
 void init_csr(void)
 {
-        hl = hpsb_register_highlevel("standard registers", &csr_ops);
-        if (hl == NULL) {
-                HPSB_ERR("out of memory during ieee1394 initialization");
-                return;
-        }
+	hpsb_register_highlevel(&csr_highlevel);
 
-        hpsb_register_addrspace(hl, &reg_ops, CSR_REGISTER_BASE,
+        hpsb_register_addrspace(&csr_highlevel, &reg_ops, CSR_REGISTER_BASE,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM);
-        hpsb_register_addrspace(hl, &map_ops, 
+        hpsb_register_addrspace(&csr_highlevel, &map_ops, 
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-        hpsb_register_addrspace(hl, &fcp_ops,
+        if (fcp) {
+		hpsb_register_addrspace(&csr_highlevel, &fcp_ops,
                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
                                 CSR_REGISTER_BASE + CSR_FCP_END);
-        hpsb_register_addrspace(hl, &map_ops,
+	}
+        hpsb_register_addrspace(&csr_highlevel, &map_ops,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
-        hpsb_register_addrspace(hl, &map_ops,
+        hpsb_register_addrspace(&csr_highlevel, &map_ops,
                                 CSR_REGISTER_BASE + CSR_SPEED_MAP,
                                 CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
 }
 
 void cleanup_csr(void)
 {
-        hpsb_unregister_highlevel(hl);
+        hpsb_unregister_highlevel(&csr_highlevel);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.h linux-2.4.21-rc3/drivers/ieee1394/csr.h
--- linux-2.4.20/drivers/ieee1394/csr.h	2001-03-02 00:57:11.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/csr.h	2003-05-22 22:06:26.000000000 +0000
@@ -16,8 +16,10 @@
 #define CSR_BUSY_TIMEOUT          0x210
 #define CSR_BUS_MANAGER_ID        0x21c
 #define CSR_BANDWIDTH_AVAILABLE   0x220
+#define CSR_CHANNELS_AVAILABLE    0x224
 #define CSR_CHANNELS_AVAILABLE_HI 0x224
 #define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_BROADCAST_CHANNEL     0x234
 #define CSR_CONFIG_ROM            0x400
 #define CSR_CONFIG_ROM_END        0x800
 #define CSR_FCP_COMMAND           0xB00
@@ -40,9 +42,12 @@
         quadlet_t bus_manager_id;
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
+	quadlet_t broadcast_channel;
 
-        const quadlet_t *rom;
+        quadlet_t *rom;
         size_t rom_size;
+        unsigned char rom_version;
+
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dma.c linux-2.4.21-rc3/drivers/ieee1394/dma.c
--- linux-2.4.20/drivers/ieee1394/dma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/dma.c	2003-05-22 22:06:41.000000000 +0000
@@ -0,0 +1,236 @@
+/*
+ * DMA region bookkeeping routines
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include "dma.h"
+
+/* dma_prog_region */
+
+void dma_prog_region_init(struct dma_prog_region *prog)
+{
+	prog->kvirt = NULL;
+	prog->dev = NULL;
+	prog->n_pages = 0;
+	prog->bus_addr = 0;
+}
+
+int  dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev)
+{
+	/* round up to page size */
+	n_bytes = round_up_to_page(n_bytes);
+
+	prog->n_pages = n_bytes / PAGE_SIZE;
+
+	prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr);
+	if(!prog->kvirt) {
+		printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
+		dma_prog_region_free(prog);
+		return -ENOMEM;
+	}
+
+	prog->dev = dev;
+
+	return 0;
+}
+
+void dma_prog_region_free(struct dma_prog_region *prog)
+{
+	if(prog->kvirt) {
+		pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr);
+	}
+
+	prog->kvirt = NULL;
+	prog->dev = NULL;
+	prog->n_pages = 0;
+	prog->bus_addr = 0;
+}
+
+/* dma_region */
+
+void dma_region_init(struct dma_region *dma)
+{
+	dma->kvirt = NULL;
+	dma->dev = NULL;
+	dma->n_pages = 0;
+	dma->n_dma_pages = 0;
+	dma->sglist = NULL;
+}
+
+int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction)
+{
+	unsigned int i, n_pages;
+
+	/* round up to page size */
+	n_bytes = round_up_to_page(n_bytes);
+
+	n_pages = n_bytes / PAGE_SIZE;
+
+	dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE);
+	if(!dma->kvirt) {
+		printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
+		goto err;
+	}
+
+	dma->n_pages = n_pages;
+
+	/* Clear the ram out, no junk to the user */
+	memset(dma->kvirt, 0, n_pages * PAGE_SIZE);
+
+	/* allocate scatter/gather list */
+	dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL);
+	if(!dma->sglist) {
+		printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n");
+		goto err;
+	}
+
+	/* just to be safe - this will become unnecessary once sglist->address goes away */
+	memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist));
+
+	/* fill scatter/gather list with pages */
+	for(i = 0; i < dma->n_pages; i++) {
+		unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE;
+			
+		dma->sglist[i].page = vmalloc_to_page((void *)va);
+		dma->sglist[i].length = PAGE_SIZE;
+	}
+
+	/* map sglist to the IOMMU */
+	dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction);
+
+	if(dma->n_dma_pages == 0) {
+		printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
+		goto err;
+	}
+
+	dma->dev = dev;
+	dma->direction = direction;
+
+	return 0;
+
+err:
+	dma_region_free(dma);
+	return -ENOMEM;
+}
+
+void dma_region_free(struct dma_region *dma)
+{
+	if(dma->n_dma_pages) {
+		pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction);
+		dma->n_dma_pages = 0;
+		dma->dev = NULL;
+	}
+
+	if(dma->sglist) {
+		kfree(dma->sglist);
+		dma->sglist = NULL;
+	}
+
+	if(dma->kvirt) {
+		vfree(dma->kvirt);
+		dma->kvirt = NULL;
+		dma->n_pages = 0;
+	}
+}
+
+/* find the scatterlist index and remaining offset corresponding to a
+   given offset from the beginning of the buffer */
+static inline int dma_region_find(struct dma_region *dma, unsigned long offset, unsigned long *rem)
+{
+	int i;
+	unsigned long off = offset;
+
+	for(i = 0; i < dma->n_dma_pages; i++) {
+		if(off < sg_dma_len(&dma->sglist[i])) {
+			*rem = off;
+			return i;
+		}
+
+		off -= sg_dma_len(&dma->sglist[i]);
+	}
+
+	panic("dma_region_find: offset %lu beyond end of DMA mapping\n", offset);
+}
+
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset)
+{
+	unsigned long rem;
+
+	struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)];
+	return sg_dma_address(sg) + rem;
+}
+
+void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len)
+{
+	int first, last;
+	unsigned long rem;
+
+	if(!len)
+		len = 1;
+
+	first = dma_region_find(dma, offset, &rem);
+	last = dma_region_find(dma, offset + len - 1, &rem);
+
+	pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction);
+}
+
+/* nopage() handler for mmap access */
+
+static struct page*
+dma_region_pagefault(struct vm_area_struct *area, unsigned long address, int write_access)
+{
+	unsigned long offset;
+	unsigned long kernel_virt_addr;
+	struct page *ret = NOPAGE_SIGBUS;
+
+	struct dma_region *dma = (struct dma_region*) area->vm_private_data;
+
+	if(!dma->kvirt)
+		goto out;
+
+	if( (address < (unsigned long) area->vm_start) ||
+	    (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) )
+		goto out;
+
+	offset = address - area->vm_start;
+	kernel_virt_addr = (unsigned long) dma->kvirt + offset;
+	ret = vmalloc_to_page((void*) kernel_virt_addr);
+	get_page(ret);
+out:
+	return ret;
+}
+
+static struct vm_operations_struct dma_region_vm_ops = {
+	.nopage	= dma_region_pagefault,
+};
+
+int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long size;
+
+	if(!dma->kvirt)
+		return -EINVAL;
+
+	/* must be page-aligned */
+	if(vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	/* check the length */
+	size = vma->vm_end - vma->vm_start;
+	if(size > (PAGE_SIZE * dma->n_pages))
+		return -EINVAL;
+
+	vma->vm_ops = &dma_region_vm_ops;
+	vma->vm_private_data = dma;
+	vma->vm_file = file;
+	vma->vm_flags |= VM_RESERVED;
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dma.h linux-2.4.21-rc3/drivers/ieee1394/dma.h
--- linux-2.4.20/drivers/ieee1394/dma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/dma.h	2003-05-22 22:06:25.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * DMA region bookkeeping routines
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#ifndef IEEE1394_DMA_H
+#define IEEE1394_DMA_H
+
+#include <linux/pci.h>
+#include <asm/scatterlist.h>
+
+/* struct dma_prog_region
+   
+   a small, physically-contiguous DMA buffer with random-access,
+   synchronous usage characteristics
+*/
+
+struct dma_prog_region {
+	unsigned char    *kvirt;     /* kernel virtual address */
+	struct pci_dev   *dev;       /* PCI device */
+	unsigned int      n_pages;   /* # of kernel pages */
+	dma_addr_t        bus_addr;  /* base bus address */
+};
+
+/* clear out all fields but do not allocate any memory */
+void dma_prog_region_init(struct dma_prog_region *prog);
+int  dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev);
+void dma_prog_region_free(struct dma_prog_region *prog);
+
+static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset)
+{
+	return prog->bus_addr + offset;
+}
+
+/* struct dma_region
+   
+   a large, non-physically-contiguous DMA buffer with streaming,
+   asynchronous usage characteristics
+*/
+
+struct dma_region {
+	unsigned char      *kvirt;       /* kernel virtual address */
+	struct pci_dev     *dev;         /* PCI device */
+	unsigned int        n_pages;     /* # of kernel pages */
+	unsigned int        n_dma_pages; /* # of IOMMU pages */
+	struct scatterlist *sglist;      /* IOMMU mapping */
+	int                 direction;   /* PCI_DMA_TODEVICE, etc */
+};
+
+/* clear out all fields but do not allocate anything */
+void dma_region_init(struct dma_region *dma);
+
+/* allocate the buffer and map it to the IOMMU */
+int  dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction);
+
+/* unmap and free the buffer */
+void dma_region_free(struct dma_region *dma);
+
+/* sync the IO bus' view of the buffer with the CPU's view */
+void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len);
+
+/* map the buffer into a user space process */
+int  dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma);
+
+/* macro to index into a DMA region (or dma_prog_region) */
+#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) )
+
+/* return the DMA bus address of the byte with the given offset
+   relative to the beginning of the dma_region */
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset);
+
+/* round up a number of bytes to be a multiple of the PAGE_SIZE */
+static inline unsigned long round_up_to_page(unsigned long len)
+{
+	if(len % PAGE_SIZE)
+		len += PAGE_SIZE - (len % PAGE_SIZE);
+	return len;
+}
+
+#endif /* IEEE1394_DMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394-private.h linux-2.4.21-rc3/drivers/ieee1394/dv1394-private.h
--- linux-2.4.20/drivers/ieee1394/dv1394-private.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/dv1394-private.h	2003-05-22 22:06:26.000000000 +0000
@@ -28,8 +28,7 @@
 
 #include "ieee1394.h"
 #include "ohci1394.h"
-#include <linux/pci.h>
-#include <asm/scatterlist.h>
+#include "dma.h"
 
 /* data structures private to the dv1394 driver */
 /* none of this is exposed to user-space */
@@ -167,12 +166,14 @@
 }
  
 static inline void fill_input_last(struct input_last *il,
+				    int want_interrupt,
 				    unsigned int data_size,
 				    unsigned long data_phys_addr)
 {
 	u32 temp =  3 << 28; /* INPUT_LAST */
 	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-	temp |= 3 << 20; /* enable interrupts */
+	if (want_interrupt)
+		temp |= 3 << 20; /* enable interrupts */
 	temp |= 0xC << 16; /* enable branch to address */
 	                       /* disable wait on sync field, not used in DV :-( */
 	temp |= data_size;
@@ -301,8 +302,7 @@
 	unsigned long data; 
 
 	/* Max # of packets per frame */
-	/* 320 is enough for NTSC, need to check what PAL is */
-        #define MAX_PACKETS 500
+#define MAX_PACKETS 500
 
 
 	/* a PAGE_SIZE memory pool for allocating CIP headers
@@ -383,35 +383,6 @@
 /* reset f so that it can be used again */
 static void frame_reset(struct frame *f);
 
-
-/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */
-
-struct dma_region {
-	unsigned int n_pages;
-	unsigned int n_dma_pages;
-	struct scatterlist *sglist;
-};
-
-/* return the DMA bus address of the byte with the given offset
-   relative to the beginning of the dma_region */
-
-static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset)
-{
-	int i;
-	struct scatterlist *sg;
-	
-	for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) {
-		if(offset < sg_dma_len(sg)) {
-			return sg_dma_address(sg) + offset;
-		} 
-		offset -= sg_dma_len(sg);
-	}
-	
-	printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset);
-	return 0;
-}
-
-
 /* struct video_card contains all data associated with one instance
    of the dv1394 driver 
 */
@@ -487,6 +458,10 @@
 	 */
 	spinlock_t spinlock;
 
+	/* flag to prevent spurious interrupts (which OHCI seems to
+	   generate a lot :) from accessing the struct */
+	int dma_running;
+	
 	/*
 	  3) the sleeping semaphore 'sem' - this is used from process context only,
 	  to serialize various operations on the video_card. Even though only one
@@ -508,9 +483,8 @@
 	
 	/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
            data, exposed to user-space via mmap() */
-	unsigned char     *user_buf;
-	unsigned long      user_buf_size;
-	struct dma_region  user_dma;
+	unsigned long      dv_buf_size;
+	struct dma_region  dv_buf;
 	
 	/* next byte in the ringbuffer that a write() call will fill */
 	size_t write_off;
@@ -518,7 +492,7 @@
 	struct frame *frames[DV1394_MAX_FRAMES];
 	
 	/* n_frames also serves as an indicator that this struct video_card is
-	   intialized and ready to run DMA buffers */
+	   initialized and ready to run DMA buffers */
 
 	int n_frames;
 
@@ -579,10 +553,8 @@
 
 	
 	/* physically contiguous packet ringbuffer for receive */
-#define MAX_PACKET_BUFFER 30
-	struct packet *packet_buffer;
-	dma_addr_t     packet_buffer_dma;
-	unsigned long  packet_buffer_size;
+	struct dma_region packet_buf;
+	unsigned long  packet_buf_size;
 	
 	unsigned int current_packet;
 	int first_frame; 	/* received first start frame marker? */
@@ -603,7 +575,7 @@
 
 static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
 static int do_dv1394_init_default(struct video_card *video);
-static int do_dv1394_shutdown(struct video_card *video, int free_user_buf);
+static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
 
 
 /* NTSC empty packet rate accurate to within 0.01%, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394.c linux-2.4.21-rc3/drivers/ieee1394/dv1394.c
--- linux-2.4.20/drivers/ieee1394/dv1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-rc3/drivers/ieee1394/dv1394.c	2003-05-22 22:06:28.000000000 +0000
@@ -53,6 +53,12 @@
     via pci_alloc_consistent()
     
   DONE:
+  - during reception, better handling of dropped frames and continuity errors
+  - during reception, prevent DMA from bypassing the irq tasklets
+  - reduce irq rate during reception (1/250 packets).
+  - add many more internal buffers during reception with scatter/gather dma.
+  - add dbc (continuity) checking on receive, increment status.dropped_frames
+    if not continuous.
   - restart IT DMA after a bus reset
   - safely obtain and release ISO Tx channels in cooperation with OHCI driver
   - map received DIF blocks to their proper location in DV frame (ensure
@@ -91,13 +97,12 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -109,6 +114,7 @@
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
+#include "ieee1394_hotplug.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"	
@@ -168,8 +174,6 @@
 static LIST_HEAD(dv1394_cards);
 static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
 
-static struct hpsb_highlevel *hl_handle; /* = NULL; */
-
 static LIST_HEAD(dv1394_devfs);
 struct dv1394_devfs_entry {
 	struct list_head list;
@@ -186,39 +190,6 @@
 	return (struct video_card*) file->private_data;
 }
 
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-/* note: we no longer use mem_map_reserve, because it causes a memory
-   leak, and setting vma->vm_flags to VM_RESERVED should be sufficient
-   to pin the pages in memory anyway. */
-
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-
-	mem = vmalloc_32(size);
-
-	if(mem)
-		memset(mem, 0, size); /* Clear the ram out, 
-					 no junk to the user */
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-	if (mem) {
-		vfree(mem);
-	}
-}
-
-/***********************************/
-/* END Memory management functions */
-/***********************************/
-
-
 /*** FRAME METHODS *********************************************************/
 
 static void frame_reset(struct frame *f)
@@ -447,11 +418,7 @@
 		/******************************/
 
 		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
-		fill_output_more_immediate( &(block->u.out.omi),
-					    /* tag - what is this??? */ 1,
-					    video->channel,
-					    /* sync tag - what is this??? */ 0,
-					    payload_size);
+		fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
 
 		if(empty_packet) {
 			/* second descriptor - OUTPUT_LAST for CIP header */
@@ -502,8 +469,8 @@
 						  PAGE_SIZE - (data_p % PAGE_SIZE),
 
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 
 				fill_output_last( &(block->u.out.u.full.u.cross.ol),
 					  
@@ -517,8 +484,8 @@
 						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
 
 						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
 
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
@@ -552,8 +519,8 @@
 
 						  
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 				
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
@@ -594,13 +561,8 @@
 	   to loop back up to the top */
 	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
-
-	/* make the latest version of the frame buffer visible to the PCI card */
-	/* could optimize this by only syncing the pages associated with this frame */
-	pci_dma_sync_sg(video->ohci->dev,
-			&video->user_dma.sglist[0],
-			video->user_dma.n_dma_pages,
-			PCI_DMA_TODEVICE);
+	/* make the latest version of this frame visible to the PCI card */
+	dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
 
 	/* lock against DMA interrupt */
 	spin_lock_irqsave(&video->spinlock, irq_flags);
@@ -732,7 +694,7 @@
 		wmb();
 #endif
 
-		
+		video->dma_running = 1;
 
 		/* set the 'run' bit */
 		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
@@ -799,6 +761,9 @@
 	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
 	int dif_block = p->data[2];
 
+	/* sanity check */
+	if (dif_sequence > 11 || dif_block > 149) return;
+		
 	switch (section_type) {
 	case 0:           /* 1 Header block */
 	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
@@ -826,47 +791,66 @@
 }
 
 
-static void start_dma_receive(struct video_card *video, struct frame *frame)
+static void start_dma_receive(struct video_card *video)
 {
-	/* reset iso recv control register */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
-	wmb();
+	if (video->first_run == 1) {
+		video->first_run = 0;
+		
+		/* start DMA once all of the frames are READY */
+		video->n_clear_frames = 0;
+		video->first_clear_frame = -1;
+		video->current_packet = 0;
+		video->active_frame = 0;
+		
+		/* reset iso recv control register */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+		wmb();
+		
+		/* clear bufferFill, set isochHeader and speed (0=100) */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
 	
-	/* clear bufferFill, set isochHeader and speed (0=100) */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+		/* match on all tags, listen on channel */
+		reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+		
+		/* address and first descriptor block + Z=1 */
+		reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
+			  video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
+		wmb();
 
-	/* match on all tags, listen on channel */
-	reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-	
-	/* address and first descriptor block + Z=1 */
-	reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
-		  frame->descriptor_pool_dma | 1); /* Z=1 */
-	wmb();
-	
-	/* run */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
-	flush_pci_write(video->ohci);
-	
-	debug_printk("dv1394: DMA started\n");
+		video->dma_running = 1;
 
-#if DV1394_DEBUG_LEVEL >= 2
-	{
-		int i;
+		/* run */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+		flush_pci_write(video->ohci);
+		
+		debug_printk("dv1394: DMA started\n");
 	
-		for(i = 0; i < 1000; ++i) {
-			mdelay(1);
-			if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
-				printk("DMA ACTIVE after %d msec\n", i);
-				break;
+#if DV1394_DEBUG_LEVEL >= 2
+		{
+			int i;
+		
+			for(i = 0; i < 1000; ++i) {
+				mdelay(1);
+				if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+					printk("DMA ACTIVE after %d msec\n", i);
+					break;
+				}
 			}
+			if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+				printk("DEAD, event = %x\n", 
+					   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+			} else
+				printk("RUNNING!\n");
 		}
-		if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-			printk("DEAD, event = %x\n", 
-			       reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-		} else
-			printk("RUNNING!\n");
-	}
 #endif
+	} 
+	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+		debug_printk("DEAD, event = %x\n", 
+			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+		/* wake */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+	}
 }
 
 
@@ -874,7 +858,7 @@
    receive_packets() - build the DMA program for receiving
 */
 
-static void receive_packets(struct video_card *video, struct frame *f)
+static void receive_packets(struct video_card *video)
 {
 	struct DMA_descriptor_block *block = NULL;
 	dma_addr_t block_dma = 0;
@@ -882,52 +866,46 @@
 	dma_addr_t data_dma = 0;
 	u32 *last_branch_address = NULL;
 	unsigned long irq_flags;
+	int want_interrupt = 0;
+	struct frame *f = NULL;
+	int i, j;
 
 	spin_lock_irqsave(&video->spinlock, irq_flags);
 
-	video->n_clear_frames = 0;
-	video->first_clear_frame = -1;
+	for (j = 0; j < video->n_frames; j++) {
 
-	for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
-		/* locate a descriptor block and packet from the buffer */
-		block = &(f->descriptor_pool[video->current_packet]);
-		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-		
-		data = &(video->packet_buffer[video->current_packet]);
-		data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
-		
-		/* setup DMA descriptor block */
-		fill_input_last( &(block->u.in.il), 512, data_dma);
+		/* connect frames */
+		if (j > 0 && f != NULL && f->frame_end_branch != NULL)
+			*(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
 
-		/* link descriptors */
-		last_branch_address = f->frame_end_branch;
+		f = video->frames[j];
 
-		if (last_branch_address)
-			*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
-		f->frame_end_branch = &(block->u.in.il.q[2]);
-	}
+		for (i = 0; i < MAX_PACKETS; i++) {
+			/* locate a descriptor block and packet from the buffer */
+			block = &(f->descriptor_pool[i]);
+			block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+			
+			data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
+			data_dma = dma_region_offset_to_bus( &video->packet_buf, 
+							     ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
+			
+			/* setup DMA descriptor block */
+			want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
+			fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
+	
+			/* link descriptors */
+			last_branch_address = f->frame_end_branch;
 	
-	/* loop tail to head */
-	if (f->frame_end_branch)
-		*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
+			if (last_branch_address != NULL)
+				*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
+	
+			f->frame_end_branch = &(block->u.in.il.q[2]);
+		}
+	
+	} /* next j */
 
 	spin_unlock_irqrestore(&video->spinlock, irq_flags);
 
-	if (video->first_run) {
-		/* start DMA once all of the frames are READY */
-		video->first_run = 0;
-		video->current_packet = 0;
-		video->active_frame = f->frame_num;
-		start_dma_receive(video, f);
-	} 
-	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-		debug_printk("DEAD, event = %x\n", 
-			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
-		/* wake */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-	}
 }
 
 
@@ -941,15 +919,16 @@
 	u64 chan_mask;
 	int retval = -EINVAL;
 
+	debug_printk("dv1394: initialising %d\n", video->id);
 	if(init->api_version != DV1394_API_VERSION)
-		goto err;
+		return -EINVAL;
 	
 	/* first sanitize all the parameters */
 	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->syt_offset == 0) || (init->syt_offset > 50) )
 		/* default SYT offset is 3 cycles */
@@ -970,17 +949,15 @@
 	if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
 
 	/* don't allow the user to allocate the DMA buffer more than once */
-	if( (video->user_buf) &&
-	    (video->user_buf_size != new_buf_size) ) {
-		goto err;
+	if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
+		printk("dv1394: re-sizing the DMA buffer is not allowed\n");
+		return -EINVAL;
 	}
-	
+
 	/* shutdown the card if it's currently active */
 	/* (the card should not be reset if the parameters are screwy) */
-	if( video_card_initialized(video) )
-		do_dv1394_shutdown(video, 0);
-
 
+	do_dv1394_shutdown(video, 0);
 	
 	/* try to claim the ISO channel */
 	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
@@ -997,7 +974,6 @@
 	/* initialize misc. fields of video */
 	video->n_frames = init->n_frames;
 	video->pal_or_ntsc = init->format;
-	
 
 	video->cip_accum = 0;
 	video->continuity_counter = 0;
@@ -1013,7 +989,6 @@
 	video->current_packet = -1;
 	video->first_frame = 0;
 
-
 	if(video->pal_or_ntsc == DV1394_NTSC) {
 		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
 		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
@@ -1026,14 +1001,8 @@
 
 	video->syt_offset = init->syt_offset;
 	
-	
 	/* find and claim DMA contexts on the OHCI card */
 
-	/* XXX this should be the last step of initialization, since the interrupt
-	   handler uses ohci_i*_ctx to indicate whether or not it is safe to touch
-	   frames. I'm not making this change quite yet, since it would be better
-	   to clean up the init/shutdown process first.*/
-
 	if(video->ohci_it_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
 					  it_tasklet_func, (unsigned long) video);
@@ -1041,14 +1010,12 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {	
 			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_it_ctx = video->it_tasklet.context;
-			debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+			goto err;
 		}
+		
+		video->ohci_it_ctx = video->it_tasklet.context;
+		debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
 	}
-	
 
 	if(video->ohci_ir_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
@@ -1057,14 +1024,11 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
 			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_ir_ctx = video->ir_tasklet.context;
-			debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+			goto err;
 		}
+		video->ohci_ir_ctx = video->ir_tasklet.context;
+		debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
 	}
-
 	
 	/* allocate struct frames */
 	for(i = 0; i < init->n_frames; i++) {
@@ -1073,97 +1037,43 @@
 		if(!video->frames[i]) {
 			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
 			retval = -ENOMEM;
-			goto err_frames;
+			goto err;
 		}
 	}
 
-	
-
-	if(video->user_buf == NULL) {
-		unsigned int i;
-		
+	if(!video->dv_buf.kvirt) {
 		/* allocate the ringbuffer */
-		video->user_buf = rvmalloc(new_buf_size);
-		if(!video->user_buf) {
-			printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
-			goto err_frames;
-		}
-		video->user_buf_size = new_buf_size;
-
-		/* allocate the sglist to hold the DMA addresses */
-		video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
-		video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
-		if(!video->user_dma.sglist) {
-			printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
-			goto err_user_buf;
-		}
-
-		/* initialize all fields of all sglist entries to zero
-		   (new requirement due to PCI changes in 2.4.13) */
-
-		memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+		retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
+		if(retval)
+			goto err;
+					  
+		video->dv_buf_size = new_buf_size;
 
-		
-		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
-		for(i = 0; i < video->user_dma.n_pages; i++) {
-			unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
-			
-			video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
-			video->user_dma.sglist[i].length = PAGE_SIZE;
-		}
-		
-		/* map the buffer in the IOMMU */
-		/* the user_data buffer only allows DMA *to* the card for transmission;
-		   incoming DV data comes through the packet_buffer first, and then is copied to user_data */
-		video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
-							 &video->user_dma.sglist[0],
-							 video->user_dma.n_pages,
-							 PCI_DMA_TODEVICE);
-		if(video->user_dma.n_dma_pages == 0) {
-			printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
-			goto err_user_buf;
-		}
-		
 		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
-			     video->n_frames, video->user_dma.n_pages,
-			     video->user_dma.n_dma_pages, video->user_buf_size);
+			     video->n_frames, video->dv_buf.n_pages,
+			     video->dv_buf.n_dma_pages, video->dv_buf_size);
 	}
 	
 	/* set up the frame->data pointers */
 	for(i = 0; i < video->n_frames; i++)
-		video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+		video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
 
-	/* allocate packet buffers */
-	video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
-	if (video->packet_buffer_size % PAGE_SIZE)
-		video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
-
-	
-	video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
-	
-	if(!video->packet_buffer) {
-		printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
-		retval = -ENOMEM;
-		goto err_user_buf;
-	}
-
-	/* map the packet buffer into the IOMMU */
-	video->packet_buffer_dma = pci_map_single(video->ohci->dev,
-						  video->packet_buffer,
-						  video->packet_buffer_size,
-						  PCI_DMA_FROMDEVICE);
-	if(!video->packet_buffer_dma) {
-		printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
-		kfree(video->packet_buffer);
-		video->packet_buffer = NULL;
-		retval = -ENOMEM;
-		goto err_user_buf;
+	if(!video->packet_buf.kvirt) {
+		/* allocate packet buffer */
+		video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
+		if (video->packet_buf_size % PAGE_SIZE)
+			video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
+		
+		retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
+					  video->ohci->dev, PCI_DMA_FROMDEVICE);
+		if(retval)
+			goto err;
+		
+		debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", 
+				 video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
+				 video->packet_buf.n_dma_pages, video->packet_buf_size);
 	}
-
-	debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", 
-		     ion;
-		   incomi("dv1394:+		
+		debug_ps
+	if(!videv1394: Alloeated %d  ackets in buffer,packetibuffer */ bp_single(video->ohcmtern int idescsi_attach(ide_drive_t ohcmtern int ides video->useacket_buffer,	mi("dv1394:attach(ide_driaaaeeeeeeeeeeeeo->user_dma.sgliseeeeeeeee.rr_user_buf;
i]->data = (unsigned long)irtdeo->user_buf + i ->packet_buffer = NUntk("dv1394: Allocated %d size,
-						  PCI_DMame_size;
 
-	/*  for transmissik(KERN_ERR "dv13941 NUntk("dv1394:N_ERR "dv13941 NUr) {
-		printk(KERN_ERR "dv1394: Can41 NUr) {
-dev, Pr,	mi("dv1394[1].chipset = iN_ERR "dv13941 NUr) {
-			 video->us_ERR "AGE_SIZE);
-
oto err_user_buf;
-		}
-		
 		deb iN_ERR "dv139intk(KERN_ERRuf;
-		}
-		
+-to Ieo->dv_buf.kvtNUr) {
-2cal)
+			goto err;
+		
+		dtk(KERN_ERRuf/-, Ó�ËIeo->dv_bufe_dmae kerne-, Ó�ËIeo-> of N_ERRuf;
-		}
-		ke_request (request_dv_bufuffer_dma = pci_map_sist (request_dv_bufu		for (
+		
+		debug_ERR "AGE_SIZE);
-
oto err_user_buet  uest (request_dv_bufuffeOR A Psist (request_dv_bubufu		for (
+		
+		debug_E) got signal %dr into the IOacketibuffer */ bp_single(video->ohcmtern int idescsi_attach(ide_drive_t ohcmtern int ides video->useacket_buffer,	mi("dv1394:attach(ide_driaaaeeeeeeeeeeeeo->user_dma.sgliseeeeeeeee.rr_user_buf;
i]->data = (unsigned long)irtdeo->user_buf + i ->packet_buffer = NUntk("dv13946-
otoffer = NUntk("lrtdeo->user_buf +ean up the in(unsigned lrr_user_buf;
i]->da