diff -urN linux-2.2.20-pristine/CREDITS linux-2.2.20/CREDITS
--- linux-2.2.20-pristine/CREDITS	Fri Nov  2 08:39:05 2001
+++ linux-2.2.20/CREDITS	Mon Nov 26 13:14:20 2001
@@ -101,6 +101,11 @@
 S: Cambridge, Massachusetts 02139
 S: USA
 
+N: Michel Aubry
+E: giovanni <giovanni@sudfr.com>
+D: Aladdin 1533/1543(C) chipset IDE
+D: VIA MVP-3/TX Pro III chipset IDE
+
 N: Jens Axboe
 E: axboe@image.dk
 D: Linux CD-ROM maintainer
@@ -445,6 +450,13 @@
 S: University of Michigan
 S: Ann Arbor, MI
 
+N: Michael Cornwell
+E: cornwell@acm.org
+D: Original designer and co-author of ATA Taskfile
+D: Kernel module SMART utilities
+S: Santa Cruz, California
+S: USA
+
 N: Alan Cox
 W: http://roadrunner.swansea.linux.org.uk/alan.shtml
 E: alan@lxorguk.ukuu.org.uk
@@ -502,6 +514,11 @@
 D: AX25-HOWTO, HAM-HOWTO, IPX-HOWTO, NET-2-HOWTO
 D: ax25-utils maintainer.
 
+N: Peter Denison
+E: peterd@pnd-pc.demon.co.uk
+W: http://www.pnd-pc.demon.co.uk/promise/
+D: Promise DC4030VL caching HD controller drivers
+
 N: Todd J. Derr
 E: tjd@fore.com
 W: http://www.wordsmith.org/~tjd
@@ -876,6 +893,14 @@
 E: ajh@primag.co.uk
 D: Selection mechanism
 
+N: Andre Hedrick
+E: andre@linux-ide.org
+W: http://www.linux-ide.org/
+D: Uniform Multi-Platform E-IDE driver
+D: Co-author of taskfile IOCTL
+S: Oakland, CA
+S: USA
+
 N: Jochen Hein
 E: jochen@jochen.org
 P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B  CB 0A DA DA 40 77 05 6C
@@ -1222,6 +1247,10 @@
 D: USB Bluetooth driver,
 D: bits and pieces of USB core code.
 
+N: Andreas S. Krebs
+E: akrebs@altavista.net
+D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
+
 N: Russell Kroll
 E: rkroll@exploits.org
 W: http://www.exploits.org/
@@ -1230,6 +1259,15 @@
 S: Colorado Springs, Colorado 80949-9458
 S: USA
 
+N: Andrzej M. Krzysztofowicz
+E: ankry@mif.pg.gda.pl
+D: XT disk driver
+D: Aladdin 1533/1543(C) chipset IDE
+D: PIIX chipset IDE
+S: ul. Matemblewska 1B/10
+S: 80-283 Gdansk
+S: Poland
+
 N: Gero Kuhlmann
 E: gero@gkminix.han.de
 D: mounting root via NFS
@@ -1972,6 +2010,10 @@
 D: added PCI support to the serial driver
 S: Buckenhof, Germany
 
+N: Michael Schmitz
+E:
+D: Macintosh IDE Driver
+
 N: Martin Schulze
 E: joey@linux.de
 W: http://home.pages.de/~joey/
@@ -2268,6 +2310,9 @@
 D: Frame buffer device and XF68_FBDev maintainer
 D: m68k IDE maintainer
 D: Amiga Zorro maintainer
+D: Amiga Buddha and Catweasel chipset IDE
+D: Atari Falcon chipset IDE
+D: Amiga Gayle chipset IDE
 S: C. Huysmansstraat 12
 S: B-3128 Baal
 S: Belgium
diff -urN linux-2.2.20-pristine/Documentation/Configure.help linux-2.2.20/Documentation/Configure.help
--- linux-2.2.20-pristine/Documentation/Configure.help	Fri Nov  2 08:39:05 2001
+++ linux-2.2.20/Documentation/Configure.help	Mon Nov 26 13:14:21 2001
@@ -292,9 +292,9 @@
 Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
 CONFIG_BLK_DEV_IDE
   If you say Y here, you will use the full-featured IDE driver to
-  control up to four IDE interfaces, each being able to serve a
-  "master" and a "slave" device, for a total of up to eight IDE
-  disk/cdrom/tape/floppy drives. People with SCSI-only systems
+  control up to eight IDE interfaces, each being able to serve a
+  "master" and a "slave" device, for a total of up to sixteen (16)
+  IDE disk/cdrom/tape/floppy drives.  People with SCSI-only systems
   can say N here.
 
   Useful information about large (>540 MB) IDE disks, multiple
@@ -373,6 +373,15 @@
   root filesystem (the one containing the directory /) is located on
   the IDE disk. If unsure, say Y.
 
+Use multi-mode by default
+CONFIG_IDEDISK_MULTI_MODE
+  If you get this error, try to enable this option.
+
+  hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
+  hda: set_multmode: error=0x04 { DriveStatusError }
+
+  If in doubt, say N.
+
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
   If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is
@@ -458,6 +467,13 @@
 
   People with SCSI-only systems can say N here. If unsure, say N.
 
+ISA-PNP EIDE support
+CONFIG_BLK_DEV_ISAPNP
+  If you have an ISA EIDE card that is PnP and requires setup first
+  before scanning for devices, say Y here.
+
+  If unsure, say N.
+
 CMD640 chipset bugfix/support
 CONFIG_BLK_DEV_CMD640
   The CMD-Technologies CMD640 IDE chip is used on many common 486 and
@@ -512,6 +528,15 @@
   
   People with SCSI-only systems should say N here; if unsure say Y.
 
+Support for sharing PCI IDE interrupts
+CONFIG_IDEPCI_SHARE_IRQ
+  Some ATA/IDE chipsets have hardware support which allows for
+  sharing a single IRQ with other cards. To enable support for
+  this in the ATA/IDE driver, say Y here.
+
+  It is safe to say Y to this question, in most cases.
+  If unsure, say N.
+
 Generic PCI bus-master DMA support
 CONFIG_BLK_DEV_IDEDMA
   If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
@@ -529,6 +554,15 @@
 
   It is safe to say Y to this question.
 
+Good-Bad DMA Model-Firmware (EXPERIMENTAL)
+IDEDMA_NEW_DRIVE_LISTINGS
+  This test compares both the model and firmware revision for buggy drives
+  that claim to (U)DMA capable.  This is a blanket on/off test with no speed
+  limit options.  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
+  whereas, many versions of EGCS have a problem and miscompile.
+
+  If in doubt, say N.
+
 Winbond SL82c105 support
 CONFIG_BLK_DEV_SL82C105
   If you have a Winbond SL82c105 IDE controller, say Y here to enable
@@ -545,6 +579,9 @@
   improve the usability of some boot managers such as LILO when
   booting from a drive on an off-board controller.
 
+  Requires that all onboard ide controllers be disabled or calling
+  "pci=reverse" to invert the device scan order.
+
   Note that, if you say Y here, the order of the hd* devices will be
   rearranged which may require modification of fstab and other files.
 
@@ -646,20 +683,224 @@
 
   Please read the comments at the top of drivers/block/ns87415.c.
 
-VIA82C586 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_VIA82C586
-  This adds initial timing settings for VIA (U)DMA onboard ide
-  controllers that are ATA3 compliant. May work with ATA4 systems, but
-  not tested to date.
+CY82C693 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CY82C693
+
+  This driver adds detection and support for the CY82C693 chipset
+  used on Digital's PC-Alpha 164SX boards.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/cy82c693.c
+
+VIA82CXXX chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_VIA82CXXX
+  This allows you to to configure your chipset for a better use while
+  running (U)DMA: it will allow you to enable efficiently the second
+  channel dma usage, as it is may not be set by BIOS. It allows you to
+  run a kernel command line at boot time in order to set fifo config.
+  If no command line is provided, it will try to set fifo configuration
+  at its best. It will allow you to get a proc/ide/via display
+  (while running a "cat") provided you enabled "proc" support and
+  set DISPLAY_APOLLO_TIMINGS in via82cxxx.c
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  If unsure, say N.
+
+VIA82CXXX Tuning support (WIP)
+CONFIG_VIA82CXXX_TUNING
+  Please read the comments at the top of drivers/block/via82cxxx.c
+
+  If unsure, say N.
+
+CMD64X chipset support
+CONFIG_BLK_DEV_CMD64X
+  Say Y here if you have an IDE controller which uses any of these chipsets,
+  CMD643, CMD646, or CMD648.
+
+CMD64X chipset RAID support (EXPERIMENTAL) (WIP)
+CONFIG_BLK_DEV_CMD64X
+  Work in progress for hardware raid ata-33/66..........rev 7 minimum.
+  Say N for now.
+
+ALI M15x3 chipset support
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+  onboard chipsets.  It also tests for Simplex mode and enables
+  normal dual channel support.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/alim15x3.c
+
+  If unsure, say N.
+
+ALI M15x3 WDC support (DANGEROUS)
+CONFIG_WDC_ALI15X3
+  This allows for UltraDMA support for WDC drives that ignore CRC
+  checking. You are a fool for enabling this option, but there have
+  been requests. DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORRUPTION, IF
+  YOU ENABLE THIS! No one will listen, just laugh for ignoring this
+  SERIOUS WARNING.
+
+  Using this option can allow WDC drives to run at ATA-4/5 transfer
+  rates with only an ATA-2 support structure.
+
+  SAY NO!
+
+PROMISE PDC20246/PDC20262 support
+CONFIG_BLK_DEV_PDC202XX
+  Promise Ultra33 or PDC20246.
+  This driver adds up to 4 more eide devices sharing a single interrupt.
+  This add-on card is a bootable PCI UDMA controller.
+  Since multiple cards can be installed and there are BIOS ROM problems
+  that happen if the BIOS revisions of all installed cards (three-max)
+  do not match.  Should you be unable to make new BIOS chips with a burner,
+  the driver attempts to dynamic tuning of the chipset at boot-time
+  for max-speed.  Ultra33 BIOS 1.25 or new required for more than one card.
+  This card may require "PDC202XX Special UDMA Feature".
+
+  Promise Ultra66 or PDC20262.
+  This driver adds up to 4 more eide devices sharing a single interrupt.
+  This add-on card is a bootable PCI UDMA ATA-66 controller.
+  The driver attempts to dynamic tuning of the chipset at boot-time
+  for max-speed.  Note tested limits are UDMA-2.
+  Ultra66 BIOS 1.11 or newer required.
+
+  Promise Ultra100 or PDC20265/PDC20267
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/pdc202xx.c
+
+  If unsure, say N.
+
+Special UDMA Feature
+PDC202XX_FORCE_BURST_BIT
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  Designed originally for PDC20246/Ultra33 that has BIOS setup failures
+  when using 3 or more cards.
+
+   Please read the comments at the top of drivers/block/pdc202xx.c
+
+   If unsure, say N.
+
+Special Mode Feature (EXPERIMENTAL)
+PDC202XX_FORCE_MASTER_MODE
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  This is reserved for possible Hardware RAID 0,1 for the FastTrak Series.
+
+  Say N.
+
+AEC62XX chipset support
+CONFIG_BLK_DEV_AEC62XX
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. In
+  order to get this card to initialize correctly in some cases, you
+  should say Y here, and preferably also to "Use DMA by default when
+  available".
+
+  The ATP850U/UF is an UltraDMA 33 chipset base.
+  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 drivers/block/aec62xx.c
+  If you say Y here, then say Y to "Use DMA by default when available" as well.
+
+AEC62XX Tuning support (WIP)
+CONFIG_AEC62XX_TUNING
+  Please read the comments at the top of drivers/block/aec62xx.c
+  If unsure, say N.
+
+AMD74XX chipset support
+CONFIG_BLK_DEV_AMD74XX
+  This driver ensures (U)DMA support for AMD756/765 Viper chipset.
 
   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 drivers/block/amd74xx.c
 
   If unsure, say N.
 
-CMD646 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CMD646
-  Say Y here if you have an IDE controller like this.
+AMD Viper ATA-66/100 Override support (WIP)
+CONFIG_AMD74XX_OVERRIDE
+  This option auto-forces the ata66 flag.
+  This effect can be also invoked by calling "idex=ata66"
+  If unsure, say N.
+
+Intel PIIXn chipsets support
+CONFIG_BLK_DEV_PIIX
+  This driver adds PIO mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly tune
+  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 drivers/block/piix.c
+
+  If unsure, say N.
+
+PIIXn Tuning support
+CONFIG_PIIX_TUNING
+  This driver extension adds DMA mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly setup
+  the device/adapter combination and speed limits, It has become a necessity
+  to back/forward speed devices as needed.
+
+  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2
+  if the BIOS can to perform this task at INIT.
+
+  If unsure, say N.
+
+HPT34X chipset support
+CONFIG_BLK_DEV_HPT34X
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT343 chipset in its current form is a non-bootable or
+  HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers.
+  This driver requires dynamic tuning of the chipset during the ide-probe
+  at boot. It is reported to support DVD II drives, by the manufacturer.
+
+  Please read the comments at the top of drivers/block/hpt34x.c
+
+  If unsure, say N.
+
+HPT34X DMA support (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT34X_DMA
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/hpt34x.c
+
+  If unsure, say N.
+
+HPT366 chipset support
+CONFIG_BLK_DEV_HPT366
+  This is an Ultra DMA chipset for ATA-66.
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT366 chipset in its current form is a non-bootable.
+  This driver requires dynamic tuning of the chipset during the ide-probe
+  at boot. It is reported to support DVD II drives, by the manufacturer.
+
+  Please read the comments at the top of drivers/block/hpt366.c
+
+HPT366 mode three unsupported (EXPERIMENTAL) (WIP)
+HPT366_MODE3
+  This is an undocumented mode that the HA366 can default to in many cases.
+  If unsure, say N.
+
+ServerWorks OSB4 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_OSB4
+  This driver adds PIO/DMA support for the Serverworks OSB4 chipset.
+
+SiS5513 chipset support
+CONFIG_BLK_DEV_SIS5513
+  This driver ensures (U)DMA support for SIS5513 chipset based mainboards.
+  SiS620 UDMA mode 4, SiS5600/5597 UDMA mode 2, all other DMA mode 2 limited
+  chipsets are unsupported to date.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/sis5513.c
 
 Cyrix CS5530 MediaGX chipset support
 CONFIG_BLK_DEV_CS5530
@@ -668,6 +909,19 @@
 
   It is safe to say Y to this question.
 
+SLC90E66 chipset support
+CONFIG_BLK_DEV_SLC90E66
+  This driver ensures (U)DMA support for Victroy66 SouthBridges for
+  SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
+  The nice thing about it is that you can mix Ultra/DMA/PIO devices
+  and it will handle timing cycles.  Since this is an improved look-a-like
+  to the PIIX4 it should be a nice addition.
+
+  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 drivers/ide/slc90e66.c
+
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
@@ -735,6 +989,68 @@
   Say Y if you have an IDE doubler.  The driver is enabled at kernel
   runtime using the "ide=doubler" kernel boot parameter.
 
+Amiga builtin Gayle IDE interface support
+CONFIG_BLK_DEV_GAYLE
+  This is the IDE driver for the builtin IDE interface on some Amiga
+  models.  It supports both the `A1200 style' (used in A600 and A1200)
+  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE interface.
+  Say Y if you have such an Amiga model and want to use IDE devices
+  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
+  IDE interface.
+
+Falcon IDE interface support
+CONFIG_BLK_DEV_FALCON_IDE
+  This is the IDE driver for the builtin IDE interface on the Atari Falcon.
+  Say Y if you have a Falcon and want to use IDE devices (hard disks,
+  CD-ROM drives, etc.) that are connected to the builtin IDE interface.
+
+Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL)
+CONFIG_BLK_DEV_BUDDHA
+  This is the IDE driver for the IDE interfaces on the Buddha and
+  Catweasel expansion boards.  It supports up to two interfaces on the
+  Buddha and three on the Catweasel.
+  Say Y if you have a Buddha or Catweasel expansion board and want to
+  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
+  to one of its IDE interfaces.
+
+Amiga IDE Doubler support (EXPERIMENTAL)
+CONFIG_BLK_DEV_IDEDOUBLER
+  This driver provides support for the so called `IDE doublers' (made by
+  various manufacturers, e.g. Eyetech) that can be connected to the
+  builtin IDE interface of some Amiga models. Using such an IDE doubler,
+  you can connect up to four instead of two IDE devices on the Amiga's
+  builtin IDE interface.
+  Note that the normal Amiga Gayle IDE driver may not work correctly if
+  you have an IDE doubler and don't enable this driver!
+  Say Y if you have an IDE doubler.  The driver is enabled at kernel
+  runtime using the "ide=doubler" kernel boot parameter.
+
+ Support for PowerMac IDE devices (must also enable IDE)
+ CONFIG_BLK_DEV_IDE_PMAC
+   No help for CONFIG_BLK_DEV_IDE_PMAC
+
+ PowerMac IDE DMA support
+ CONFIG_BLK_DEV_IDEDMA_PMAC
+   No help for CONFIG_BLK_DEV_IDEDMA_PMAC
+
+ Use DMA by default
+ CONFIG_PMAC_IDEDMA_AUTO
+   No help for CONFIG_PMAC_IDEDMA_AUTO
+
+Macintosh Quadra/Powerbook IDE interface support
+CONFIG_BLK_DEV_MAC_IDE
+  This is the IDE driver for the builtin IDE interface on the some m68k
+  Macintosh models. It supports both the `Quadra style' (used in Quadra/
+  Centris 630 and Performa 588 models) and `Powerbook style' (used in the
+  Powerbook 150 and 190 models) IDE interface.
+  Say Y if you have such an Macintosh model and want to use IDE devices
+  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
+  IDE interface.
+
+ RapIDE interface support
+ CONFIG_BLK_DEV_IDE_RAPIDE
+   No help for CONFIG_BLK_DEV_IDE_RAPIDE
+
 XT hard disk support
 CONFIG_BLK_DEV_XD
   Very old 8 bit hard disk controllers used in the IBM XT computer
@@ -15463,5 +15779,5 @@
 # LocalWords:  BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
 # LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
 # LocalWords:  QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
-# LocalWords:  IrLPT UIRCC Tecra
+# LocalWords:  IrLPT UIRCC Tecra ServerWorks
 
diff -urN linux-2.2.20-pristine/Documentation/devices.txt linux-2.2.20/Documentation/devices.txt
--- linux-2.2.20-pristine/Documentation/devices.txt	Sun Mar 25 08:37:29 2001
+++ linux-2.2.20/Documentation/devices.txt	Mon Nov 26 13:14:21 2001
@@ -546,10 +546,11 @@
 		  0 = /dev/ttyD0	First Digiboard port
 		  1 = /dev/ttyD1	Second Digiboard port
 		    ...
+
     block	Second IDE hard disk/CD-ROM interface
 		  0 = /dev/hdc		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdd		Slave: whole disk (or CD-ROM)
-		
+
 		Partitions are handled the same way as for the first
 		interface (see major number 3).
 
@@ -722,6 +723,7 @@
 		  0 = /dev/cux0		Callout device for ttyX0
 		  1 = /dev/cux1		Callout device for ttyX1
 		    ...
+
     block	Third IDE hard disk/CD-ROM interface
 		  0 = /dev/hde		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdf		Slave: whole disk (or CD-ROM)
@@ -743,7 +745,7 @@
     block	Fourth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdg		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdh		Slave: whole disk (or CD-ROM)
-		
+
 		Partitions are handled the same way as for the first
 		interface (see major number 3).
 
@@ -1535,7 +1537,6 @@
 
 		Partitions are handled the same way as for the first
 		interface (see major number 3).
-
 
  89 char	I2C bus interface
 		  0 = /dev/i2c-0	First I2C adapter
diff -urN linux-2.2.20-pristine/MAINTAINERS linux-2.2.20/MAINTAINERS
--- linux-2.2.20-pristine/MAINTAINERS	Fri Nov  2 08:39:05 2001
+++ linux-2.2.20/MAINTAINERS	Mon Nov 26 13:14:21 2001
@@ -477,7 +477,8 @@
 P:	Andre Hedrick
 M:	andre@linux-ide.org
 L:	linux-kernel@vger.kernel.org
-S:	Maintained
+W:	http://linux.kernel.org/pub/linux/kernel/people/hedrick/
+S:	Supported
 
 IDE/ATAPI CDROM DRIVER 
 P:	Jens Axboe
@@ -811,6 +812,12 @@
 P:	Al Longyear
 M:	longyear@pobox.com
 L:	linux-ppp@vger.kernel.org
+S:	Maintained
+
+PROMISE DC4030 CACHING DISK CONTROLLER DRIVER
+P:	Peter Denison
+M:	promise@pnd-pc.demon.co.uk
+W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
 QNX4 FILESYSTEM
diff -urN linux-2.2.20-pristine/arch/i386/kernel/smp.c linux-2.2.20/arch/i386/kernel/smp.c
--- linux-2.2.20-pristine/arch/i386/kernel/smp.c	Sun Mar 25 08:37:29 2001
+++ linux-2.2.20/arch/i386/kernel/smp.c	Mon Nov 26 13:14:21 2001
@@ -137,7 +137,7 @@
 unsigned long mp_lapic_addr = 0;
 int skip_ioapic_setup = 0;				/* 1 if "noapic" boot option passed */
 
-/* #define SMP_DEBUG */
+#define SMP_DEBUG
 
 #ifdef SMP_DEBUG
 #define SMP_PRINTK(x)	printk x
diff -urN linux-2.2.20-pristine/arch/mips/lib/ide-no.c linux-2.2.20/arch/mips/lib/ide-no.c
--- linux-2.2.20-pristine/arch/mips/lib/ide-no.c	Sun Mar 25 08:31:48 2001
+++ linux-2.2.20/arch/mips/lib/ide-no.c	Mon Nov 26 13:14:21 2001
@@ -11,6 +11,7 @@
  */
 #include <linux/hdreg.h>
 #include <linux/kernel.h>
+#include <asm/hdreg.h>
 #include <asm/ptrace.h>
 #include <asm/ide.h>
 
@@ -24,8 +25,10 @@
 	return 0;
 }
 
-static void no_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base,
-                                     int *irq)
+static void no_ide_init_hwif_ports (	hw_regs_t *hw,
+					ide_ioreg_t data_port,
+					ide_ioreg_t ctrl_port,
+					int *irq)
 {
 }
 
diff -urN linux-2.2.20-pristine/arch/mips/lib/ide-std.c linux-2.2.20/arch/mips/lib/ide-std.c
--- linux-2.2.20-pristine/arch/mips/lib/ide-std.c	Sun Mar 25 08:31:48 2001
+++ linux-2.2.20/arch/mips/lib/ide-std.c	Mon Nov 26 13:14:21 2001
@@ -12,6 +12,7 @@
 #include <linux/ioport.h>
 #include <linux/hdreg.h>
 #include <asm/ptrace.h>
+#include <asm/hdreg.h>
 #include <asm/ide.h>
 
 static int std_ide_default_irq(ide_ioreg_t base)
@@ -42,15 +43,23 @@
 	}
 }
 
-static void std_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base,
-                                     int *irq)
+static void std_ide_init_hwif_ports (	hw_regs_t *hw,
+					ide_ioreg_t data_port,
+					ide_ioreg_t ctrl_port,
+					int *irq)
 {
-	ide_ioreg_t port = base;
-	int i = 8;
+	ide_ioreg_t reg = data_port;
+	int i;
 
-	while (i--)
-		*p++ = port++;
-	*p++ = base + 0x206;
+	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;
 }
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/apus_setup.c linux-2.2.20/arch/ppc/kernel/apus_setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/apus_setup.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/apus_setup.c	Mon Nov 26 13:14:21 2001
@@ -561,9 +561,9 @@
 }
 
 __initfunc(void
-apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq))
 {
-        m68k_ide_init_hwif_ports(p, base, irq);
+        m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
 }
 #endif
 
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/chrp_pci.c linux-2.2.20/arch/ppc/kernel/chrp_pci.c
--- linux-2.2.20-pristine/arch/ppc/kernel/chrp_pci.c	Sun Mar 25 08:31:48 2001
+++ linux-2.2.20/arch/ppc/kernel/chrp_pci.c	Mon Nov 26 13:14:21 2001
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/openpic.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -15,7 +16,6 @@
 #include <asm/hydra.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
-#include <asm/ide.h>
 #include <asm/machdep.h>
 
 #include "pci.h"
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/chrp_setup.c linux-2.2.20/arch/ppc/kernel/chrp_setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/chrp_setup.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/chrp_setup.c	Mon Nov 26 13:14:21 2001
@@ -28,6 +28,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
 #include <linux/pci.h>
@@ -39,7 +40,6 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
 #include <asm/pci-bridge.h>
@@ -527,16 +527,23 @@
         ppc_generic_ide_fix_driveid(id);
 }
 
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-        ide_ioreg_t port = base;
-        int i = 8;
+	ide_ioreg_t reg = data_port;
+	int i;
 
-        while (i--)
-                *p++ = port++;
-        *p++ = port;
-        if (irq != NULL)
-                *irq = chrp_ide_irq;
+	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] = 0;
+	}
+	if (irq != NULL)
+		hw->irq = chrp_ide_irq;
 }
 
 EXPORT_SYMBOL(chrp_ide_irq);
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/mbx_setup.c linux-2.2.20/arch/ppc/kernel/mbx_setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/mbx_setup.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/mbx_setup.c	Mon Nov 26 13:14:21 2001
@@ -30,6 +30,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 
@@ -38,7 +39,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/ide.h>
 #include <asm/mbx.h>
 #include <asm/machdep.h>
 #include <asm/keyboard.h>
@@ -390,23 +390,35 @@
         ppc_generic_ide_fix_driveid(id);
 }
 
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-	ide_ioreg_t port = base;
-	int i = 8;
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	*irq = 0;
+
+	if (data_port != 0)	/* Only map the first ATA flash drive */
+		return;
 
-	while (i--)
-		*p++ = port++;
-	*p++ = base + 0x206;
-	if (irq != NULL)
-		*irq = 0;
 #ifdef ATA_FLASH
-	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
-	for (i = 0; i < 8; ++i)
-		*p++ = base++;
-	*p = ++base;		/* Does not matter */
+
+	reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200);
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+
+	/* Does not matter */
+
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = reg;
+	}
 	if (irq)
-		*irq = 13;
+		hw->irq = 13;
 #endif
 }
 #endif
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/pmac_setup.c linux-2.2.20/arch/ppc/kernel/pmac_setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/pmac_setup.c	Sun Mar 25 08:37:30 2001
+++ linux-2.2.20/arch/ppc/kernel/pmac_setup.c	Mon Nov 26 13:14:21 2001
@@ -39,6 +39,7 @@
 #include <linux/ioport.h>
 #include <linux/major.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <linux/pci.h>
@@ -55,7 +56,6 @@
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
 #include <asm/feature.h>
-#include <asm/ide.h>
 #include <asm/machdep.h>
 #include <asm/keyboard.h>
 #include <asm/time.h>
@@ -635,7 +635,8 @@
 }
 
 /* This is declared in drivers/block/ide-pmac.c */
-void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void pmac_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
+
 #endif
 
 __initfunc(void
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/ppc_ksyms.c linux-2.2.20/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.2.20-pristine/arch/ppc/kernel/ppc_ksyms.c	Sun Mar 25 08:37:30 2001
+++ linux-2.2.20/arch/ppc/kernel/ppc_ksyms.c	Mon Nov 26 13:14:22 2001
@@ -13,6 +13,7 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/ide.h>
+#include <linux/ide.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
 #include <asm/adb.h>
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/prep_setup.c linux-2.2.20/arch/ppc/kernel/prep_setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/prep_setup.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/prep_setup.c	Mon Nov 26 13:14:22 2001
@@ -28,6 +28,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
 #include <linux/timex.h>
@@ -40,7 +41,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/ide.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
@@ -707,14 +707,20 @@
 }
 
 __initfunc(void
-prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq))
 {
-	ide_ioreg_t port = base;
-	int i = 8;
+	ide_ioreg_t reg = data_port;
+	int i;
 
-	while (i--)
-		*p++ = port++;
-	*p++ = base + 0x206;
+	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;
 }
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/residual.c linux-2.2.20/arch/ppc/kernel/residual.c
--- linux-2.2.20-pristine/arch/ppc/kernel/residual.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/residual.c	Mon Nov 26 13:14:22 2001
@@ -46,6 +46,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 
 
diff -urN linux-2.2.20-pristine/arch/ppc/kernel/setup.c linux-2.2.20/arch/ppc/kernel/setup.c
--- linux-2.2.20-pristine/arch/ppc/kernel/setup.c	Sun Mar 25 08:31:49 2001
+++ linux-2.2.20/arch/ppc/kernel/setup.c	Mon Nov 26 22:44:35 2001
@@ -11,13 +11,13 @@
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
-#include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
@@ -176,10 +176,10 @@
 }
   
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	if (ppc_ide_md.ide_init_hwif != NULL) {
-		ppc_ide_md.ide_init_hwif(p, base, irq);
+		ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq);
 	}
 }
 #endif
@@ -637,16 +637,16 @@
 	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++)
+	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++)
+	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++)
+	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);
@@ -664,66 +664,48 @@
 	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);
-	id->word69         = __le16_to_cpu(id->word69);
-	id->word70         = __le16_to_cpu(id->word70);
-	id->word71         = __le16_to_cpu(id->word71);
-	id->word72         = __le16_to_cpu(id->word72);
-	id->word73         = __le16_to_cpu(id->word73);
-	id->word74         = __le16_to_cpu(id->word74);
-	id->word75         = __le16_to_cpu(id->word75);
-	id->word76         = __le16_to_cpu(id->word76);
-	id->word77         = __le16_to_cpu(id->word77);
-	id->word78         = __le16_to_cpu(id->word78);
-	id->word79         = __le16_to_cpu(id->word79);
-	id->word80         = __le16_to_cpu(id->word80);
-	id->word81         = __le16_to_cpu(id->word81);
-	id->command_sets   = __le16_to_cpu(id->command_sets);
-	id->word83         = __le16_to_cpu(id->word83);
-	id->word84         = __le16_to_cpu(id->word84);
-	id->word85         = __le16_to_cpu(id->word85);
-	id->word86         = __le16_to_cpu(id->word86);
-	id->word87         = __le16_to_cpu(id->word87);
+	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->word91         = __le16_to_cpu(id->word91);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
 	id->word92         = __le16_to_cpu(id->word92);
-	id->word93         = __le16_to_cpu(id->word93);
-	id->word94         = __le16_to_cpu(id->word94);
-	id->word95         = __le16_to_cpu(id->word95);
-	id->word96         = __le16_to_cpu(id->word96);
-	id->word97         = __le16_to_cpu(id->word97);
-	id->word98         = __le16_to_cpu(id->word98);
-	id->word99         = __le16_to_cpu(id->word99);
-	id->word100        = __le16_to_cpu(id->word100);
-	id->word101        = __le16_to_cpu(id->word101);
-	id->word102        = __le16_to_cpu(id->word102);
-	id->word103        = __le16_to_cpu(id->word103);
-	id->word104        = __le16_to_cpu(id->word104);
-	id->word105        = __le16_to_cpu(id->word105);
-	id->word106        = __le16_to_cpu(id->word106);
-	id->word107        = __le16_to_cpu(id->word107);
-	id->word108        = __le16_to_cpu(id->word108);
-	id->word109        = __le16_to_cpu(id->word109);
-	id->word110        = __le16_to_cpu(id->word110);
-	id->word111        = __le16_to_cpu(id->word111);
-	id->word112        = __le16_to_cpu(id->word112);
-	id->word113        = __le16_to_cpu(id->word113);
-	id->word114        = __le16_to_cpu(id->word114);
-	id->word115        = __le16_to_cpu(id->word115);
-	id->word116        = __le16_to_cpu(id->word116);
-	id->word117        = __le16_to_cpu(id->word117);
-	id->word118        = __le16_to_cpu(id->word118);
-	id->word119        = __le16_to_cpu(id->word119);
-	id->word120        = __le16_to_cpu(id->word120);
-	id->word121        = __le16_to_cpu(id->word121);
-	id->word122        = __le16_to_cpu(id->word122);
-	id->word123        = __le16_to_cpu(id->word123);
-	id->word124        = __le16_to_cpu(id->word124);
-	id->word125        = __le16_to_cpu(id->word125);
+	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->security       = __le16_to_cpu(id->security);
-	for (i=0; i<127; i++)
-	        id->reserved[i] = __le16_to_cpu(id->reserved[i]);
+	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);
 }
diff -urN linux-2.2.20-pristine/arch/sparc64/config.in linux-2.2.20/arch/sparc64/config.in
--- linux-2.2.20-pristine/arch/sparc64/config.in	Sun Mar 25 08:37:30 2001
+++ linux-2.2.20/arch/sparc64/config.in	Mon Nov 26 13:14:22 2001
@@ -132,7 +132,7 @@
 	  define_bool CONFIG_BLK_DEV_IDEDMA y
 	  define_bool CONFIG_IDEDMA_AUTO y
 	  define_bool CONFIG_BLK_DEV_NS87415 y
-	  define_bool CONFIG_BLK_DEV_CMD646 y
+	  define_bool CONFIG_BLK_DEV_CMD64X y
 	fi
 fi
 
diff -urN linux-2.2.20-pristine/arch/sparc64/defconfig linux-2.2.20/arch/sparc64/defconfig
--- linux-2.2.20-pristine/arch/sparc64/defconfig	Sun Mar 25 08:37:30 2001
+++ linux-2.2.20/arch/sparc64/defconfig	Mon Nov 26 13:14:22 2001
@@ -126,7 +126,7 @@
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_AUTO=y
 CONFIG_BLK_DEV_NS87415=y
-CONFIG_BLK_DEV_CMD646=y
+CONFIG_BLK_DEV_CMD64X=y
 
 #
 # Networking options
diff -urN linux-2.2.20-pristine/drivers/block/Config.in linux-2.2.20/drivers/block/Config.in
--- linux-2.2.20-pristine/drivers/block/Config.in	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/Config.in	Tue Nov 27 08:44:09 2001
@@ -19,35 +19,107 @@
 else
   bool '   Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
   dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+  if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
+    bool '     Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
+    bool '     Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE
+  fi
   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
   dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
   dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+
+  bool '   IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+  dep_bool '   Packet Taskfile Access' CONFIG_PKT_TASK_IOCTL $CONFIG_IDE_TASK_IOCTL
+  dep_bool '     TaskFile IOCTL Debugging' CONFIG_IDE_TASK_IOCTL_DEBUG $CONFIG_IDE_TASK_IOCTL
+  dep_bool '  IDE Taskfile IO Access' CONFIG_IDE_TASKFILE_IO $CONFIG_IDE_TASK_IOCTL $CONFIG_EXPERIMENTAL
+
   if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
     bool '   CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
     if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
       bool '     CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
     fi
+    if [ "$CONFIG_ISAPNP" = "y" ]; then
+      bool '    ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP
+    fi
     if [ "$CONFIG_PCI" = "y" ]; then
       bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
       bool '   Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
       if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+        bool '     Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
         bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
-        bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
         if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
           bool '     Use DMA by default when available' CONFIG_IDEDMA_AUTO
+          if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+            bool '       Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+            define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL y
+          else
+            define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n
+          fi
+        fi
+        if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '    ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP
+        fi
+	define_bool CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
+        bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+        bool '     AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AEC62XX" = "y" ]; then
+          bool '      AEC62XX Tuning support (WIP)' CONFIG_AEC62XX_TUNING
+        fi
+        bool '     ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_ALI15X3" = "y" ]; then
+          bool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3
+        fi
+        bool '     AMD Viper support' CONFIG_BLK_DEV_AMD74XX
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AMD74XX" = "y" ]; then
+          bool '      AMD Viper ATA-66/100 Override (WIP)' CONFIG_AMD74XX_OVERRIDE
+        fi
+        bool '     CMD64X chipset support' CONFIG_BLK_DEV_CMD64X
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_CMD64X" = "y" ]; then
+           bool '       CMD64X chipset RAID support (WIP)' CONFIG_CMD64X_RAID
+        fi
+        if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+           bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+        fi
+        bool '     Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530
+        bool '     HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+           bool '       HPT34X DMA support (WIP)' CONFIG_HPT34X_AUTODMA
+        fi
+        bool '     HPT366 chipset support' CONFIG_BLK_DEV_HPT366
+        if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then
+           bool '       HPT366 Fast Interrupt support (WIP)' HPT366_FIP
+           bool '       HPT366 mode three unsupported (WIP)' HPT366_MODE3
+        fi
+        bool '     Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
+        if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_AUTO" = "y" ]; then
+           bool '       PIIXn Tuning support' CONFIG_PIIX_TUNING
+        fi
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+           bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
         fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-          bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
-          if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
-			bool '     ALI 15X3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
-            bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
-            bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
-            bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
-            bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
-            bool '     Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 
+           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+        fi
+        if [ "$CONFIG_BLK_DEV_ADMA" = "y" ]; then
+          bool '     Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA
+        fi
+        if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+          bool '     PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
+          if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+            bool '       Special UDMA Feature' CONFIG_PDC202XX_BURST
+            if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" ]; then
+              bool '       Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_MASTER
+              bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE
+            fi
           fi
         fi
+        bool '     ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS
+        bool '     SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
+        bool '     SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66
+        if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+           bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+        fi
+        bool '     VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX
       fi
       if [ "$CONFIG_PPC" = "y" ]; then
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
@@ -70,14 +142,30 @@
       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 QD6580 support' CONFIG_BLK_DEV_QD6580
       bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+    fi
+    if [ "$CONFIG_AMIGA" = "y" ]; then
+      bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then
-        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-	 fi
+        bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
       fi
     fi
+    if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
+    fi
+    if [ "$CONFIG_ATARI" = "y" ]; then
+      bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
+    fi
+    if [ "$CONFIG_MAC" = "y" ]; then
+      bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+    fi
+  fi
+  if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+     bool '   IGNORE word93 Validation BITS' CONFIG_IDEDMA_IVB
   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
@@ -135,6 +223,28 @@
 dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
+fi
+
+if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+     "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD640" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD64X" = "y" -o \
+     "$CONFIG_BLK_DEV_CS5530" = "y" -o \
+     "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT366" = "y" -o \
+     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
+     "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
+     "$CONFIG_BLK_DEV_PIIX" = "y" -o \
+     "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
+     "$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
 fi
 if [ "$CONFIG_PCI" = "y" ]; then
   tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
diff -urN linux-2.2.20-pristine/drivers/block/Makefile linux-2.2.20/drivers/block/Makefile
--- linux-2.2.20-pristine/drivers/block/Makefile	Sun Mar 25 08:31:23 2001
+++ linux-2.2.20/drivers/block/Makefile	Mon Nov 26 23:59:50 2001
@@ -20,7 +20,7 @@
 
 
 L_TARGET := block.a
-L_OBJS   := genhd.o
+L_OBJS   := genhd.o ide-geometry.o
 M_OBJS   :=
 MOD_LIST_NAME := BLOCK_MODULES
 LX_OBJS := ll_rw_blk.o
@@ -94,86 +94,157 @@
   endif
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HD),y)
-L_OBJS += hd.o
+#
+# IDE-STUFF
+#
+
+ifeq ($(CONFIG_BLK_DEV_AEC62XX),y)
+IDE_OBJS += aec62xx.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_RZ1000),y)
-IDE_OBJS += rz1000.o
+ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
+IDE_OBJS += ali14xx.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
+IDE_OBJS += alim15x3.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_AMD74XX),y)
+IDE_OBJS += amd74xx.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_BUDDHA),y)
+IDE_OBJS += buddha.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_CMD640),y)
 IDE_OBJS += cmd640.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
-IDE_OBJS += ide-pmac.o
+ifeq ($(CONFIG_BLK_DEV_CMD64X),y)
+IDE_OBJS += cmd64x.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
-IDE_OBJS += ide-pci.o
+ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
+IDE_OBJS += cy82c693.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
-IDE_OBJS += ide-dma.o
+ifeq ($(CONFIG_BLK_DEV_CS5530),y)
+IDE_OBJS += cs5530.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_DTC2278),y)
 IDE_OBJS += dtc2278.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y)
+IDE_OBJS += falconide.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_GAYLE),y)
+IDE_OBJS += gayle.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_HD),y)
+L_OBJS += hd.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_HPT34X),y)
+IDE_OBJS += hpt34x.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_HPT366),y)
+IDE_OBJS += hpt366.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_HT6560B),y)
 IDE_OBJS += ht6560b.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_QD6580),y)
-IDE_OBJS += qd6580.o
+ifeq ($(CONFIG_BLK_DEV_ADMA),y)
+IDE_OBJS += ide-adma.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_UMC8672),y)
-IDE_OBJS += umc8672.o
+ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
+IDE_OBJS += ide-dma.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
-IDE_OBJS += ali14xx.o
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+IDE_OBJS += ide-pci.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_PDC4030),y)
-IDE_OBJS += pdc4030.o
+ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
+IDE_OBJS += ide-pmac.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
-IDE_OBJS += alim15x3.o
+ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y)
+IDE_OBJS += macide.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_TRM290),y)
-IDE_OBJS += trm290.o
+ifeq ($(CONFIG_BLK_DEV_NS87415),y)
+IDE_OBJS += ns87415.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
 IDE_OBJS += opti621.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_NS87415),y)
-IDE_OBJS += ns87415.o
+ifeq ($(CONFIG_BLK_DEV_PDC_ADMA),y)
+IDE_OBJS += pdcadma.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
-IDE_OBJS += via82c586.o
+ifeq ($(CONFIG_BLK_DEV_PDC202XX),y)
+IDE_OBJS += pdc202xx.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_CMD646),y)
-IDE_OBJS += cmd646.o
+ifeq ($(CONFIG_BLK_DEV_PDC4030),y)
+IDE_OBJS += pdc4030.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_CS5530),y)
-IDE_OBJS += cs5530.o
-endif     
+ifeq ($(CONFIG_BLK_DEV_PIIX),y)
+IDE_OBJS += piix.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_QD6580),y)
+IDE_OBJS += qd6580.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_RZ1000),y)
+IDE_OBJS += rz1000.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_SVWKS),y)
+IDE_OBJS += serverworks.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_SIS5513),y)
+IDE_OBJS += sis5513.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_SLC90E66),y)
+IDE_OBJS += slc90e66.o
+endif
 
 ifeq ($(CONFIG_BLK_DEV_SL82C105),y)
 IDE_OBJS += sl82c105.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_TRM290),y)
+IDE_OBJS += trm290.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_UMC8672),y)
+IDE_OBJS += umc8672.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_VIA82CXXX),y)
+IDE_OBJS += via82cxxx.o
+endif
+
+# The virtualised raid layers MUST come after the ide itself or bad stuff
+# will happen.
+
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
 
 ifeq ($(CONFIG_PROC_FS),y)
@@ -183,12 +254,12 @@
 ###Collect
 
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
-  LX_OBJS += ide.o
+  LX_OBJS += ide.o ide-features.o ide-taskfile.o
   L_OBJS += ide-probe.o $(IDE_OBJS)
 else
   ifeq ($(CONFIG_BLK_DEV_IDE),m)
-  MIX_OBJS += ide.o $(IDE_OBJS)
-  M_OBJS += ide-mod.o ide-probe.o
+  MIX_OBJS += ide.o ide-features.o ide-taskfile.o $(IDE_OBJS)
+  M_OBJS += ide-mod.o ide-probe-mod.o
   endif
 endif
 
@@ -311,6 +382,32 @@
   endif
 endif
 
+###
+
+ifeq ($(CONFIG_BLK_DEV_ATARAID),y)
+L_OBJS += ataraid.o
+else
+  ifeq ($(CONFIG_BLK_DEV_ATARAID),m)
+  M_OBJS +=  ataraid.o
+  endif
+endif
+
+ifeq ($(CONFIG_BLK_DEV_ATARAID_PDC),y)
+L_OBJS += pdcraid.o
+else
+  ifeq ($(CONFIG_BLK_DEV_ATARAID_PDC),m)
+  M_OBJS += pdcraid.o
+  endif
+endif
+
+ifeq ($(CONFIG_BLK_DEV_ATARAID_HPT),y)
+L_OBJS += hptraid.o
+else
+  ifeq ($(CONFIG_BLK_DEV_ATARAID_HPT),m)
+  M_OBJS += hptraid.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE),y)
 SUB_DIRS	+= paride
 MOD_IN_SUB_DIRS	+= paride
@@ -322,5 +419,8 @@
 
 include $(TOPDIR)/Rules.make
 
-ide-mod.o: ide.o $(IDE_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS)
+ide-mod.o: ide.o ide-features.o ide-taskfile.o $(IDE_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ide.o ide-features.o ide-taskfile.o $(IDE_OBJS)
+
+ide-probe-mod.o: ide-probe.o ide-geometry.o
+	$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
diff -urN linux-2.2.20-pristine/drivers/block/README.buddha linux-2.2.20/drivers/block/README.buddha
--- linux-2.2.20-pristine/drivers/block/README.buddha	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/README.buddha	Mon Nov 26 13:14:22 2001
@@ -0,0 +1,210 @@
+
+The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by
+Geert Uytterhoeven based on the following specifications:
+
+------------------------------------------------------------------------
+
+Register map of the Buddha IDE controller and the
+Buddha-part of the Catweasel Zorro-II version
+
+The Autoconfiguration has been implemented just as Commodore
+described  in  their  manuals, no tricks have been used (for
+example leaving some address lines out of the equations...).
+If you want to configure the board yourself (for example let
+a  Linux  kernel  configure the card), look at the Commodore
+Docs.  Reading the nibbles should give this information:
+
+Vendor number: 4626 ($1212)
+product number: 0 (42 for Catweasel Z-II)
+Serial number: 0
+Rom-vector: $1000
+
+The  card  should be a Z-II board, size 64K, not for freemem
+list, Rom-Vektor is valid, no second Autoconfig-board on the
+same card, no space preferrence, supports "Shutup_forever".
+
+Setting  the  base address should be done in two steps, just
+as  the Amiga Kickstart does:  The lower nibble of the 8-Bit
+address is written to $4a, then the whole Byte is written to
+$48, while it doesn't matter how often you're writing to $4a
+as  long as $48 is not touched.  After $48 has been written,
+the  whole card disappears from $e8 and is mapped to the new
+addrress just written.  Make shure $4a is written befor $48,
+otherwise your chance is only 1:16 to find the board :-).
+
+The local memory-map is even active when mapped to $e8:
+
+$0-$7e		Autokonfig-space, see Z-II docs.
+
+$80-$7fd	reserved
+
+$7fe		Speed-select Register: Read & Write
+		(description see further down)
+
+$800-$8ff	IDE-Select 0 (Port 0, Register set 0)
+
+$900-$9ff	IDE-Select 1 (Port 0, Register set 1)
+
+$a00-$aff	IDE-Select 2 (Port 1, Register set 0)
+
+$b00-$bff	IDE-Select 3 (Port 1, Register set 1)
+
+$c00-$cff	IDE-Select 4 (Port 2, Register set 0,
+                          Catweasel only!)
+
+$d00-$dff	IDE-Select 5 (Port 3, Register set 1,
+			      Catweasel only!)
+
+$e00-$eff	local expansion port, on Catweasel Z-II the 
+		Catweasel registers are also mapped here.
+		Never touch, use multidisk.device!
+		
+$f00		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 0. 
+
+$f01-$f3f	mirror of $f00
+
+$f40		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 1. 
+
+$f41-$f7f	mirror of $f40
+
+$f80		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 2. 
+		(Catweasel only!)
+
+$f81-$fbf	mirror of $f80
+
+$fc0		write-only: Writing any value to this
+		register enables IRQs to be passed from the 
+		IDE ports to the Zorro bus. This mechanism 
+		has been implemented to be compatible with 
+		harddisks that are either defective or have
+		a buggy firmware and pull the IRQ line up 
+		while starting up. If interrupts would 
+		always be passed to the bus, the computer 
+		might not start up. Once enabled, this flag 
+		can not be disabled again. The level of the 
+		flag can not be determined by software 
+		(what for? Write to me if it's necessary!).
+
+$fc1-$fff	mirror of $fc0
+
+$1000-$ffff	Buddha-Rom with offset $1000 in the rom
+		chip. The addresses $0 to $fff of the rom 
+		chip cannot be read. Rom is Byte-wide and
+		mapped to even addresses.
+
+The  IDE ports issue an INT2.  You can read the level of the
+IRQ-lines  of  the  IDE-ports by reading from the three (two
+for  Buddha-only)  registers  $f00, $f40 and $f80.  This way
+more  than one I/O request can be handled and you can easily
+determine  what  driver  has  to serve the INT2.  Buddha and
+Catweasel  expansion  boards  can issue an INT6.  A seperate
+memory  map  is available for the I/O module and the sysop's
+I/O module.
+
+The IDE ports are fed by the address lines A2 to A4, just as
+the  Amiga  1200  and  Amiga  4000  IDE ports are.  This way
+existing  drivers  can be easily ported to Buddha.  A move.l
+polls  two  words  out of the same address of IDE port since
+every  word  is  mirrored  once.  movem is not possible, but
+it's  not  necessary  either,  because  you can only speedup
+68000  systems  with  this  technique.   A 68020 system with
+fastmem is faster with move.l.
+
+If you're using the mirrored registers of the IDE-ports with
+A6=1,  the Buddha doesn't care about the speed that you have
+selected  in  the  speed  register (see further down).  With
+A6=1  (for example $840 for port 0, register set 0), a 780ns
+access  is being made.  These registers should be used for a
+command   access   to  the  harddisk/CD-Rom,  since  command
+accesses  are Byte-wide and have to be made slower according
+to the ATA-X3T9 manual.
+
+Now  for the speed-register:  The register is byte-wide, and
+only  the  upper  three  bits are used (Bits 7 to 5).  Bit 4
+must  always  be set to 1 to be compatible with later Buddha
+versions  (if  I'll  ever  update this one).  I presume that
+I'll  never use the lower four bits, but they have to be set
+to 1 by definition.
+  The  values in this table have to be shifted 5 bits to the
+left and or'd with $1f (this sets the lower 5 bits).
+
+All  the timings have in common:  Select and IOR/IOW rise at
+the  same  time.   IOR  and  IOW have a propagation delay of
+about  30ns  to  the clocks on the Zorro bus, that's why the
+values  are no multiple of 71.  One clock-cycle is 71ns long
+(exactly 70,5 at 14,18 Mhz on PAL systems).
+
+value 0 (Default after reset)
+
+497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles)
+(same timing as the Amiga 1200 does on it's IDE port without
+accelerator card)
+
+value 1
+
+639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 2
+
+781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 3
+
+355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+value 4
+
+355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles)
+
+value 5
+
+355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 6
+
+1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 7
+
+355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+When accessing IDE registers with A6=1 (for example $84x),
+the timing will always be mode 0 8-bit compatible, no matter
+what you have selected in the speed register:
+
+781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. 
+
+All  the  timings with a very short select-signal (the 355ns
+fast  accesses)  depend  on the accelerator card used in the
+system:  Sometimes two more clock cycles are inserted by the
+bus  interface,  making  the  whole access 497ns long.  This
+doesn't  affect  the  reliability  of the controller nor the
+performance  of  the  card,  since  this doesn't happen very
+often.
+
+All  the  timings  are  calculated  and  only  confirmed  by
+measurements  that allowed me to count the clock cycles.  If
+the  system  is clocked by an oscillator other than 28,37516
+Mhz  (for  example  the  NTSC-frequency  28,63636 Mhz), each
+clock  cycle is shortened to a bit less than 70ns (not worth
+mentioning).   You  could think of a small performance boost
+by  overclocking  the  system,  but  you would either need a
+multisync  monitor,  or  a  graphics card, and your internal
+diskdrive would go crazy, that's why you shouldn't tune your
+Amiga this way.
+
+Giving  you  the  possibility  to  write  software  that  is
+compatible  with both the Buddha and the Catweasel Z-II, The
+Buddha  acts  just  like  a  Catweasel  Z-II  with no device
+connected  to  the  third  IDE-port.   The IRQ-register $f80
+always  shows a "no IRQ here" on the Buddha, and accesses to
+the  third  IDE  port  are  going into data's Nirwana on the
+Buddha.
+
+			    Jens Schönfeld february 19th, 1997
+					updated may 27th, 1997
+			     eMail: sysop@nostlgic.tng.oche.de
+
diff -urN linux-2.2.20-pristine/drivers/block/aec62xx.c linux-2.2.20/drivers/block/aec62xx.c
--- linux-2.2.20-pristine/drivers/block/aec62xx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/aec62xx.c	Mon Nov 26 13:14:22 2001
@@ -0,0 +1,587 @@
+/*
+ * linux/drivers/block/aec62xx.c		Version 0.08	Mar. 28, 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, int);
+extern int (*aec62xx_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	char *p = buffer;
+
+	u32 bibma = bmide_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	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 */
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = 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->rom_address) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
+	}
+
+#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 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 -urN linux-2.2.20-pristine/drivers/block/ali14xx.c linux-2.2.20/drivers/block/ali14xx.c
--- linux-2.2.20-pristine/drivers/block/ali14xx.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ali14xx.c	Mon Nov 26 13:14:22 2001
@@ -47,8 +47,10 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /* port addresses for auto-detection */
@@ -116,7 +118,7 @@
 	byte param1, param2, param3, param4;
 	unsigned long flags;
 	ide_pio_data_t d;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 
 	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
 
@@ -202,11 +204,11 @@
 {
 	/* auto-detect IDE controller port */
 	if (!findPort()) {
-		printk("ali14xx: not found\n");
+		printk("\nali14xx: not found");
 		return;
 	}
 
-	printk("ali14xx: base= 0x%03x, regOn = 0x%02x\n", basePort, regOn);
+	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
 	ide_hwifs[0].chipset = ide_ali14xx;
 	ide_hwifs[1].chipset = ide_ali14xx;
 	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
@@ -217,7 +219,7 @@
 
 	/* initialize controller registers */
 	if (!initRegisters()) {
-		printk("ali14xx: Chip initialization failed\n");
+		printk("\nali14xx: Chip initialization failed");
 		return;
 	}
 }
diff -urN linux-2.2.20-pristine/drivers/block/alim15x3.c linux-2.2.20/drivers/block/alim15x3.c
--- linux-2.2.20-pristine/drivers/block/alim15x3.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/alim15x3.c	Tue Nov 27 13:36:32 2001
@@ -1,75 +1,32 @@
 /*
+ * linux/drivers/ide/alim15x3.c         Version 0.10    Jun. 9, 2000
  *
- *  Copyright (C) 1998-99 Michel Aubry, Maintainer
- *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer
+ *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
  *
- *  (U)DMA capable version of ali 1543(C), 1535(D)
+ *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ *  May be copied or modified under the terms of the GNU General Public License
  *
- */
-
-/*  ======================================================
- *  linux/drivers/block/alim15x3.c
- *  version: 1.0 beta3 (Sep. 6, 1999)
- *	e-mail your problems to cjtsai@ali.com.tw
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
  *
- *  Note: if you want to combine the code to kernel 2.3.x
- *  you should ---
- *		change:		//#define ALI_KERNEL_2_3_X
- *		to:			#define ALI_KERNEL_2_3_X
- *  and replace the "alim15x3.c" exists in kernel 2.3.x
- *  with this file. I am not very sure that this file can 
- *  support all 2.3.x. Because I only test it in kernel
- *  version 2.3.16. So, before you replace the file, backup
- *	the old one.
- * ======================================================= */
-
-/* ===================== important =======================
- *  for 2.2.x, you should use "//#define ALI_KERNEL_2_3_X"
- *  for 2.3.x, you should use "#define ALI_KERNEL_2_3_X"
- * ======================================================= */
-//#define ALI_KERNEL_2_3_X
-
+ **********************************************************************
+ *  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 <asm/io.h>
-
-#if defined(ALI_KERNEL_2_3_X)
+#include <linux/hdreg.h>
 #include <linux/ide.h>
-#else
-#include "ide.h"
-#endif
-
-#include "ide_modes.h"
-
-static int m5229_revision = -1;
-static int chip_is_1543c_e = 0;
-static int cable_80_pin[2] = { 0, 0 };
-
-/* This is fun.  -DaveM */
-#define IDE_SETXFER			0x03
-#define IDE_SETFEATURE		0xef
-
-#define IDE_DMA2_ENABLE		0x22	// dma
-#define IDE_DMA1_ENABLE		0x21
-#define IDE_DMA0_ENABLE		0x20
-
-#define IDE_UDMA4_ENABLE	0x44	// ultra 66
-#define IDE_UDMA3_ENABLE	0x43
-
-#define IDE_UDMA2_ENABLE	0x42	// ultra 33
-#define IDE_UDMA1_ENABLE	0x41
-#define IDE_UDMA0_ENABLE	0x40
-
-
+#include <linux/init.h>
 
-#if defined(ALI_KERNEL_2_3_X)
-// =====================   Support 2.3.x   =====================
+#include <asm/io.h>
 
+#include "ide_modes.h"
 
 #define DISPLAY_ALI_TIMINGS
 
@@ -108,100 +65,7 @@
 	"error DRQ     ",
 	"error DRQ busy"
 };
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	byte confreg0 = 0, confreg1 =0, progif = 0;
-	int errors = 0;
-
-	if (pci_read_config_byte(dev, 0x50, &confreg1))
-		goto veryspecialsettingserror;
-	if (!(confreg1 & 0x02))
-		if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02))
-			goto veryspecialsettingserror;
-
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif))
-		goto veryspecialsettingserror;
-	if (!(progif & 0x40)) {
-		/*
-		 * The way to enable them is to set progif
-		 * writable at 0x4Dh register, and set bit 6
-		 * of progif to 1:
-		 */
-		if (pci_read_config_byte(dev, 0x4d, &confreg0))
-			goto veryspecialsettingserror;
-		if (confreg0 & 0x80)
-			if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80))
-				goto veryspecialsettingserror;
-		if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40))
-			goto veryspecialsettingserror;
-		if (confreg0 & 0x80)
-			if (pci_write_config_byte(dev, 0x4d, confreg0))
-				errors++;
-	}
-
-	if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40)))
-		goto veryspecialsettingserror;
-
-	printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n",
-		name, errors ? "with Error(s)" : "Succeeded" );
-	return 0;
-
-veryspecialsettingserror:
-	printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name);
-	return 0;
-}
-
-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 = ide_system_bus_speed();
-	int port = hwif->index ? 0x5c : 0x58;
-
-	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();
-	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)
-	 */
-}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
 static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy)
 {
 	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
@@ -307,11 +171,11 @@
 				((reg5yh & 0x30)>>4) + 12 );
 		}
 	} else {
-		p += sprintf(p, q,
-			(tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4,
-			(tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4,
-			(tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4,
-			(tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4 );
+		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
@@ -369,375 +233,470 @@
 }
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+static byte m5229_revision	= 0;
+static byte chip_is_1543c_e	= 0;
 
-// ===================   End Support 2.3.x   ===================
-#endif	// defined(ALI_KERNEL_2_3_X)
-
+byte ali_proc = 0;
+static struct pci_dev *isa_dev;
 
-
-static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
 {
-	if(bits & 0x04)
-		return IDE_DMA2_ENABLE;
-	if(bits & 0x02)
-		return IDE_DMA1_ENABLE;
-	return IDE_DMA0_ENABLE;
-}
+	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;
 
-static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x10)
-		return IDE_UDMA4_ENABLE;
-	if(bits & 0x08)
-		return IDE_UDMA3_ENABLE;
-	if(bits & 0x04)
-		return IDE_UDMA2_ENABLE;
-	if(bits & 0x02)
-		return IDE_UDMA1_ENABLE;
-	return IDE_UDMA0_ENABLE;
-}
+	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;
 
-static __inline__ int wait_for_ready(ide_drive_t *drive)
-{
-	int timeout = 20000;
-	byte stat;
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
 
-	while(--timeout) {
-		stat = GET_STAT();	// printk("STAT(%2x) ", stat);
-		
-		if(!(stat & BUSY_STAT)) {
-			if((stat & READY_STAT) || (stat & ERR_STAT))
-				break;
+	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);
 		}
-		udelay(150);
 	}
-	if((stat & ERR_STAT) || timeout <= 0)
-		return 1;
-	return 0;
-}
-
-static void ali15x3_do_setfeature(ide_drive_t *drive, byte command)
-{
-	unsigned long flags;
-	byte old_select;
-
-	save_flags(flags);
-	cli();
-		
-	old_select = IN_BYTE(IDE_SELECT_REG);	//  save old selected device
-	OUT_BYTE(drive->select.all, IDE_SELECT_REG);	// "SELECT "
-
-	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);	// "SETXFER "	
-	OUT_BYTE(command, IDE_NSECTOR_REG);	// "CMND "
 	
-	if(wait_for_ready(drive))	// "wait "
-		goto out;
+	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);
 
-	OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);	// "SETFEATURE "
-	(void) wait_for_ready(drive);	// "wait "
+	/*
+	 * 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)
+	 */
 
-out:	
-	OUT_BYTE(old_select, IDE_SELECT_REG);	// restore to old "selected device"
-	restore_flags(flags);
 }
 
-static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
+static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	byte unit = (drive->select.b.unit & 0x01);
-	byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
-	byte tmpbyte;
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long flags;
-	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;		
-	
-/*	if((((drive->id->dma_mword & 0x0007) << 8) !=
-	   (drive->id->dma_mword & 0x0700)))*/
-		ali15x3_do_setfeature(drive, dma2_bits_to_command(bits));
-
-	// clear "ultra enable" bit
-	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
-	if(unit)
-		tmpbyte &= 0x7f;
-	else
-		tmpbyte &= 0xf7;
-	save_flags(flags);
-	cli();
-	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
-	restore_flags(flags);
-	drive->id->dma_ultra = 0x00;
-
-	/* Enable DMA*/
-	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-
-	printk(" ALI15X3: MultiWord DMA enabled\n");
-}
-
-static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base)
-{	
-	byte unit = (drive->select.b.unit & 0x01);
-	byte bits = drive->id->dma_ultra & 0x1f;	
-	byte tmpbyte;
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long flags;
-	unsigned char udma_mode = 0;
-	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
+	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(bits & 0x18) {	// 00011000, disk: ultra66
-		if(m5229_revision < 0xc2) {		// controller: ultra33
-			bits = 0x04;	// 00000100, use ultra33, mode 2			
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0004;			
-		}
-		else {	// controller: ultra66
-			// Try to detect word93 bit13 and 80-pin cable (from host view)
-			if( ! ( (drive->id->word93 & 0x2000) && cable_80_pin[hwif->channel] ) ) {	
-				bits = 0x04;	// 00000100, use ultra33, mode 2
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x0004;
-			}
-		}
+	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);
 	}
 
-	// set feature only if we are not in that mode
-/*	if(((drive->id->dma_ultra & 0x001f) << 8) !=
-	   (drive->id->dma_ultra & 0x1f00))*/
-		ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits));
-	udma_mode &= 0x0f;	// get UDMA mode
+	err = ide_config_drive_speed(drive, speed);
 
-	/* Enable DMA and UltraDMA */
-	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed >= XFER_SW_DMA_0) {
+		unsigned long dma_base = hwif->dma_base;
 
-	// m5229 ultra
-	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
-	
-	tmpbyte &= (0x0f << ( (1-unit) << 2) );	// clear bit0~3 or bit 4~7
-	// enable ultra dma and set timing
-	tmpbyte |= ( (0x08 | (4-udma_mode) ) << (unit << 2) );
-	// set to m5229
-	save_flags(flags);
-	cli();		
-	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
-	restore_flags(flags);
-
-	if(udma_mode >= 3) { // ultra 66
-		pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte);
-		tmpbyte |= 1;			
-		save_flags(flags);
-		cli();
-		pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte);		
-		restore_flags(flags);
+		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
 	}
 
-	printk(" ALI15X3: Ultra DMA enabled\n");
+	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 int ali15x3_dma_onoff(ide_drive_t *drive, int enable)
+static void config_chipset_for_pio (ide_drive_t *drive)
 {
-	if(enable) {
-		ide_hwif_t *hwif = HWIF(drive);
-		unsigned long dma_base = hwif->dma_base;
-		struct hd_driveid *id = drive->id;
-				
-		if((id->field_valid & 0x0004) && 
-		   (id->dma_ultra & 0x001f)) {
-			// 1543C_E, in ultra mode, some WDC "harddisk" will cause "CRC" errors
-			// (even if no CRC problem), so we try to use "DMA" here
-			if( m5229_revision <= 0x20)
-				ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */
-			else if( (m5229_revision < 0xC2) && 
-			   ( (drive->media!=ide_disk) || (chip_is_1543c_e && strstr(id->model, "WDC ")) ) )
-				ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */
-			else	// >= 0xC2 or 0xC1 with no problem
-				ali15x3_udma_enable(drive, dma_base);	/* UltraDMA modes. */
-		} else {
-			ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */		
-		}
+	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);
 	}
 
-	drive->using_dma = enable;	// on, off
-	return 0;
+	(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 int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+static byte ali15x3_can_ultra (ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
 
-	if( (m5229_revision<=0x20) && (drive->media!=ide_disk) )
-		return hwif->dmaproc(ide_dma_off_quietly, drive);	
-
-	/* Even if the drive is not _currently_ in a DMA
-	 * mode, we succeed, and we'll enable it manually
-	 * below in alim15x3_dma_onoff */
-	if((id != NULL) && 
-	   (id->capability & 1) &&	// dma supported
-	   hwif->autodma ) {		
-		if(id->field_valid & 0x0004)	// word 88 is valid
-			if(id->dma_ultra & 0x001F)	// 00011111 => ultra dma mode 0~4
-				return hwif->dmaproc(ide_dma_on, drive);
-
-		if(id->field_valid & 0x0002)	// words 64~70 is valid
-			if((id->dma_mword & 0x0007)	// word 63, multiword DMA mode 0~2
-			 || (id->dma_1word & 0x0007)) // word 62, single word DMA mode 0~2
-				return hwif->dmaproc(ide_dma_on, drive);
+	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;
 	}
+}
 
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+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) {
+	switch(func) {
 		case ide_dma_check:
 			return ali15x3_config_drive_for_dma(drive);
-		case ide_dma_on:
-		case ide_dma_off:
-		case ide_dma_off_quietly:
-			return ali15x3_dma_onoff(drive, (func == ide_dma_on));					
 		case ide_dma_write:
-			if( (m5229_revision < 0xC2) && (drive->media != ide_disk) )
+			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 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+
+	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 || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
+		/*
+		 *
+		 */
+	} 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 ide_dmaproc(func, drive);	// use standard DMA stuff
+	return 0;
 }
 
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{	
+/*
+ * 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 tmp_m5229_revision;
+	byte tmpbyte;
 
-	struct pci_dev *dev_m1533, *dev_m5229 = hwif->pci_dev;
-	byte ideic, inmir, tmpbyte;	
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-								  1, 11, 0, 12, 0, 14, 0, 15 };
+	__save_flags(flags);
+	__cli();
 
-	hwif->irq = hwif->channel ? 15 : 14;	
+	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
+		 */
 
-	// look for ISA bridge m1533
-	for (dev_m1533=pci_devices; dev_m1533; dev_m1533=dev_m1533->next)
-		if(dev_m1533->vendor==PCI_VENDOR_ID_AL && 
-		   dev_m1533->device==PCI_DEVICE_ID_AL_M1533)
-			break;	// we find it
+		/*
+		 * enable "Cable Detection", m5229, 0x4b, bit3
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
 
-	pci_read_config_byte(dev_m1533, 0x58, &ideic);	// read IDE interface control
-	ideic = ideic & 0x03;	// bit0, bit1
-	
-	/* get IRQ for IDE Controller */
-	if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) { // get SIRQ1 routing table
-		pci_read_config_byte(dev_m1533, 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(dev_m1533, 0x75, &inmir);
-		inmir = inmir & 0x0f;
-		hwif->irq = irq_routing_table[inmir];
+		/*
+		 * 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;
 	}
-	
-	// read m5229 revision to a temp variable
-	pci_read_config_byte(dev_m5229, PCI_REVISION_ID, &tmp_m5229_revision);
 
-	if(m5229_revision == -1)	{	// only do it one time.
-		m5229_revision = 0;	// change the default to 0	
-		printk("\n************************************\n");
-		printk("*    ALi IDE driver (1.0 beta3)    *\n");
-		printk("*       Chip Revision is %02X        *\n", tmp_m5229_revision);
-		printk("*  Maximum capability is ");
-		if(tmp_m5229_revision >= 0xC2)
-			printk("- UDMA 66 *\n");
-		else if(tmp_m5229_revision >= 0xC0)
-			printk("- UDMA 33 *\n");
-		else if(tmp_m5229_revision == 0x20)
-			printk("  -  DMA  *\n");
-		else
-			printk("  -  PIO  *\n");
-		printk("************************************\n\n");	
-
-		// support CD-ROM DMA mode
-		pci_read_config_byte(dev_m5229, 0x53, &tmpbyte);
-		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-		save_flags(flags);
-		cli();		
-		pci_write_config_byte(dev_m5229, 0x53, tmpbyte);
-		restore_flags(flags);
-	}
-	
-	if ( (hwif->dma_base) && (tmp_m5229_revision>=0x20) ) {
-		
-#if defined(ALI_KERNEL_2_3_X)
-		if(tmp_m5229_revision>=0xC2)
-			hwif->udma_four = 1;
-		else
-			hwif->udma_four = 0;
-#endif
-		
-		if(m5229_revision == 0) {	// only do it one time
-			m5229_revision = tmp_m5229_revision;	// keep it
-
-			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
-				save_flags(flags);
-				cli();
-				// enable "Cable Detection", m5229, 0x4b, bit3
-				pci_read_config_byte(dev_m5229, 0x4b, &tmpbyte);
-				pci_write_config_byte(dev_m5229, 0x4b, tmpbyte | 0x08);
-
-				// set south-bridge's enable bit, m1533, 0x79
-				pci_read_config_byte(dev_m1533, 0x79, &tmpbyte);
-				if(m5229_revision==0xC2)		// 1543C-B0 (m1533, 0x79, bit 2)
-					pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x04);
-				else if	(m5229_revision==0xC3)	// 1553/1535 (m1533, 0x79, bit 1)
-					pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x02);
-				restore_flags(flags);
-								
-				// Ultra66 cable detection (from Host View)
-				// m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-				pci_read_config_byte(dev_m5229, 0x4a, &tmpbyte);
-				if(! (tmpbyte & 0x01))	// 0x4a, bit0 is 0 => 
-					cable_80_pin[0] = 1;	// primary channel has 80-pin (from host view)
-				if(! (tmpbyte & 0x02))	// 0x4a, bit1 is 0 =>				
-					cable_80_pin[1] = 1;	// secondary channel has 80-pin (from host view)					
-			} 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_m5229, 0x4b, &tmpbyte);
-				save_flags(flags);
-				cli();
-				pci_write_config_byte(dev_m5229, 0x4b, tmpbyte & 0x7F);	// clear bit 7
-				restore_flags(flags);
-
-				// check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-				pci_read_config_byte(dev_m1533, 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];
 		}
-		
-		// M1543 or newer for DMAing
+	}
+#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;
-	} else {
-		// if both channel use PIO, then chip revision is not important.
-		// we should't assign m5229_revision here (assign it will affect
-		// the chip detection procedure above --- if(! m5229_revision)
-		hwif->autodma = 0;			
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
 	}
-	
-#if defined(ALI_KERNEL_2_3_X) 
-	hwif->tuneproc = &ali15x3_tune_drive;
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	bmide_dev = hwif->pci_dev;
-	ali_display_info = &ali_get_info;
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */	
-#endif  /* defined(ALI_KERNEL_2_3_X) */	
-	
-	return;
-}
\ No newline at end of file
+#else
+	hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((dmabase) && (m5229_revision < 0x20)) {
+		return;
+	}
+	ide_setup_dma(hwif, dmabase, 8);
+}
diff -urN linux-2.2.20-pristine/drivers/block/amd74xx.c linux-2.2.20/drivers/block/amd74xx.c
--- linux-2.2.20-pristine/drivers/block/amd74xx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/amd74xx.c	Tue Nov 27 13:36:55 2001
@@ -0,0 +1,482 @@
+/*
+ * 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, int);
+extern int (*amd74xx_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	char *p = buffer;
+	u32 bibma = bmide_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	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 ((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 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+
+#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 || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
+		/*
+		 *
+		 */
+	} 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)
+{
+#ifdef CONFIG_AMD74XX_OVERRIDE
+	byte ata66 = 1;
+#else
+	byte ata66 = 0;
+#endif /* CONFIG_AMD74XX_OVERRIDE */
+
+#if 0
+	pci_read_config_byte(hwif->pci_dev, 0x48, &ata66);
+	return ((ata66 & 0x02) ? 0 : 1);
+#endif
+	return ata66;
+}
+
+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;
+		hwif->autodma = 1;
+	} else {
+		hwif->autodma = 0;
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+void ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
diff -urN linux-2.2.20-pristine/drivers/block/ataraid.c linux-2.2.20/drivers/block/ataraid.c
--- linux-2.2.20-pristine/drivers/block/ataraid.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/ataraid.c	Tue Nov 27 00:00:26 2001
@@ -0,0 +1,319 @@
+/*
+   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);
+	                current->policy |= SCHED_YIELD;
+	                schedule();             
+		}
+	}
+	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);
+	                current->policy |= SCHED_YIELD;
+	                schedule();             
+		}
+	}
+	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 -urN linux-2.2.20-pristine/drivers/block/ataraid.h linux-2.2.20/drivers/block/ataraid.h
--- linux-2.2.20-pristine/drivers/block/ataraid.h	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/ataraid.h	Tue Nov 27 00:00:26 2001
@@ -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 -urN linux-2.2.20-pristine/drivers/block/buddha.c linux-2.2.20/drivers/block/buddha.c
--- linux-2.2.20-pristine/drivers/block/buddha.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/buddha.c	Mon Nov 26 13:14:22 2001
@@ -20,8 +20,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/zorro.h>
-
-#include "ide.h"
+#include <linux/ide.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
@@ -62,7 +61,7 @@
 #define BUDDHA_STATUS	0x1e		/* see status-bits */
 #define BUDDHA_CONTROL	0x11a
 
-static const u_int buddha_offsets[IDE_NR_PORTS] = {
+static int buddha_offsets[IDE_NR_PORTS] = {
     BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
     BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL
 };
@@ -140,29 +139,23 @@
      *  We support only _one_ of them, no multiple boards!
      */
 
-int buddha_probe_hwif(int index, ide_hwif_t *hwif)
+void buddha_init(void)
 {
-    static int buddha_index[CATWEASEL_NUM_HWIFS] = { 0, };
-    int i;
+    hw_regs_t hw;
+    int i, index;
 
     if (buddha_num_hwifs < 0 && !find_buddha())
-	return 0;
+	return;
 
     for (i = 0; i < buddha_num_hwifs; i++) {
-	if (!buddha_index[i]) {
+	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);
+	index = ide_register_hw(&hw, NULL);
+	if (index != -1)
 	    printk("ide%d: %s IDE interface\n", index,
 		   buddha_num_hwifs == BUDDHA_NUM_HWIFS ? "Buddha" :
 		   					  "Catweasel");
-	    buddha_index[i] = index+1;
-	}
-	if (buddha_index[i] == index+1) {
-	    ide_setup_ports(hwif, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
-	    		    buddha_offsets,
-			    (ide_ioreg_t)(buddha_board+buddha_irqports[i]),
-			    buddha_ack_intr);
-	    hwif->irq = IRQ_AMIGA_PORTS;
-	    return 1;
-	}
     }
-    return 0;
 }
diff -urN linux-2.2.20-pristine/drivers/block/cmd640.c linux-2.2.20/drivers/block/cmd640.c
--- linux-2.2.20-pristine/drivers/block/cmd640.c	Sun Mar 25 08:31:23 2001
+++ linux-2.2.20/drivers/block/cmd640.c	Mon Nov 26 13:14:22 2001
@@ -110,8 +110,10 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
@@ -593,7 +595,7 @@
 {
 	int setup_time, active_time, recovery_time, clock_time;
 	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = ide_system_bus_speed();
+	int bus_speed = system_bus_clock();
 
 	if (pio_mode > 5)
 		pio_mode = 5;
@@ -684,6 +686,7 @@
 		d.cycle_time,
 		d.overridden ? " (overriding vendor mode)" : "");
 	display_clocks(index);
+	return;
 }
 
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff -urN linux-2.2.20-pristine/drivers/block/cmd646.c linux-2.2.20/drivers/block/cmd646.c
--- linux-2.2.20-pristine/drivers/block/cmd646.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/cmd646.c	Wed Dec 31 16:00:00 1969
@@ -1,255 +0,0 @@
-/* $Id: cmd646.c,v 1.11.2.1 2000/01/31 05:02:39 davem Exp $
- * cmd646.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)
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include "ide.h"
-
-static int cmd646_config_drive_for_dma(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	/* Even if the drive is not _currently_ in a DMA
-	 * mode, we succeed, and we'll enable it manually
-	 * below in cmd646_dma_onoff.
-	 *
-	 * This is done for disks only, CDROMs and other
-	 * IDE devices are just too quirky.
-	 */
-	if((id != NULL) &&
-	   ((id->capability & 1) != 0) &&
-	   hwif->autodma &&
-	   (drive->media == ide_disk)) {
-		if(id->field_valid & 0x0004) {
-			if(id->dma_ultra & 0x0007)
-				return hwif->dmaproc(ide_dma_on, drive);
-		}
-		if(id->field_valid & 0x0002)
-			if((id->dma_mword & 0x0004) || (id->dma_1word & 0x0004))
-				return hwif->dmaproc(ide_dma_on, drive);
-	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
-}
-
-/* This is fun.  -DaveM */
-#define IDE_SETXFER		0x03
-#define IDE_SETFEATURE		0xef
-#define IDE_DMA2_ENABLE		0x22
-#define IDE_DMA1_ENABLE		0x21
-#define IDE_DMA0_ENABLE		0x20
-#define IDE_UDMA2_ENABLE	0x42
-#define IDE_UDMA1_ENABLE	0x41
-#define IDE_UDMA0_ENABLE	0x40
-
-static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return IDE_DMA2_ENABLE;
-	if(bits & 0x02)
-		return IDE_DMA1_ENABLE;
-	return IDE_DMA0_ENABLE;
-}
-
-static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return IDE_UDMA2_ENABLE;
-	if(bits & 0x02)
-		return IDE_UDMA1_ENABLE;
-	return IDE_UDMA0_ENABLE;
-}
-
-static __inline__ int wait_for_ready(ide_drive_t *drive)
-{
-	int timeout = 100;
-	byte stat;
-
-	while(--timeout) {
-		stat = GET_STAT();
-
-		printk("STAT(%2x) ", stat);
-		if(!(stat & BUSY_STAT)) {
-			if((stat & READY_STAT) || (stat & ERR_STAT))
-				break;
-		}
-		udelay(100);
-	}
-	if((stat & ERR_STAT) || timeout <= 0)
-		return 1;
-	return 0;
-}
-
-static void cmd646_do_setfeature(ide_drive_t *drive, byte command)
-{
-	unsigned long flags;
-	byte old_select;
-
-	save_flags(flags);
-	cli();
-	printk("SELECT ");
-	old_select = IN_BYTE(IDE_SELECT_REG);
-	OUT_BYTE(drive->select.all, IDE_SELECT_REG);
-	printk("SETXFER ");
-	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
-	printk("CMND ");
-	OUT_BYTE(command, IDE_NSECTOR_REG);
-	printk("wait ");
-	if(wait_for_ready(drive))
-		goto out;
-	printk("SETFEATURE ");
-	OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
-	printk("wait ");
-	(void) wait_for_ready(drive);
-out:
-	OUT_BYTE(old_select, IDE_SELECT_REG);
-	restore_flags(flags);
-}
-
-static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
-{
-	byte unit = (drive->select.b.unit & 0x01);
-	byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
-
-	printk("CMD646: MDMA enable [");
-	if((((drive->id->dma_mword & 0x0007) << 8) !=
-	    (drive->id->dma_mword & 0x0700)))
-		cmd646_do_setfeature(drive, dma2_bits_to_command(bits));
-	printk("DMA_CAP ");
-	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	printk("DONE]\n");
-}
-
-static void cmd646_udma_enable(ide_drive_t *drive, unsigned long dma_base)
-{
-	byte unit = (drive->select.b.unit & 0x01);
-	byte udma_ctrl, bits = drive->id->dma_ultra & 0x07;
-	byte udma_timing_bits;
-
-	printk("CMD646: UDMA enable [");
-	if(((drive->id->dma_ultra & 0x0007) << 8) !=
-	   (drive->id->dma_ultra & 0x0700))
-		cmd646_do_setfeature(drive, udma2_bits_to_command(bits));
-
-	/* Enable DMA and UltraDMA */
-	printk("DMA_CAP ");
-	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-
-	udma_ctrl = inb(dma_base + 3);
-
-	/* Put this channel into UDMA mode. */
-	printk("UDMA_CTRL ");
-	udma_ctrl |= (1 << unit);
-
-	/* Set UDMA2 usable timings. */
-	if(bits & 0x04)
-		udma_timing_bits = 0x10;
-	else if(bits & 0x02)
-		udma_timing_bits = 0x20;
-	else
-		udma_timing_bits = 0x30;
-	udma_ctrl &= ~(0x30 << (unit * 2));
-	udma_ctrl |=  (udma_timing_bits << (unit * 2));
-
-	outb(udma_ctrl, dma_base+3);
-	printk("DONE]\n");
-}
-
-static int cmd646_dma_onoff(ide_drive_t *drive, int enable)
-{
-	if(enable) {
-		ide_hwif_t *hwif = HWIF(drive);
-		unsigned long dma_base = hwif->dma_base;
-		struct hd_driveid *id = drive->id;
-		unsigned int class_rev;
-
-		/* UltraDMA only supported on PCI646U and PCI646U2,
-		 * which correspond to revisions 0x03 and 0x05 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 chipsets.
-		 */
-		pci_read_config_dword(hwif->pci_dev,
-				      PCI_CLASS_REVISION,
-				      &class_rev);
-		class_rev &= 0xff;
-		if((class_rev == 0x05) &&
-		   (id->field_valid & 0x0004) &&
-		   (id->dma_ultra & 0x07)) {
-			/* UltraDMA modes. */
-			cmd646_udma_enable(drive, dma_base);
-		} else {
-			/* Normal MultiWord DMA modes. */
-			cmd646_dma2_enable(drive, dma_base);
-		}
-	}
-	drive->using_dma = enable;
-	return 0;
-}
-
-static int cmd646_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	if(func == ide_dma_check)
-		return cmd646_config_drive_for_dma(drive);
-	else if(func == ide_dma_on || func == ide_dma_off || func == ide_dma_off_quietly)
-		return cmd646_dma_onoff(drive, (func == ide_dma_on));
-
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-
-__initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned char mrdmode;
-
-	hwif->chipset = ide_cmd646;
-
-	/* 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, 0x71, &mrdmode);
-	mrdmode &= ~(0x30);
-	(void) pci_write_config_byte(dev, 0x71, 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, 0x71, mrdmode | 0x02);
-
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, 0x53, 0x40);
-	(void) pci_write_config_byte(dev, 0x54, 0x3f);
-	(void) pci_write_config_byte(dev, 0x55, 0x40);
-	(void) pci_write_config_byte(dev, 0x56, 0x3f);
-	(void) pci_write_config_byte(dev, 0x57, 0x5c);
-	(void) pci_write_config_byte(dev, 0x58, 0x3f);
-	(void) pci_write_config_byte(dev, 0x5b, 0x3f);
-
-#ifdef CONFIG_PPC
-	(void) pci_write_config_byte(dev, 0x73, 0xf0);
-#endif /* CONFIG_PPC */
-
-	hwif->dmaproc = &cmd646_dmaproc;
-}
diff -urN linux-2.2.20-pristine/drivers/block/cmd64x.c linux-2.2.20/drivers/block/cmd64x.c
--- linux-2.2.20-pristine/drivers/block/cmd64x.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/cmd64x.c	Mon Nov 26 23:34:31 2001
@@ -0,0 +1,797 @@
+/* $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, int);
+extern int (*cmd64x_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	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! */
+}
+
+#if 0
+static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+	p += sprintf(p, "thingy stuff\n");
+	return (char *)p;
+}
+static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	char *p = buffer;
+	p = cmd64x_chipset_data(buffer, bmide_dev);
+	return p-buffer;	/* hoping it is less than 4K... */
+}
+#endif
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte cmd64x_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 void config_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 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;
+
+	byte 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;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_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 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;
+	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_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 & 0x003F) {
+				/* 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 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 */
+			}
+			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 */
+			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 */
+
+unsigned int __init pci_init_cmd64x (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->rom_address) {
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
+	}
+#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 ata66_cmd64x (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;
+}
+
+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->tuneproc	= &cmd64x_tuneproc;
+	hwif->speedproc	= &cmd64x_tune_chipset;
+	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_649:
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_643:
+			hwif->dmaproc = &cmd64x_dmaproc;
+			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;
+			}
+			break;
+		default:
+			break;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
diff -urN linux-2.2.20-pristine/drivers/block/cs5530.c linux-2.2.20/drivers/block/cs5530.c
--- linux-2.2.20-pristine/drivers/block/cs5530.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/cs5530.c	Mon Nov 26 23:37:27 2001
@@ -1,13 +1,17 @@
 /*
- * linux/drivers/block/cs5530.c		Version 0.4	Feb 6, 2000
+ * linux/drivers/ide/cs5530.c           Version 0.6     Mar. 18, 2000
  *
- * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
+ * 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>
@@ -19,167 +23,69 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-
-#ifndef SETFEATURES_XFER
-	#define CS5530_2_2_KERNEL
-#endif
-
-#ifdef CS5530_2_2_KERNEL
-	#include "ide.h"
-	#define XFER_UDMA_6	0x46	/* 0100|0110 */
-	#define XFER_UDMA_5	0x45	/* 0100|0101 */
-	#define XFER_UDMA_4	0x44	/* 0100|0100 */
-	#define XFER_UDMA_3	0x43	/* 0100|0011 */
-	#define XFER_UDMA_2	0x42	/* 0100|0010 */
-	#define XFER_UDMA_1	0x41	/* 0100|0001 */
-	#define XFER_UDMA_0	0x40	/* 0100|0000 */
-	#define XFER_MW_DMA_2	0x22	/* 0010|0010 */
-	#define XFER_MW_DMA_1	0x21	/* 0010|0001 */
-	#define XFER_MW_DMA_0	0x20	/* 0010|0000 */
-	#define XFER_SW_DMA_2	0x12	/* 0001|0010 */
-	#define XFER_SW_DMA_1	0x11	/* 0001|0001 */
-	#define XFER_SW_DMA_0	0x10	/* 0001|0000 */
-	#define XFER_PIO_4	0x0C	/* 0000|1100 */
-	#define XFER_PIO_3	0x0B	/* 0000|1011 */
-	#define XFER_PIO_2	0x0A	/* 0000|1010 */
-	#define XFER_PIO_1	0x09	/* 0000|1001 */
-	#define XFER_PIO_0	0x08	/* 0000|1000 */
-	#define XFER_PIO_SLOW	0x00	/* 0000|0000 */
-	#define SETFEATURES_XFER 0x03	/* Set transfer mode */
-	#define pci_for_each_dev(dev) \
-        	for(dev = pci_devices; dev; dev=dev->next)
-#else
-	#include <linux/ide.h>
-#endif	/* CS5530_2_2_KERNEL */
-
+#include <linux/ide.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+
 #include "ide_modes.h"
 
-/*
- * Return the mode name for a drive transfer mode value:
- */
-static const char *strmode (byte mode)
+#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, int);
+extern int (*cs5530_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
 {
-	switch (mode) {
-		case XFER_UDMA_4:	return("UDMA4");
-		case XFER_UDMA_3:	return("UDMA3");
-		case XFER_UDMA_2:	return("UDMA2");
-		case XFER_UDMA_1:	return("UDMA1");
-		case XFER_UDMA_0:	return("UDMA0");
-		case XFER_MW_DMA_2:	return("MDMA2");
-		case XFER_MW_DMA_1:	return("MDMA1");
-		case XFER_MW_DMA_0:	return("MDMA0");
-		case XFER_SW_DMA_2:	return("SDMA2");
-		case XFER_SW_DMA_1:	return("SDMA1");
-		case XFER_SW_DMA_0:	return("SDMA0");
-		case XFER_PIO_4:	return("PIO4");
-		case XFER_PIO_3:	return("PIO3");
-		case XFER_PIO_2:	return("PIO2");
-		case XFER_PIO_1:	return("PIO1");
-		case XFER_PIO_0:	return("PIO0");
-		default:		return("???");
-	}
+	char *p = buffer;
+	u32 bibma = bmide_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	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		i, error = 1;
-	byte		stat;
-	ide_hwif_t	*hwif = HWIF(drive);
+	int error = 0;
 
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode));
-	/*
-	 * If this is a DMA mode setting, then turn off all DMA bits.
-	 * We will set one of them back on afterwards, if all goes well.
-	 *
-	 * Not sure why this is needed (it looks very silly),
-	 * but other IDE chipset drivers also do this fiddling.  ???? -ml
- 	 */
-	switch (mode) {
-		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_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-	}
+	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+	error = ide_config_drive_speed(drive, mode);
 
-	/*
-	 * Select the drive, and issue the SETFEATURES command
-	 */
-	disable_irq(hwif->irq);
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(mode, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
-
-	/*
-	 * 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.
-	 */
-	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;
-		}
-	}
-	enable_irq(hwif->irq);
-
-	/*
-	 * Turn dma bit on if all is okay
-	 */
-	if (error) {
-		(void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat);
-	} else {
-		switch (mode) {
-			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;
-		}
-	}
 	return error;
 }
 
@@ -218,6 +124,7 @@
 	}
 }
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
 /*
  * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
  * for both the chipset and drive.
@@ -249,18 +156,13 @@
 	 */
 	if (mate->present) {
 		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1)) {
-#ifndef CS5530_2_2_KERNEL
-			if (!hwif->dmaproc(ide_dma_bad_drive, mate))
-#endif /* CS5530_2_2_KERNEL */
-			{
-				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;
-			}
+		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;
 		}
 	}
 
@@ -268,27 +170,22 @@
 	 * 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) {
-#ifndef CS5530_2_2_KERNEL
-		if (!hwif->dmaproc(ide_dma_bad_drive, drive))
-#endif /* CS5530_2_2_KERNEL */
-		{
-			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;
-			}
+	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;
 		}
 	}
 
@@ -344,9 +241,12 @@
 		case ide_dma_check:
 			return cs5530_config_dma(drive);
 		default:
-			return ide_dmaproc(func, drive);
+			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.
@@ -357,7 +257,15 @@
 	unsigned short pcicmd = 0;
 	unsigned long flags;
 
-	pci_for_each_dev (dev) {
+#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 */
+
+	for(dev = pci_devices; dev; dev=dev->next) {
 		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
 			switch (dev->device) {
 				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
@@ -426,6 +334,7 @@
 	pci_write_config_byte(master_0, 0x43, 0xc1);
 
 	restore_flags(flags);
+
 	return 0;
 }
 
@@ -435,13 +344,6 @@
  */
 void __init ide_init_cs5530 (ide_hwif_t *hwif)
 {
-#ifndef CS5530_2_2_KERNEL
-	static int already_done = 0;
-	if (!already_done) {
-		++already_done;
-		(void) pci_init_cs5530 (hwif->pci_dev, "CS5530");
-	}
-#endif /* CS5530_2_2_KERNEL */
 	if (hwif->mate)
 		hwif->serialized = hwif->mate->serialized = 1;
 	if (!hwif->dma_base) {
@@ -449,7 +351,12 @@
 	} 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);
diff -urN linux-2.2.20-pristine/drivers/block/cy82c693.c linux-2.2.20/drivers/block/cy82c693.c
--- linux-2.2.20-pristine/drivers/block/cy82c693.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/cy82c693.c	Mon Nov 26 13:14:22 2001
@@ -0,0 +1,432 @@
+/*
+ * linux/drivers/block/cy82c693.c	Version 0.34	Dec. 13, 1999
+ *
+ *  Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-99 Andre Hedrick, 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/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-09-03 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;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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 = dev->next;
+
+#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
+ */
+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", data, name);
+#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", data, name);
+#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;
+	if (hwif->dma_base) {
+		hwif->dmaproc = &cy82c693_dmaproc;
+		hwif->drives[0].autotune = 0;
+		hwif->drives[1].autotune = 0;
+	} else {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+}
diff -urN linux-2.2.20-pristine/drivers/block/dtc2278.c linux-2.2.20/drivers/block/dtc2278.c
--- linux-2.2.20-pristine/drivers/block/dtc2278.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/dtc2278.c	Mon Nov 26 13:14:22 2001
@@ -14,8 +14,10 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
diff -urN linux-2.2.20-pristine/drivers/block/falconide.c linux-2.2.20/drivers/block/falconide.c
--- linux-2.2.20-pristine/drivers/block/falconide.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/falconide.c	Mon Nov 26 13:14:22 2001
@@ -13,8 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-
-#include "ide.h"
+#include <linux/ide.h>
 
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
@@ -41,9 +40,9 @@
 #define ATA_HD_STATUS	0x1d		/* see status-bits */
 #define ATA_HD_CONTROL	0x39
 
-static const int falconide_offsets[IDE_NR_PORTS] = {
+static int falconide_offsets[IDE_NR_PORTS] = {
     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
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
 };
 
 
@@ -51,22 +50,17 @@
      *  Probe for a Falcon IDE interface
      */
 
-int falconide_probe_hwif(int index, ide_hwif_t *hwif)
+void falconide_init(void)
 {
-    static int falcon_index = 0;
-
-    if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
-	return 0;
+    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 (!falcon_index) {
-	printk("ide%d: Falcon IDE interface\n", index);
-	falcon_index = index+1;
-    }
-    if (falcon_index == index+1) {
-	ide_setup_ports(hwif, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets, 0,
-			NULL);
-	hwif->irq = IRQ_MFP_IDE;
-	return 1;
+	if (index != -1)
+	    printk("ide%d: Falcon IDE interface\n", index);
     }
-    return 0;
 }
diff -urN linux-2.2.20-pristine/drivers/block/gayle.c linux-2.2.20/drivers/block/gayle.c
--- linux-2.2.20-pristine/drivers/block/gayle.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/gayle.c	Mon Nov 26 13:14:22 2001
@@ -14,12 +14,10 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-
-#include "ide.h"
+#include <linux/ide.h>
 
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
-#include <asm/setup.h>
 
 
     /*
@@ -43,9 +41,9 @@
 #define GAYLE_STATUS	0x1e		/* see status-bits */
 #define GAYLE_CONTROL	0x101a
 
-static u_int gayle_offsets[IDE_NR_PORTS] = {
+static int gayle_offsets[IDE_NR_PORTS] = {
     GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, GAYLE_CONTROL
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
 };
 
 
@@ -103,27 +101,48 @@
     return 1;
 }
 
-
     /*
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-int gayle_probe_hwif(int index, ide_hwif_t *hwif)
+void gayle_init(void)
 {
-    static int gayle_index[GAYLE_NUM_HWIFS] = { 0, };
     int a4000, i;
 
     if (!MACH_IS_AMIGA)
-	return 0;
+	return;
 
     if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
-	return 0;
-
-    if (!GAYLE_HAS_CONTROL_REG)
-	gayle_offsets[IDE_CONTROL_OFFSET] = -1;
+	return;
 
     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-	if (!gayle_index[i]) {
+	ide_ioreg_t base, ctrlport, irqport;
+	ide_ack_intr_t *ack_intr;
+	hw_regs_t hw;
+	int index;
+
+	if (a4000) {
+	    base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000);
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+	    ack_intr = gayle_ack_intr_a4000;
+	} else {
+	    base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200);
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+	    ack_intr = gayle_ack_intr_a1200;
+	}
+
+	if (GAYLE_HAS_CONTROL_REG)
+	    ctrlport = base + GAYLE_CONTROL;
+	else
+	    ctrlport = 0;
+
+	base += i*GAYLE_NEXT_PORT;
+
+	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,
@@ -135,35 +154,16 @@
 		    break;
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
 	    }
-	    gayle_index[i] = index+1;
 	}
-	if (gayle_index[i] == index+1) {
-	    ide_ioreg_t base, irqport;
-	    ide_ack_intr_t *ack_intr;
-	    if (a4000) {
-		base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000);
-		irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
-		ack_intr = gayle_ack_intr_a4000;
-	    } else {
-		base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200);
-		irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
-		ack_intr = gayle_ack_intr_a1200;
-	    }
-	    base += i*GAYLE_NEXT_PORT;
-	    ide_setup_ports(hwif, base, gayle_offsets, irqport, ack_intr);
 #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 */
-	    hwif->irq = IRQ_AMIGA_PORTS;
-	    return 1;
+	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 */
     }
-    return 0;
 }
diff -urN linux-2.2.20-pristine/drivers/block/genhd.c linux-2.2.20/drivers/block/genhd.c
--- linux-2.2.20-pristine/drivers/block/genhd.c	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/genhd.c	Mon Nov 26 13:14:22 2001
@@ -128,6 +128,14 @@
 	 * MD devices are named md0, md1, ... md15, fix it up here.
 	 */
 	switch (hd->major) {
+		case IDE9_MAJOR:
+			unit += 2;
+		case IDE8_MAJOR:
+			unit += 2;
+		case IDE7_MAJOR:
+			unit += 2;
+		case IDE6_MAJOR:
+			unit += 2;
 		case IDE5_MAJOR:
 			unit += 2;
 		case IDE4_MAJOR:
@@ -311,7 +319,7 @@
 				     first_sector + first_size))
 				continue;
 
-			add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, 
+			add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size,
 				      NR_SECTS(p)*sector_size, ptype(SYS_IND(p)));
 			current_minor++;
 			if ((current_minor & mask) == 0)
@@ -340,10 +348,11 @@
 			first_sector + START_SECT(p) * sector_size;
 		this_sector = first_sector + START_SECT(p) * sector_size;
 		dev = MKDEV(hd->major, current_minor);
-		brelse(bh);
+		/* Use bforget(), as we have changed the disk geometry */
+		bforget(bh);	/* brelse(bh); */
 	}
 done:
-	brelse(bh);
+	bforget(bh);	/* brelse(bh); */
 }
 
 #ifdef CONFIG_SOLARIS_X86_PARTITION
@@ -463,7 +472,9 @@
 		if (p->p_fstype != BSD_FS_UNUSED) 
 			check_and_add_bsd_partition(hd, p, dev);
 	}
-	brelse(bh);
+
+	/* Use bforget(), as we have changed the disk setup */
+	bforget(bh);	/* brelse(bh); */
 
 }
 #endif
@@ -502,7 +513,8 @@
 		}
 		p++;
 	}
-	brelse(bh);
+	/* Use bforget, as we have changed the disk setup */
+	bforget(bh);	/* brelse(bh); */
 	printk(" >");
 }
 #endif
@@ -547,7 +559,9 @@
 		}
 		printk(" >");
 	}
-	brelse(bh);
+
+	/* Use bforget, as we have changed the disk setup */
+	bforget(bh);	/* brelse(bh); */
 }
 #endif /* CONFIG_MINIX_SUBPARTITION */
  
@@ -591,8 +605,9 @@
 #ifdef CONFIG_BLK_DEV_IDE
 check_table:
 #endif
+	/* Use bforget(), because we have potentially changed the disk geometry */
 	if (!(msdos_magic_present(data + 510))) {
-		brelse(bh);
+		bforget(bh);	/* brelse(bh); */
 		return 0;
 	}
 	p = (struct partition *) (data + 0x1be);
@@ -602,8 +617,26 @@
 		/*
 		 * Look for various forms of IDE disk geometry translation
 		 */
-		extern int ide_xlate_1024(kdev_t, int, const char *);
+		extern int ide_xlate_1024(kdev_t, int, int, const char *);
 		unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
+		int heads = 0;
+
+		/*
+		 * The i386 partition handling programs very often
+		 * make partitions end on cylinder boundaries.
+		 * There is no need to do so, and Linux fdisk doesnt always
+		 * do this, and Windows NT on Alpha doesnt do this either,
+		 * but still, this helps to guess #heads.
+		 */
+		for (i = 0; i < 4; i++) {
+			struct partition *q = &p[i];
+			if (NR_SECTS(q)) {
+				if ((q->sector & 63) == 1 &&
+				    (q->end_sector & 63) == 63)
+					heads = q->end_head + 1;
+				break;
+			}
+		}
 		if (SYS_IND(p) == EZD_PARTITION) {
 			/*
 			 * The remainder of the disk must be accessed using
@@ -613,7 +646,7 @@
 			 * ide_xlate_1024() will take care of the necessary
 			 * adjustments to fool fdisk/LILO and partition check.
 			 */
-			if (ide_xlate_1024(dev, -1, " [EZD]")) {
+			if (ide_xlate_1024(dev, -1, heads, " [EZD]")) {
 				data += 512;
 				goto check_table;
 			}
@@ -629,7 +662,7 @@
 			 * ide_xlate_1024() will take care of the necessary
 			 * adjustments to fool fdisk/LILO and partition check.
 			 */
-			if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
+			if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) {
 				brelse(bh);
 				goto read_mbr;	/* start over with new MBR */
 			}
@@ -637,32 +670,15 @@
 			   *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) &&
 			   (1 & *(unsigned char *)(data + sig + 2))) {
 			/* DM6 signature in MBR, courtesy of OnTrack */
-			(void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
-		} else if (SYS_IND(p) == DM6_AUX1PARTITION || SYS_IND(p) == DM6_AUX3PARTITION) {
+			(void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
+		} else if (SYS_IND(p) == DM6_AUX1PARTITION ||
+			   SYS_IND(p) == DM6_AUX3PARTITION) {
 			/*
 			 * DM6 on other than the first (boot) drive
 			 */
-			(void) ide_xlate_1024(dev, 0, " [DM6:AUX]");
+			(void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
 		} else {
-			/*
-			 * Examine the partition table for common translations.
-			 * This is useful for drives in situations where the
-			 * translated geometry is unavailable from the BIOS.
-			 */
-			for (i = 0; i < 4; i++) {
-				struct partition *q = &p[i];
-				if (NR_SECTS(q)
-				   && (q->sector & 63) == 1
-				   && (q->end_sector & 63) == 63) {
-					unsigned int heads = q->end_head + 1;
-					if (heads == 32 || heads == 64 ||
-					    heads == 128 || heads == 240 ||
-					    heads == 255) {
-						(void) ide_xlate_1024(dev, heads, " [PTBL]");
-						break;
-					}
-				}
-			}
+			(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
 		}
 	}
 #endif	/* CONFIG_BLK_DEV_IDE */
@@ -779,7 +795,7 @@
 		}
 	}
 	printk("\n");
-	brelse(bh);
+	bforget(bh);	/* brelse(bh); */
 	return 1;
 }
 
diff -urN linux-2.2.20-pristine/drivers/block/hd.c linux-2.2.20/drivers/block/hd.c
--- linux-2.2.20-pristine/drivers/block/hd.c	Sun Mar 25 08:37:30 2001
+++ linux-2.2.20/drivers/block/hd.c	Mon Nov 26 13:14:22 2001
@@ -746,7 +746,7 @@
 
 		
 	*/
-                spin_lock_irqsave(&rtc_lock, flags);
+		spin_lock_irqsave(&rtc_lock, flags);
 		cmos_disks = CMOS_READ(0x12);
 		spin_unlock_irqrestore(&rtc_lock, flags);
 
diff -urN linux-2.2.20-pristine/drivers/block/hpt34x.c linux-2.2.20/drivers/block/hpt34x.c
--- linux-2.2.20-pristine/drivers/block/hpt34x.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/hpt34x.c	Mon Nov 26 13:14:23 2001
@@ -0,0 +1,432 @@
+/*
+ * linux/drivers/ide/hpt34x.c		Version 0.29	Feb. 10, 2000
+ *
+ * Copyright (C) 1998-2000	Andre Hedrick (andre@suse.com)
+ * 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		1
+
+#define 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, int);
+extern int (*hpt34x_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	char *p = buffer;
+	u32 bibma = bmide_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	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(virt_to_bus(hwif->dmatable), 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 */
+			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 = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	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 (dev->rom_address) {
+			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
+		}
+		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->base_address[0] = (hpt34xIoBase + 0x20);
+	dev->base_address[1] = (hpt34xIoBase + 0x34);
+	dev->base_address[2] = (hpt34xIoBase + 0x28);
+	dev->base_address[3] = (hpt34xIoBase + 0x3c);
+	for(i=0; i<4; i++)
+		dev->base_address[i] |= 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->base_address[0]);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]);
+	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);
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 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 -urN linux-2.2.20-pristine/drivers/block/hpt366.c linux-2.2.20/drivers/block/hpt366.c
--- linux-2.2.20-pristine/drivers/block/hpt366.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/hpt366.c	Tue Nov 27 13:37:11 2001
@@ -0,0 +1,1229 @@
+/*
+ * 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/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 short iobase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+		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->rom_address)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | 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;
+		}
+		hwif->autodma = 1;
+	} 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 -urN linux-2.2.20-pristine/drivers/block/hptraid.c linux-2.2.20/drivers/block/hptraid.c
--- linux-2.2.20-pristine/drivers/block/hptraid.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/hptraid.c	Tue Nov 27 00:00:27 2001
@@ -0,0 +1,437 @@
+/*
+   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;
+		}
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			return -EINVAL;
+	};
+
+	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);
+                                                                	
+	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 -urN linux-2.2.20-pristine/drivers/block/hptraid.h linux-2.2.20/drivers/block/hptraid.h
--- linux-2.2.20-pristine/drivers/block/hptraid.h	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/hptraid.h	Tue Nov 27 00:00:27 2001
@@ -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 -urN linux-2.2.20-pristine/drivers/block/ht6560b.c linux-2.2.20/drivers/block/ht6560b.c
--- linux-2.2.20-pristine/drivers/block/ht6560b.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ht6560b.c	Mon Nov 26 13:14:23 2001
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/ht6580.c       Version 0.04  Mar 19, 1996
+ *  linux/drivers/block/ht6560b.c      Version 0.07  Feb  1, 2000
  *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
  */
 
 /*
@@ -12,42 +12,31 @@
  *
  *  Version 0.03        Some cleanups
  *
- * 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.
+ *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
  *
- * 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]
+ *  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.
  *
- * 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.
- *
- * Port 0x3e6 bit 0x20 sets these timings on/off. If 0x20 bit is set
- * these timings are disabled.
+ *  Version 0.07        Trying to fix CD-ROM detection problem.
+ *                      "Prefetch" mode bit OFF for ide disks and
+ *                      ON for anything else.
  *
- * Mikko Ala-Fossi
  *
- * More notes:
+ *  HT-6560B EIDE-controller support
+ *  To activate controller support use kernel parameter "ide0=ht6560b".
+ *  Use hdparm utility to enable PIO mode support.
  *
- * There's something still missing from the initialization code, though.
- * If I have booted to dos sometime after power on, I can get smaller
- * timing values working. Perhaps I could soft-ice the initialization.
+ *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
+ *             Jan Evert van Grootheest   <janevert@iae.nl>
  *
- * -=- malafoss@snakemail.hut.fi -=- searching the marvels of universe -=-
+ *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
  */
 
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -57,179 +46,297 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
-/*
- * 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 stuff is courtesy of malafoss@snakemail.hut.fi
- *                          (or maf@nemesis.tky.hut.fi)
- *
- * At least one user has reported that this code can confuse the floppy
- * controller and/or driver -- perhaps this should be changed to use
- * a read-modify-write sequence, so as not to disturb other bits in the reg?
- */
+/* #define DEBUG */  /* remove comments for DEBUG messages */
 
 /*
- * The special i/o-port that HT-6560B uses to select interfaces:
+ * 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_SELECT_PORT     0x3e6
-
+#define HT_CONFIG_PORT	  0x3e6
+#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
 /*
- * We don't know what all of the bits are for, but we *do* know about these:
- *	bit5 (0x20): "1" selects slower speed by disabling use of timing values
- *	bit0 (0x01): "1" selects second interface
+ * FIFO + PREFETCH (both a/b-model)
  */
-static byte ht6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}};
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF	  0x01
+#define HT_PREFETCH_MODE  0x20
 
 /*
- * VLB ht6560b Timing values:
+ * 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 Time  (rt)
- *           The valid values range from 2 to 15. The default is 15.
+ *	High nibble:  Recovery Cycle Time  (rt)
+ *	     The valid values range from 2 to 15. The default is 15.
  *
- *      Low nibble:   Active Time    (at)
- *           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.
- *
- * Here's an example to make it clearer:
- *
- * DOS:    DEVICE=C:\bin\HTIDE\HTIDE.SYS /D0=2,4 /D1=4,5 /D2=10,10 /D3=15,15
- * Linux:  byte ht6560b_timings [][] = {{0x24, 0x45}, {0xaa, 0xff}};
- *
- * Note: There are no ioctls to change these values directly,
- * but settings can be approximated as PIO modes, using "hdparm":
- *
- * rc.local:  hdparm -p3 /dev/hda -p2 /dev/hdb -p1 /dev/hdc -p0 /dev/hdd
  */
+#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
 
-static byte ht6560b_timings [2][MAX_DRIVES] = {{0xff,0xff}, {0xff,0xff}};
-
-static byte pio_to_timings[6] = {0xff, 0xaa, 0x45, 0x24, 0x13, 0x12};
+/*
+ * 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)
 {
-	byte t;
 	unsigned long flags;
 	static byte current_select = 0;
 	static byte current_timing = 0;
-	byte select = ht6560b_selects[HWIF(drive)->index][drive->select.b.unit];
-        byte timing = ht6560b_timings[HWIF(drive)->index][drive->select.b.unit];
 
+	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;
-		__save_flags (flags);	/* local CPU only */
-		__cli();		/* local CPU only */
-		(void) inb(HT_SELECT_PORT);
-		(void) inb(HT_SELECT_PORT);
-		(void) inb(HT_SELECT_PORT);
+		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);
 		/*
-		 * Note: input bits are reversed to output bits!!
+		 * Set timing for this drive:
 		 */
-		t = inb(HT_SELECT_PORT) ^ 0x3f;
-		t &= (~0x21);
-		t |= (current_select & 0x21);
-		outb(t, HT_SELECT_PORT);
-                /*
-                 * Set timing for this drive:
-                 */
-                outb (timing, IDE_SELECT_REG);
-                (void) inb (IDE_STATUS_REG);
-		__restore_flags (flags);	/* local CPU only */
+		outb(timing, IDE_SELECT_REG);
+		(void) inb(IDE_STATUS_REG);
 #ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing);
+		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
 #endif
 	}
+	__restore_flags (flags);	/* local CPU only */
 }
 
 /*
  * Autodetection and initialization of ht6560b
  */
-int try_to_init_ht6560b(void)
+static int __init try_to_init_ht6560b(void)
 {
 	byte orig_value;
 	int i;
-
+	
 	/* Autodetect ht6560b */
-	if ((orig_value=inb(HT_SELECT_PORT)) == 0xff)
+	if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
 		return 0;
-
+	
 	for (i=3;i>0;i--) {
-		outb(0x00, HT_SELECT_PORT);
-		if (!( (~inb(HT_SELECT_PORT)) & 0x3f )) {
-			  outb(orig_value, HT_SELECT_PORT);
-			  return 0;
+		outb(0x00, HT_CONFIG_PORT);
+		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+			outb(orig_value, HT_CONFIG_PORT);
+			return 0;
 		}
 	}
-	outb(0x00, HT_SELECT_PORT);
-	if ((~inb(HT_SELECT_PORT))& 0x3f) {
-		outb(orig_value, HT_SELECT_PORT);
+	outb(0x00, HT_CONFIG_PORT);
+	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+		outb(orig_value, HT_CONFIG_PORT);
 		return 0;
 	}
 	/*
-	 * Ht6560b autodetected:
-	 *     reverse input bits to output bits
-	 *     initialize bit1 to 0
+	 * Ht6560b autodetected
 	 */
-	outb((orig_value ^ 0x3f) & 0xfd, HT_SELECT_PORT);
-
-	printk("\nht6560b: detected and initialized");
+	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 void tune_ht6560b (ide_drive_t *drive, byte pio)
+static byte ht_pio2timings(ide_drive_t *drive, byte pio)
 {
-	unsigned int hwif, unit;
+	int bus_speed, active_time, recovery_time;
+	int active_cycles, recovery_cycles;
+	ide_pio_data_t d;
+	
+        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.
+		 */
+		bus_speed = system_bus_clock();
+		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 */
+	}
+}
 
-	if (pio == 255)  {	/* auto-tune */
-		if (drive->media != ide_disk)
-			pio = 0; /* some CDROMs don't like fast modes (?) */
-		else
-			pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	}
-	unit = drive->select.b.unit;
-	hwif = HWIF(drive)->index;
-	ht6560b_timings[hwif][unit] = pio_to_timings[pio];
-	if (pio == 0)
-		ht6560b_selects[hwif][unit] |= 0x20;
-	else
-		ht6560b_selects[hwif][unit] &= ~0x20;
+/*
+ *  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_ht6560b (void)
+void __init init_ht6560b (void)
 {
-	if (check_region(HT_SELECT_PORT,1)) {
-		printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n");
+	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_SELECT_PORT, 1, ide_hwifs[0].name);
+			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;
-			ide_hwifs[1].serialized = 1;
+			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("\nht6560b: not found\n");
+			printk(KERN_ERR "ht6560b: not found\n");
 	}
 }
diff -urN linux-2.2.20-pristine/drivers/block/ide-adma.c linux-2.2.20/drivers/block/ide-adma.c
--- linux-2.2.20-pristine/drivers/block/ide-adma.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/ide-adma.c	Mon Nov 26 23:47:41 2001
@@ -0,0 +1,9 @@
+/*
+ *  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 -urN linux-2.2.20-pristine/drivers/block/ide-cd.c linux-2.2.20/drivers/block/ide-cd.c
--- linux-2.2.20-pristine/drivers/block/ide-cd.c	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/ide-cd.c	Tue Nov 27 11:53:22 2001
@@ -131,7 +131,7 @@
  * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
  *                        from Ben Galliart <bgallia@luc.edu> with 
  *                        special help from Jeff Lightfoot 
- *                        <jeffml@pobox.com>
+ *                        <jeffml@netcom.com>
  * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
  * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
  * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
@@ -299,6 +299,7 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -306,7 +307,6 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include "ide.h"
 #include "ide-cd.h"
 
 /****************************************************************************
@@ -2392,7 +2392,13 @@
         else 	
         	printk (" drive");
 
-	printk (", %dkB Cache\n", 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);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	printk("\n");
 
 	return nslots;
 }
@@ -2617,6 +2623,8 @@
 	return 0;
 }
 
+int ide_cdrom_reinit (ide_drive_t *drive);
+
 static ide_driver_t ide_cdrom_driver = {
 	"ide-cdrom",			/* name */
 	IDECD_VERSION,			/* version */
@@ -2625,16 +2633,20 @@
 	1,				/* supports_dma */
 	1,				/* supports_dsc_overlap */
 	ide_cdrom_cleanup,		/* cleanup */
+	NULL,				/* standby */
+	NULL,				/* flushcache */
 	ide_do_rw_cdrom,		/* do_request */
 	NULL,				/* ??? or perhaps cdrom_end_request? */
 	ide_cdrom_ioctl,		/* ioctl */
 	ide_cdrom_open,			/* open */
 	ide_cdrom_release,		/* release */
 	ide_cdrom_check_media_change,	/* media_change */
+	NULL,				/* ide_cdrom_revalidate revalidate */
 	NULL,				/* pre_reset */
 	ide_cdrom_capacity,		/* capacity */
 	NULL,				/* special */
-	NULL				/* proc */
+	NULL,				/* proc */
+	ide_cdrom_reinit,		/* reinit */
 };
 
 int ide_cdrom_init(void);
@@ -2648,6 +2660,39 @@
 /* options */
 char *ignore = NULL;
 
+int ide_cdrom_reinit (ide_drive_t *drive)
+{
+	struct cdrom_info *info;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+	if (info == NULL) {
+		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		return 1;
+	}
+	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+		kfree (info);
+		return 1;
+	}
+	memset (info, 0, sizeof (struct cdrom_info));
+	drive->driver_data = info;
+	DRIVER(drive)->busy++;
+	if (ide_cdrom_setup (drive)) {
+		DRIVER(drive)->busy--;
+		if (ide_cdrom_cleanup (drive))
+			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 #ifdef MODULE
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
@@ -2686,6 +2731,10 @@
 				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);
+			continue;
 		}
 		info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 		if (info == NULL) {
diff -urN linux-2.2.20-pristine/drivers/block/ide-disk.c linux-2.2.20/drivers/block/ide-disk.c
--- linux-2.2.20-pristine/drivers/block/ide-disk.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ide-disk.c	Wed Nov 28 00:34:01 2001
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-disk.c	Version 1.08  Dec   10, 1998
+ *  linux/drivers/block/ide-disk.c	Version 1.09  April 23, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -25,12 +25,16 @@
  *			process of adding new ATA4 compliance.
  *			fixed problems in allowing fdisk to see
  *			the entire disk.
+ * Version 1.09		added increment of rq->sector in ide_multwrite
+ *			added UDMA 3/4 reporting
  */
 
-#define IDEDISK_VERSION	"1.08"
+#define IDEDISK_VERSION	"1.09"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
+#define _IDE_DISK_C		/* Tell linux/hdsmart.h it's really us */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -43,22 +47,37 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/blkdev.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/ide.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
 
-#include "ide.h"
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  define __TASKFILE__IO
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifndef __TASKFILE__IO
 
 static void idedisk_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
 
 	while (wcount--) {
-		*p++ = *p << 8 | *p >> 8;
-		*p++ = *p << 8 | *p >> 8;
+		*p = *p << 8 | *p >> 8; p++;
+		*p = *p << 8 | *p >> 8; p++;
 	}
 }
 
@@ -79,17 +98,26 @@
 		ide_output_data(drive, buffer, wcount);
 }
 
+#endif /* __TASKFILE__IO */
+
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
  *
  * Returns:	1 if lba_capacity looks sensible
  *		0 otherwise
+ *
+ * It is called only once for each drive.
  */
 static int lba_capacity_is_ok (struct hd_driveid *id)
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+		printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+		return 1;
+	}
+
 	/*
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
@@ -106,7 +134,7 @@
 	lba_sects   = id->lba_capacity;
 	chs_sects   = id->cyls * id->heads * id->sectors;
 
-	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
+	/* perform a rough sanity check on lba_sects:  within 10% is OK */
 	if ((lba_sects - chs_sects) < chs_sects/10)
 		return 1;
 
@@ -122,6 +150,8 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
+#ifndef __TASKFILE__IO
+
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
@@ -131,11 +161,8 @@
 	int i;
 	unsigned int msect, nsect;
 	struct request *rq;
-#if 0
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		return ide_error(drive, "read_intr", stat);
-	}
-#else	/* new way for dealing with premature shared PCI interrupts */
+
+	/* new way for dealing with premature shared PCI interrupts */
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			return ide_error(drive, "read_intr", stat);
@@ -144,7 +171,6 @@
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
-#endif
 	msect = drive->mult_count;
 	
 read_next:
@@ -214,6 +240,7 @@
 	return ide_error(drive, "write_intr", stat);
 }
 
+#if 0
 /*
  * ide_multwrite() transfers a block of up to mcount sectors of data
  * to a drive as part of a disk multiple-sector write operation.
@@ -250,13 +277,14 @@
 			nsect, rq->nr_sectors - nsect);
 #endif
 		spin_lock_irqsave(&io_request_lock, flags);	/* Is this really necessary? */
-		
+#ifdef CONFIG_BLK_DEV_PDC4030
+		rq->sector += nsect;
+#endif		
 		/*
 		 *	Completed ?
 		 */
 		 
-		if (((long)(rq->nr_sectors -= nsect)) <= 0)
-		{
+		if (((long)(rq->nr_sectors -= nsect)) <= 0) {
 			spin_unlock_irqrestore(&io_request_lock, flags);
 			break;
 		}
@@ -292,6 +320,61 @@
 	} while (mcount);
 	return 0;
 }
+#else
+/*
+ * ide_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+ 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
+ 	struct request	*rq = &hwgroup->wrq;
+ 
+  	do {
+  		char *buffer;
+  		int nsect = rq->current_nr_sectors;
+ 
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+		buffer = rq->buffer;
+
+		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+		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->buffer             = bh->b_data;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		idedisk_output_data(drive, buffer, nsect<<7);
+	} while (mcount);
+
+        return 0;
+}
+#endif
 
 /*
  * multwrite_intr() is the handler for disk multwrite interrupts
@@ -333,48 +416,217 @@
 	}
 	return ide_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);
 
 /*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ * 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 set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat = GET_STAT();
+	if (rq->cmd == READ)
+		goto good_command;
+	if (rq->cmd == WRITE)
+		goto good_command;
 
-	if (OK_STAT(stat,READY_STAT,BAD_STAT)) {
-		drive->mult_count = drive->mult_req;
-	} else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
-	}
+	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);
 }
 
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
 {
-	byte stat = GET_STAT();
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
-	return ide_stopped;
+#if 1
+	lba48bit = drive->addressing;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
+
+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);
 }
 
 /*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
  */
-static ide_startstop_t recal_intr (ide_drive_t *drive)
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
 {
-	byte stat = GET_STAT();
+	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;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
-	return ide_stopped;
+#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);
 }
 
+#else /* !__TASKFILE__IO */
 /*
  * do_rw_disk() issues READ and WRITE commands to a disk,
  * using LBA if supported, or CHS otherwise, to address sectors.
@@ -382,32 +634,72 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-#ifdef CONFIG_BLK_DEV_PDC4030
-	ide_hwif_t *hwif = HWIF(drive);
-	int use_pdc4030_io = 0;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
 
-	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		if (hwif->channel != 0 || rq->cmd == READ) {
-			use_pdc4030_io = 1;
-		}
-	}
-	if (drive->select.b.lba || use_pdc4030_io) {
+	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)) {
+			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[4] = (task_ioreg_t) block;
+			tasklets[5] = (task_ioreg_t) (block>>8);
+			tasklets[6] = (task_ioreg_t) (block>>16);
+			tasklets[7] = (task_ioreg_t) (block>>24);
+			tasklets[8] = (task_ioreg_t) 0;
+			tasklets[9] = (task_ioreg_t) 0;
+//			tasklets[8] = (task_ioreg_t) (block>>32);
+//			tasklets[9] = (task_ioreg_t) (block>>40);
 #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
-		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);
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+				drive->name,
+				(rq->cmd==READ)?"read":"writ",
+				block,
+				rq->nr_sectors,
+				(unsigned long) rq->buffer,
+				block);
+			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+				drive->name, tasklets[3], tasklets[2],
+				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);
+		} else {
+#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
+			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);
+		}
 	} else {
 		unsigned int sect,head,cyl,track;
 		track = block / drive->sect;
@@ -415,6 +707,9 @@
 		OUT_BYTE(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);
@@ -425,7 +720,7 @@
 #endif
 	}
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (use_pdc4030_io) {
+	if (IS_PDC4030_DRIVE) {
 		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
 		return do_pdc4030_io (drive, rq);
 	}
@@ -436,7 +731,11 @@
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		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);
+		}
 		return ide_started;
 	}
 	if (rq->cmd == WRITE) {
@@ -445,7 +744,11 @@
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		if ((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,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
@@ -455,17 +758,17 @@
 			__cli();	/* local CPU only */
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-			/*
-			 * Ugh.. this part looks ugly because we MUST set up
-			 * the interrupt handler before outputting the first block
-			 * of data to be written.  If we hit an error (corrupted buffer list)
-			 * in ide_multwrite(), then we need to remove the handler/timer
-			 * before returning.  Fortunately, this NEVER happens (right?).
-			 *
-			 * Except when you get an error it seems...
-			 */
+	/*
+	 * Ugh.. this part looks ugly because we MUST set up
+	 * the interrupt handler before outputting the first block
+	 * of data to be written.  If we hit an error (corrupted buffer list)
+	 * in ide_multwrite(), then we need to remove the handler/timer
+	 * before returning.  Fortunately, this NEVER happens (right?).
+	 *
+	 * Except when you get an error it seems...
+	 */
 			hwgroup->wrq = *rq; /* scratchpad */
-			ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 			if (ide_multwrite(drive, drive->mult_count)) {
 				unsigned long flags;
 				spin_lock_irqsave(&io_request_lock, flags);
@@ -485,29 +788,47 @@
 	return ide_stopped;
 }
 
+#endif /* __TASKFILE__IO */
+
 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;
 		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_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
 }
 
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+		taskfile.command = WIN_DOORUNLOCK;
 		invalidate_buffers(inode->i_rdev);
-		if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
@@ -516,24 +837,248 @@
 	return drive->removable;	/* if removable, always assume it was changed */
 }
 
+#if 0
+static void idedisk_revalidate (ide_drive_t *drive)
+{
+	grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
+			1<<PARTN_BITS,
+			current_capacity(drive));
+}
+#endif
+
 /*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
  */
-static unsigned long idedisk_capacity (ide_drive_t  *drive)
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long addr = 0;
+
+	if (!(drive->id->command_set_1 & 0x0400) &&
+	    !(drive->id->cfs_enable_2 & 0x0100))
+		return addr;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+	args.handler				= task_no_data_intr;
+
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long long addr = 0;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+	args.handler				= task_no_data_intr;
+
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr = ((__u64)high << 24) | low;
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+	ide_task_t args;
+	unsigned long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+	args.handler				= task_no_data_intr;
+
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, read new maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr_set++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+	ide_task_t args;
+	unsigned long long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+        args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr_set = ((__u64)high << 24) | low;
+	}
+	return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+	printk("%s: host protected area => %d\n", drive->name, flag);
+	return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
+ */
+static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
+	unsigned long set_max = idedisk_read_native_max_address(drive);
+	unsigned long long capacity_2 = capacity;
+	unsigned long long set_max_ext;
 
+	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
+
+	if (id->cfs_enable_2 & 0x0400) {
+		capacity_2 = id->lba_capacity_2;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->head		= drive->bios_head = 255;
+		drive->sect		= drive->bios_sect = 63;
+		drive->select.b.lba	= 1;
+#if 1
+		set_max_ext = idedisk_read_native_max_address_ext(drive);
+		if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+			set_max_ext = idedisk_read_native_max_address_ext(drive);
+			set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+			if (set_max_ext) {
+				drive->capacity48 = capacity_2 = set_max_ext;
+				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+				drive->select.b.lba = 1;
+				drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+				drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+		}
+#endif
+		drive->bios_cyl		= drive->cyl;
+		drive->capacity48	= capacity_2;
+		drive->capacity		= (unsigned long) capacity_2;
+		return;
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
-		if (id->lba_capacity >= capacity) {
-			capacity = id->lba_capacity;
+	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+		capacity = id->lba_capacity;
+		drive->cyl = capacity / (drive->head * drive->sect);
+		drive->select.b.lba = 1;
+	}
+
+	if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+		set_max = idedisk_read_native_max_address(drive);
+		set_max = idedisk_set_max_address(drive, set_max);
+		if (set_max) {
+			drive->capacity = capacity = set_max;
+			drive->cyl = set_max / (drive->head * drive->sect);
 			drive->select.b.lba = 1;
+			drive->id->lba_capacity = capacity;
 		}
+#else /* !CONFIG_IDEDISK_STROKE */
+		printk("%s: setmax LBA %lu, native  %lu\n",
+			drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
 	}
-	return (capacity - drive->sect0);
+
+	drive->capacity = capacity;
+
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+                drive->capacity48 = id->lba_capacity_2;
+		drive->head = 255;
+		drive->sect = 63;
+		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+	}
+}
+
+static unsigned long idedisk_capacity (ide_drive_t  *drive)
+{
+	if (drive->id->cfs_enable_2 & 0x0400)
+		return (drive->capacity48 - drive->sect0);
+	return (drive->capacity - drive->sect0);
 }
 
 static ide_startstop_t idedisk_special (ide_drive_t *drive)
@@ -541,23 +1086,46 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		s->b.set_geometry = 0;
-		OUT_BYTE(drive->sect,IDE_SECTOR_REG);
-		OUT_BYTE(drive->cyl,IDE_LCYL_REG);
-		OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		ide_handler_t *handler = NULL;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+		s->b.set_geometry	= 0;
+		taskfile.sector_number	= drive->sect;
+		taskfile.low_cylinder	= drive->cyl;
+		taskfile.high_cylinder	= drive->cyl>>8;
+		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
+		if (!IS_PDC4030_DRIVE) {
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_SPECIFY;
+			handler			= ide_handler_parser(&taskfile, &hobfile);
+		}
+		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_RESTORE;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->mult_req;
+			taskfile.command	= WIN_SETMULT;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->all) {
 		int special = s->all;
 		s->all = 0;
@@ -569,9 +1137,11 @@
 
 static void idedisk_pre_reset (ide_drive_t *drive)
 {
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
 	drive->special.all = 0;
-	drive->special.b.set_geometry = 1;
-	drive->special.b.recalibrate  = 1;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
 	if (OK_TO_RESET_CONTROLLER)
 		drive->mult_count = 0;
 	if (!drive->keep_settings && !drive->using_dma)
@@ -584,19 +1154,45 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_ENABLE;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_VALUES;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_THRESHOLDS;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -620,7 +1216,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_thresholds(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -639,7 +1235,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_values(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -667,87 +1263,145 @@
 
 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)
 		return -EBUSY;
 	ide_init_drive_cmd (&rq);
+	rq.cmd = IDE_DRIVE_CMD;
 	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;
 }
 
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
-	unsigned long flags;
-
-	if (ide_spin_wait_hwgroup(drive, &flags))
+	if (ide_spin_wait_hwgroup(drive))
 		return -EBUSY;
 	drive->nowerr = arg;
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irq(&io_request_lock);
+	return 0;
+}
+
+static int write_cache (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	taskfile.command	= WIN_SETFEATURES;
+
+	if (!(drive->id->cfs_enable_2 & 0x3000))
+		return 1;
+
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->wcache = arg;
+	return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.command	= WIN_STANDBYNOW1;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	if (drive->id->cfs_enable_2 & 0x2400) {
+		taskfile.command	= WIN_FLUSH_CACHE_EXT;
+	} else {
+		taskfile.command	= WIN_FLUSH_CACHE;
+	}
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+	taskfile.sector_count	= arg;
+
+	taskfile.command	= WIN_SETFEATURES;
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->acoustic = arg;
+	return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+	drive->addressing =  0;
+
+	if (!(drive->id->cfs_enable_2 & 0x0400))
+		return -EIO;
+
+	drive->addressing = arg;
 	return 0;
 }
 
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+	return (probe_lba_addressing(drive, arg));
+}
+
 static void idedisk_add_settings(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_SHORT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,     set_lba_addressing);
+
 	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
-	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	2,	&drive->mult_count,		set_multcount);
+	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
 	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	1,	&read_ahead[major],		NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	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 subdriver functions, registered with ide.c
- */
-static ide_driver_t idedisk_driver = {
-	"ide-disk",		/* name */
-	IDEDISK_VERSION,	/* version */
-	ide_disk,		/* media */
-	0,			/* busy */
-	1,			/* supports_dma */
-	0,			/* supports_dsc_overlap */
-	NULL,			/* cleanup */
-	do_rw_disk,		/* do_request */
-	NULL,			/* end_request */
-	NULL,			/* ioctl */
-	idedisk_open,		/* open */
-	idedisk_release,	/* release */
-	idedisk_media_change,	/* media_change */
-	idedisk_pre_reset,	/* pre_reset */
-	idedisk_capacity,	/* capacity */
-	idedisk_special,	/* special */
-	idedisk_proc		/* proc */
-};
-
-int idedisk_init (void);
-static ide_module_t idedisk_module = {
-	IDE_DRIVER_MODULE,
-	idedisk_init,
-	&idedisk_driver,
-	NULL
-};
-
-static int idedisk_cleanup (ide_drive_t *drive)
-{
-	return ide_unregister_subdriver(drive);
+	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	1,	&max_sectors[major][minor],	NULL);
+	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
+	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
+	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	128,	254,				1,	1,	&drive->acoustic,		set_acoustic);
+	ide_add_setting(drive,  "failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
+	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
 static void idedisk_setup (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
-	unsigned long capacity, check;
+	unsigned long capacity;
 	
 	idedisk_add_settings(drive);
 
@@ -766,106 +1420,160 @@
 			drive->doorlocking = 1;
 		}
 	}
+#if 0
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		ide_hwif_t *hwif = HWIF(drive);
 
+		if (drive != &hwif->drives[i]) continue;
+		hwif->gd->de_arr[i] = drive->de;
+		if (drive->removable)
+			hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
+		break;
+	}
+#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;
 		drive->head    = drive->bios_head = id->heads;
 		drive->sect    = drive->bios_sect = id->sectors;
 	}
+
 	/* Handle logical geometry translation by the drive */
 	if ((id->field_valid & 1) && id->cur_cyls &&
 	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
-		/*
-		 * Extract the physical drive geometry for our use.
-		 * Note that we purposely do *not* update the bios info.
-		 * This way, programs that use it (like fdisk) will
-		 * still have the same logical view as the BIOS does,
-		 * which keeps the partition table from being screwed.
-		 *
-		 * An exception to this is the cylinder count,
-		 * which we reexamine later on to correct for 1024 limitations.
-		 */
 		drive->cyl  = id->cur_cyls;
 		drive->head = id->cur_heads;
 		drive->sect = id->cur_sectors;
-
-		/* check for word-swapped "capacity" field in id information */
-		capacity = drive->cyl * drive->head * drive->sect;
-		check = (id->cur_capacity0 << 16) | id->cur_capacity1;
-		if (check == capacity) {	/* was it swapped? */
-			/* yes, bring it into little-endian order: */
-			id->cur_capacity0 = (capacity >>  0) & 0xffff;
-			id->cur_capacity1 = (capacity >> 16) & 0xffff;
-		}
 	}
+
 	/* Use physical geometry if what we have still makes no sense */
-	if ((!drive->head || drive->head > 16) &&
-	    id->heads && id->heads <= 16) {
+	if (drive->head > 16 && id->heads && id->heads <= 16) {
 		drive->cyl  = id->cyls;
 		drive->head = id->heads;
 		drive->sect = id->sectors;
 	}
 
 	/* calculate drive capacity, and select LBA if possible */
-	capacity = idedisk_capacity (drive);
+	init_idedisk_capacity (drive);
 
 	/*
 	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
-	if (!drive->forced_geom &&
-	    capacity > drive->bios_cyl * drive->bios_sect * drive->bios_head) {
-		unsigned long cylsize;
-		cylsize = drive->bios_sect * drive->bios_head;
-		if (cylsize == 0 || capacity/cylsize > 65535) {
-			drive->bios_sect = 63;
-			drive->bios_head = 255;
-			cylsize = 63*255;
-		}
-		if (capacity/cylsize > 65535)
-			drive->bios_cyl = 65535;
-		else
-			drive->bios_cyl = capacity/cylsize;
-	}
-
-#if 0	/* done instead for entire identify block in arch/ide.h stuff */
-	/* fix byte-ordering of buffer size field */
-	id->buf_size = le16_to_cpu(id->buf_size);
-#endif
-	printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
-			drive->name, id->model,
-			capacity/2048L, id->buf_size/2,
-			drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
-	if (drive->using_dma) {
-		if ((id->field_valid & 4) &&
-		    (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-			printk(", UDMA");       /* UDMA BIOS-enabled! */
-		} else if (id->field_valid & 4) {
-			printk(", (U)DMA");	/* Can be BIOS-enabled! */
-		} else {
-			printk(", DMA");
-		}
-	}
+	capacity = idedisk_capacity (drive);
+	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
+	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
+		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
+
+	/* Give size in megabytes (MB), not mebibytes (MiB). */
+	/* We compute the exact rounded value, avoiding overflow. */
+	printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
+
+        /* Only print cache size when it was specified */
+	if (id->buf_size)
+		printk (" w/%dKiB Cache", id->buf_size/2);
+
+	printk(", CHS=%d/%d/%d",
+		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);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
-#if 1	/* original, pre IDE-NFG, per request of AC */
+#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;
-#else
-		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;
 #endif
 	}
 	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)
+{
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
+	return ide_unregister_subdriver(drive);
+}
+
+int idedisk_reinit(ide_drive_t *drive);
+
+/*
+ *	IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idedisk_driver = {
+	"ide-disk",		/* name */
+	IDEDISK_VERSION,	/* version */
+	ide_disk,		/* media */
+	0,			/* busy */
+	1,			/* supports_dma */
+	0,			/* supports_dsc_overlap */
+	idedisk_cleanup,	/* cleanup */ /* NULL, */
+	do_idedisk_standby,	/* standby */
+	do_idedisk_flushcache,	/* flushcache */
+	do_rw_disk,		/* do_request */
+	NULL,			/* end_request */
+	NULL,			/* ioctl */
+	idedisk_open,		/* open */
+	idedisk_release,	/* release */
+	idedisk_media_change,	/* media_change */
+	NULL,			/* revalidate */
+	idedisk_pre_reset,	/* pre_reset */
+	idedisk_capacity,	/* capacity */
+	idedisk_special,	/* special */
+	idedisk_proc,		/* proc */
+	idedisk_reinit,		/* reinit */
+};
+
+int idedisk_init (void);
+static ide_module_t idedisk_module = {
+	IDE_DRIVER_MODULE,
+	idedisk_init,
+	&idedisk_driver,
+	NULL
+};
+
+int idedisk_reinit (ide_drive_t *drive)
+{
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+
+	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy++;
+	idedisk_setup(drive);
+	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		(void) idedisk_cleanup(drive);
+		DRIVER(drive)->busy--;
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 int idedisk_init (void)
@@ -879,12 +1587,15 @@
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
+			DRIVER(drive)->busy--;
 			continue;
 		}
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idedisk_module);
@@ -903,11 +1614,16 @@
 	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);
 			failed++;
 		}
+		/* 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);
+	}
 	ide_unregister_module(&idedisk_module);
 }
 #endif /* MODULE */
diff -urN linux-2.2.20-pristine/drivers/block/ide-dma.c linux-2.2.20/drivers/block/ide-dma.c
--- linux-2.2.20-pristine/drivers/block/ide-dma.c	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/ide-dma.c	Tue Nov 27 09:05:59 2001
@@ -1,5 +1,12 @@
 /*
- *  linux/drivers/block/ide-dma.c	Version 4.08  December 31, 1997
+ *  linux/drivers/block/ide-dma.c	Version 4.09	April 23, 1999
+ *
+ *  Copyright (c) 1999  Andre Hedrick
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ *  Special Thanks to Mark for his Six years of work.
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -24,7 +31,7 @@
  *
  * Use "hdparm -i" to view modes supported by a given drive.
  *
- * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
+ * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
  * DMA support, but must be (re-)compiled against this kernel version or later.
  *
  * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
@@ -79,11 +86,90 @@
 #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.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);
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+struct drive_list_entry drive_whitelist [] = {
+
+	{ "Micropolis 2112A"	,       "ALL"		},
+	{ "CONNER CTMA 4000"	,       "ALL"		},
+	{ "CONNER CTT8000-A"	,       "ALL"		},
+	{ "ST34342A"		,	"ALL"		},
+	{ 0			,	0		}
+};
+
+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"           },  
+	{ 0			,	0		}
+
+};
+
+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;
+}
+
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -109,11 +195,14 @@
  */
 const char *bad_dma_drives[] = {"WDC AC11000H",
 				"WDC AC22100H",
+				"WDC AC32100H",
 				"WDC AC32500H",
 				"WDC AC33100H",
 				"WDC AC31600H",
  				NULL};
 
+#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
@@ -163,11 +252,12 @@
  * Returns 0 if all went okay, returns 1 otherwise.
  * May also be invoked from trm290.c
  */
-int ide_build_dmatable (ide_drive_t *drive)
+int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	struct buffer_head *bh = rq->bh;
 	unsigned int size, addr, *table = (unsigned int *)HWIF(drive)->dmatable;
+	unsigned char *virt_addr;
 #ifdef CONFIG_BLK_DEV_TRM290
 	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
 #else
@@ -184,11 +274,13 @@
 		 * than two possibly non-adjacent physical 4kB pages.
 		 */
 		if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
-			addr = virt_to_bus (rq->buffer);
+			virt_addr = rq->buffer;
+			addr = virt_to_bus (virt_addr);
 			size = rq->nr_sectors << 9;
 		} else {
 			/* group sequential buffers into one large buffer */
-			addr = virt_to_bus (bh->b_data);
+			virt_addr = bh->b_data;
+			addr = virt_to_bus (virt_addr);
 			size = bh->b_size;
 			while ((bh = bh->b_reqnext) != NULL) {
 				if ((addr + size) != virt_to_bus (bh->b_data))
@@ -205,6 +297,20 @@
 			printk("%s: misaligned DMA buffer\n", drive->name);
 			return 0;
 		}
+
+		/*
+		 * Some CPUs without cache snooping need to invalidate/write
+		 * back their caches before DMA transfers to guarantee correct
+		 * data.        -- rmk
+		 */
+		if (size) {
+			if (func == ide_dma_read) {
+				dma_cache_inv((unsigned int)virt_addr, size);
+			} else {
+				dma_cache_wback((unsigned int)virt_addr, size);
+			}
+		}
+
 		while (size) {
 			if (++count >= PRD_ENTRIES) {
 				printk("%s: DMA table too small\n", drive->name);
@@ -237,13 +343,52 @@
 			}
 		}
 	} while (bh != NULL);
-	if (!count)
+	if (!count) {
 		printk("%s: empty DMA table?\n", drive->name);
-	else if (!is_trm290_chipset)
-		*--table |= cpu_to_le32(0x80000000);	/* set End-Of-Table (EOT) bit */
+	} else {
+		if (!is_trm290_chipset)
+			*--table |= cpu_to_le32(0x80000000);	/* set End-Of-Table (EOT) bit */
+		/*
+		 * Some CPUs need to flush the DMA table to physical RAM
+		 * before DMA can start.        -- rmk
+		 */
+		dma_cache_wback((unsigned long)HWIF(drive)->dmatable, count * sizeof(unsigned int) * 2);
+	}
 	return count;
 }
 
+#if 0
+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;
+	int sector_count = rq->nr_sectors;
+
+	if (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->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, hwif->sg_dma_direction);
+}
+
+#endif
+
 /*
  *  For both Blacklisted and Whitelisted drives.
  *  This is setup to be called as an extern for future support
@@ -251,9 +396,20 @@
  */
 int check_drive_lists (ide_drive_t *drive, int good_bad)
 {
-	const char **list;
 	struct hd_driveid *id = drive->id;
 
+#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 (good_bad) {
 		/* Consult the list of known "good" drives */
 		list = good_dma_drives;
@@ -272,33 +428,135 @@
 			}
 		}
 	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 	return 0;
 }
 
+int report_drive_dmaing (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	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");
+	}
+	return 1;
+}
+
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	if (id && (id->capability & 1) && hwif->autodma) {
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	if (drive->media != ide_disk)
+		config_allows_dma = 0;
+#endif
+
+	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
 		/* Consult the list of known "bad" drives */
-		if (check_drive_lists(drive, BAD_DMA_DRIVE))
+		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
+
+		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
+				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))
+			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 (check_drive_lists(drive, GOOD_DMA_DRIVE))
+		if (ide_dmaproc(ide_dma_good_drive, drive))
 			return hwif->dmaproc(ide_dma_on, drive);
 	}
 	return hwif->dmaproc(ide_dma_off_quietly, drive);
 }
 
+#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
+ /*
+ * 1 dmaing, 2 error, 4 intr
+ */
+static int dma_timer_expiry (ide_drive_t *drive)
+{
+	byte dma_stat = inb(HWIF(drive)->dma_base+2);
+
+#ifdef DEBUG
+	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
+#endif /* DEBUG */
+
+#if 1
+	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+#endif
+
+	if (dma_stat & 2) {	/* ERROR */
+		byte stat = GET_STAT();
+		return ide_error(drive, "dma_timer_expiry", stat);
+	}
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+	return 0;
+}
+#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+static ide_startstop_t ide_dma_timeout_revovery (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);
+
+	drive->waiting_for_dma = 0;
+
+	startstop = ide_do_reset(drive);
+
+	if ((enable_dma) && !(drive->using_dma))
+		(void) hwif->dmaproc(ide_dma_on, drive);
+
+	return startstop;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+
 /*
  * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
  *
@@ -317,24 +575,30 @@
  */
 int ide_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;
+//	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;
 	byte dma_stat;
 
 	switch (func) {
 		case ide_dma_off:
 			printk("%s: DMA disabled\n", drive->name);
 		case ide_dma_off_quietly:
+			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);
 			return 0;
 		case ide_dma_check:
 			return config_drive_for_dma (drive);
 		case ide_dma_read:
 			reading = 1 << 3;
 		case ide_dma_write:
-			if (!(count = ide_build_dmatable(drive)))
+			SELECT_READ_WRITE(hwif,drive,func);
+			if (!(count = ide_build_dmatable(drive, func)))
 				return 1;	/* try PIO instead of DMA */
 			outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */
 			outb(reading, dma_base);			/* specify r/w */
@@ -342,8 +606,21 @@
 			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 ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+#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);
+			} 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.
@@ -360,9 +637,60 @@
 			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);
+#if 0
+			if (dma_stat & 4) {
+				byte stat = GET_STAT();
+				outb(dma_base+2, dma_stat & 0xE4);
+			}
+#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 func: %d\n", func);
+			printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
 			return 1;
 	}
 }
@@ -433,6 +761,12 @@
 	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->mate && hwif->mate->dma_base) {
 		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
 	} else {
@@ -442,20 +776,56 @@
 			dma_base = 0;
 		}
 	}
+
+#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;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
 	if (dma_base) {
-		if (extra) /* PDC20246 & HPT343 */
+		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
 			request_region(dma_base+16, extra, name);
 		dma_base += hwif->channel ? 8 : 0;
 		hwif->dma_extra = extra;
-		
-		/* ====== ALI M5229 ================================*/
-		if( hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229)
-			outb(inb(dma_base+2) & 0x60, dma_base+2);           
-		/* =================================================*/
-		
-		if (inb(dma_base+2) & 0x80) {
-			printk("%s: simplex device:  DMA disabled\n", name);
-			dma_base = 0;
+
+		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;
+					}
+				}
 		}
 	}
 	return dma_base;
diff -urN linux-2.2.20-pristine/drivers/block/ide-features.c linux-2.2.20/drivers/block/ide-features.c
--- linux-2.2.20-pristine/drivers/block/ide-features.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/ide-features.c	Tue Nov 27 04:32:23 2001
@@ -0,0 +1,374 @@
+/*
+ * 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/malloc.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;
+	}
+}
+
+int ide_driveid_update (ide_drive_t *drive)
+{
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	struct hd_driveid *id;
+	unsigned long timeout, irqs, flags;
+
+	probe_irq_off(probe_irq_on());
+	irqs = probe_irq_on();
+	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)) {
+			if (irqs)
+				(void) probe_irq_off(irqs);
+			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);
+		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;
+}
+
+/*
+ *  All hosts that use the 80c ribbon mus use!
+ */
+byte eighty_ninty_three (ide_drive_t *drive)
+{
+	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);
+}
+
+/*
+ * 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;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	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 */
+
+	/*
+	 * 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;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	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 */
+
+	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);
+EXPORT_SYMBOL(eighty_ninty_three);
+EXPORT_SYMBOL(ide_config_drive_speed);
diff -urN linux-2.2.20-pristine/drivers/block/ide-floppy.c linux-2.2.20/drivers/block/ide-floppy.c
--- linux-2.2.20-pristine/drivers/block/ide-floppy.c	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/ide-floppy.c	Tue Nov 27 03:19:14 2001
@@ -62,6 +62,7 @@
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -71,12 +72,6 @@
 #include <asm/bitops.h>
 
 /*
- *	Main Linux ide driver include file
- */
-#include "ide.h"
-
-
-/*
  *	The following are used to debug the driver.
  */
 #define IDEFLOPPY_DEBUG_INFO		0
@@ -1014,7 +1009,8 @@
 		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	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);
@@ -1534,7 +1530,7 @@
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_SHORT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
+	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
@@ -1616,6 +1612,7 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -1628,16 +1625,20 @@
 	1,			/* supports_dma */
 	0,			/* supports_dsc_overlap */
 	idefloppy_cleanup,	/* cleanup */
+	NULL,			/* standby */
+	NULL,			/* flushcache  */
 	idefloppy_do_request,	/* do_request */
 	idefloppy_end_request,	/* end_request */
 	idefloppy_ioctl,	/* ioctl */
 	idefloppy_open,		/* open */
 	idefloppy_release,	/* release */
 	idefloppy_media_change,	/* media_change */
+	NULL,			/* revalidate */
 	NULL,			/* pre_reset */
 	idefloppy_capacity,	/* capacity */
 	NULL,			/* special */
-	idefloppy_proc		/* proc */
+	idefloppy_proc,		/* proc */
+	idefloppy_reinit,	/* reinit */
 };
 
 int idefloppy_init (void);
@@ -1648,6 +1649,39 @@
 	NULL
 };
 
+int idefloppy_reinit (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
 /*
  *	idefloppy_init will register the driver for each floppy.
@@ -1664,6 +1698,10 @@
 			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;
@@ -1696,11 +1734,16 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL)
+	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.
+		   Otherwise we oops while accessing these entries */
+		if (drive->proc)
+			ide_remove_proc_entries(drive->proc, idefloppy_proc);
+	}
 	ide_unregister_module(&idefloppy_module);
 }
 #endif /* MODULE */
diff -urN linux-2.2.20-pristine/drivers/block/ide-geometry.c linux-2.2.20/drivers/block/ide-geometry.c
--- linux-2.2.20-pristine/drivers/block/ide-geometry.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.20/drivers/block/ide-geometry.c	Tue Nov 27 04:23:02 2001
@@ -0,0 +1,230 @@
+/*
+ * linux/drivers/ide/ide-geometry.c
+ */
+#include <linux/config.h>
+#ifdef __i386__
+#include <linux/mc146818rtc.h>
+#endif
+#include <linux/ide.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
+ * 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 -- 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.  A non-zero value
+ * means we have an AT controller hard disk for that drive.
+ *
+ * Of course, there is no guarantee that either drive is actually on the
+ * "primary" IDE interface, but we don't bother trying to sort that out here.
+ * 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 doesnt work - there is no reasonable way to find the
+ * correspondence between the BIOS numbering of the disks and the Linux
+ * numbering. -aeb
+ *
+ * The code below is bad. One of the problems is that drives 1 and 2
+ * may be SCSI disks (even when IDE disks are present), so that
+ * the geometry we read here from BIOS is attributed to the wrong disks.
+ * Consequently, also the former "drive->present = 1" below was a mistake.
+ *
+ * Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
+ *
+ */
+#ifdef __i386__
+extern spinlock_t rtc_lock;
+#endif
+
+void probe_cmos_for_drives (ide_hwif_t *hwif)
+{
+#ifdef __i386__
+	unsigned long flags;
+	extern struct drive_info_struct drive_info;
+	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	int unit;
+
+#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);
+	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
+	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	/* Extract drive geometry from CMOS+BIOS if not already setup */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if ((cmos_disks & (0xf0 >> (unit*4)))
+		   && !drive->present && !drive->nobios) {
+			unsigned short cyl = *(unsigned short *)BIOS;
+			unsigned char head = *(BIOS+2);
+			unsigned char sect = *(BIOS+14);
+			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
+				drive->cyl   = drive->bios_cyl  = cyl;
+				drive->head  = drive->bios_head = head;
+				drive->sect  = drive->bios_sect = sect;
+				drive->ctl   = *(BIOS+8);
+			} else {
+				printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n",
+				       unit, cyl, head, sect);
+			}
+		}
+
+		BIOS += 16;
+	}
+#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 *);
+
+/*
+ * 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;
+	unsigned long total;
+
+	/*
+	 * The specs say: take geometry as obtained from Identify,
+	 * compute total capacity C*H*S from that, and truncate to
+	 * 1024*255*63. Now take S=63, H the first in the sequence
+	 * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+	 * [Please tell aeb@cwi.nl in case this computes a
+	 * geometry different from what OnTrack uses.]
+	 */
+	total = DRIVER(drive)->capacity(drive);
+
+	*s = 63;
+
+	if (heads) {
+		*h = heads;
+		*c = total / (63 * heads);
+		return;
+	}
+
+	while (63 * headp[0] * 1024 < total && headp[1] != 0)
+		 headp++;
+	*h = headp[0];
+	*c = total / (63 * headp[0]);
+}
+
+/*
+ * This routine is called from the partition-table code in pt/msdos.c.
+ * It has two tasks:
+ * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
+ *  or to handle EZdrive by remapping sector 0 to sector 1.
+ * (ii) to invent a translated geometry.
+ * Part (i) is suppressed if the user specifies the "noremap" option
+ * on the command line.
+ * Part (ii) is suppressed if the user specifies an explicit geometry.
+ *
+ * The ptheads parameter is either 0 or tells about the number of
+ * heads shown by the end of the first nonempty partition.
+ * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
+ *
+ * The xparm parameter has the following meaning:
+ *	 0 = convert to CHS with fewer than 1024 cyls
+ *	     using the same method as Ontrack DiskManager.
+ *	 1 = same as "0", plus offset everything by 63 sectors.
+ *	-1 = similar to "0", plus redirect sector 0 to sector 1.
+ *	 2 = convert to a CHS geometry with "ptheads" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not 
+ * 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;
+	const char *msg1 = "";
+	int heads = 0;
+	int c, h, s;
+	int transl = 1;		/* try translation */
+	int ret = 0;
+
+	drive = get_info_ptr(i_rdev);
+	if (!drive)
+		return 0;
+
+	/* remap? */
+	if (drive->remap_0_to_1 != 2) {
+		if (xparm == 1) {		/* DM */
+			drive->sect0 = 63;
+			msg1 = " [remap +63]";
+			ret = 1;
+		} else if (xparm == -1) {	/* EZ-Drive */
+			if (drive->remap_0_to_1 == 0) {
+				drive->remap_0_to_1 = 1;
+				msg1 = " [remap 0->1]";
+				ret = 1;
+			}
+		}
+	}
+
+	/* There used to be code here that assigned drive->id->CHS
+	   to drive->CHS and that to drive->bios_CHS. However,
+	   some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
+	   In such cases that code was wrong.  Moreover,
+	   there seems to be no reason to do any of these things. */
+
+	/* translate? */
+	if (drive->forced_geom)
+		transl = 0;
+
+	/* does ptheads look reasonable? */
+	if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
+	    ptheads == 240 || ptheads == 255)
+		heads = ptheads;
+
+	if (xparm == 2) {
+		if (!heads ||
+		   (drive->bios_head >= heads && drive->bios_sect == 63))
+			transl = 0;
+	}
+	if (xparm == -1) {
+		if (drive->bios_head > 16)
+			transl = 0;     /* we already have a translation */
+	}
+
+	if (transl) {
+		ontrack(drive, heads, &c, &h, &s);
+		drive->bios_cyl = c;
+		drive->bios_head = h;
+		drive->bios_sect = s;
+		ret = 1;
+	}
+
+	drive->part[0].nr_sects = current_capacity(drive);
+
+	if (ret)
+		printk("%s%s [%d/%d/%d]", msg, msg1,
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	return ret;
+}
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -urN linux-2.2.20-pristine/drivers/block/ide-pci.c linux-2.2.20/drivers/block/ide-pci.c
--- linux-2.2.20-pristine/drivers/block/ide-pci.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ide-pci.c	Tue Nov 27 13:41:42 2001
@@ -1,5 +1,7 @@
 /*
- *  linux/drivers/block/ide-pci.c	Version 1.02  December 29, 1997
+ *  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
@@ -10,6 +12,13 @@
  *  configuration of all PCI IDE interfaces present in a system.  
  */
 
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
+ */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -18,61 +27,193 @@
 #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.h"
-
-#define DEVID_450NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
 #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_PIIX4E	((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_PIIX4U	((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_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
+#define DEVID_PIIX4U4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
+#define DEVID_PIIX4U5	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
+#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_VP_OLDIDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_0})
 #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_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
 #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,    0xd568})  /* from datasheets */
-#define DEVID_ALI15X3   ((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
+#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_HPT343	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#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 IDE_IGNORE	((void *)-1)
+#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 SUB_DEVID	((ide_pci_devid_t){0x0000, 0x0000})
+
+#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 *);
-#define INIT_ALI15X3  &ide_init_ali15x3
+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 INIT_ALI15X3  NULL
+#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_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
+#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 INIT_TRM290	IDE_IGNORE
+#define PCI_CY82C693	NULL
+#define INIT_CY82C693	IDE_NO_DRIVER
 #endif
 
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
+#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 INIT_OPTI621	NULL
+#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
@@ -82,22 +223,53 @@
 #define INIT_NS87415	IDE_IGNORE
 #endif
 
-#ifdef CONFIG_BLK_DEV_CMD646
-extern void ide_init_cmd646(ide_hwif_t *);
-#define INIT_CMD646	&ide_init_cmd646
-#else
-#ifdef __sparc_v9__
-#define INIT_CMD646	IDE_IGNORE
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void ide_init_opti621(ide_hwif_t *);
+#define INIT_OPTI621	&ide_init_opti621
 #else
-#define INIT_CMD646	NULL
-#endif
+#define INIT_OPTI621	IDE_NO_DRIVER
 #endif
 
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define INIT_W82C105	IDE_IGNORE
+#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	IDE_IGNORE
+#define ATA66_PDC202XX	IDE_IGNORE
+#define INIT_PDC202XX	IDE_IGNORE
+#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_RZ1000
@@ -107,21 +279,82 @@
 #define INIT_RZ1000	IDE_IGNORE
 #endif
 
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern void ide_init_via82c586(ide_hwif_t *);
-#define	INIT_VIA82C586	&ide_init_via82c586
+#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	INIT_VIA82C586	NULL
+#define PCI_W82C105	NULL
+#define DMA_W82C105	NULL
+#define INIT_W82C105	IDE_IGNORE
 #endif
 
-#ifdef CONFIG_BLK_DEV_CS5530
-extern void ide_init_cs5530(ide_hwif_t *);
-#define INIT_CS5530     &ide_init_cs5530
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290	&ide_init_trm290
 #else
-#define INIT_CS5530     NULL
+#define INIT_TRM290	IDE_IGNORE
 #endif
 
-static int autodma_default = 0;
+#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 */
@@ -131,39 +364,90 @@
 
 typedef struct ide_pci_device_s {
 	ide_pci_devid_t		devid;
-	const char		*name;
+	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_devid_t		sub_devid;
 } ide_pci_device_t;
 
 static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	INIT_VIA82C586,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_PDC20246,"PDC20246",	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_RZ1000,	"RZ1000",	INIT_RZ1000,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	INIT_RZ1000,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	IDE_IGNORE,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	INIT_CMD646,	{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_HT6565,	"HT6565",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_ALI15X3, "ALI15X3",  INIT_ALI15X3,   {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,   0 },
-	{DEVID_TRM290,	"TRM290",	INIT_TRM290,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	INIT_NS87415,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	INIT_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT343,	"HPT343",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_CS5530,	"CS5530",	INIT_CS5530,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	112 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
+	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4E,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4U,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4U3,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4U4, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PIIX4U5, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0,	SUB_DEVID },
+#ifdef CONFIG_PDC202XX_FORCE
+        {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16,	SUB_DEVID },
+        {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48,	SUB_DEVID },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48,	SUB_DEVID },
+        {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48,	SUB_DEVID },
+#else /* !CONFIG_PDC202XX_FORCE */
+	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16,	SUB_DEVID },
+	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48,	SUB_DEVID },
+	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48,	SUB_DEVID },
+	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48,	SUB_DEVID },
+#endif
+	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0,	SUB_DEVID },
+	/* Promise used a different PCI ident for the raid card apparently to try and
+	   prevent Linux detecting it and using our own raid code. We want to detect
+	   it for the ataraid drivers, so we have to list both here.. */
+	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0,	SUB_DEVID },
+	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16,	SUB_DEVID },
+	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240,	SUB_DEVID },
+	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0,	SUB_DEVID },
+	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0,	SUB_DEVID },
+        {DEVID_OSB4,    "ServerWorks OSB4",	PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{DEVID_CSB5,	"ServerWorks CSB5",	PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	SUB_DEVID },
+	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	SUB_DEVID }};
 
 /*
  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
@@ -173,27 +457,18 @@
 __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name))
 {
 	switch(dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		case PCI_DEVICE_ID_TTI_HPT366:
 		case PCI_DEVICE_ID_PROMISE_20246:
-			if (dev->rom_address) {
-				pci_write_config_byte(dev, PCI_ROM_ADDRESS,
-					dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
-				printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
-			}
-			
-			if ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID) {
-				unsigned char irq1 = 0, irq2 = 0;
-
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq1);
-				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
-				if (irq1 != irq2) {
-					printk("%s: IRQ1 %d IRQ2 %d\n",
-						name, irq1, irq2);
-					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq1);	/* 0xbc */
-				}
-			}
-			return dev->irq;
-		case PCI_DEVICE_ID_TTI_HPT343:
+		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_20268R:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
 			return dev->irq;
 		default:
 			break;
@@ -252,13 +527,14 @@
 				return hwif;	/* pick an unused entry */
 		}
 	} else {
+//		for (h = 0; h < ((MAX_HWIFS >= 2) ? 2 : MAX_HWIFS); ++h) {
 		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 < ((MAX_HWIFS >= 2) ? 2 : MAX_HWIFS); ++h) {
+	for (h = 0; h < 2; ++h) {
 		hwif = ide_hwifs + h;
 		if (hwif->chipset == ide_unknown)
 			return hwif;	/* pick an unused entry */
@@ -291,7 +567,7 @@
 	 */
 	for (reg = 0; reg < 4; reg++)
 		if (!dev->base_address[reg]) {
-			printk("%s: Missing I/O address #%d, please report to <mj@ucw.cz>\n", name, reg);
+			printk("%s: Missing I/O address #%d\n", name, reg);
 			return 1;
 		}
 	return 0;
@@ -309,11 +585,21 @@
  */
 __initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d))
 {
-	unsigned int port, at_least_one_hwif_enabled = 0, pciirq = 0;
+	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;
-	int autodma = autodma_default;
+	unsigned int class_rev;
+	static int secondpdc = 0;
+
+#ifdef CONFIG_IDEDMA_AUTO
+	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;
+	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
@@ -339,13 +625,52 @@
 	}
 	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);
-		pciirq = ide_special_settings(dev, 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;
@@ -353,6 +678,8 @@
 		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));
@@ -360,17 +687,40 @@
 		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->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK;
 			base = dev->base_address[2*port] & ~7;
+			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);
@@ -383,13 +733,14 @@
 		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->io_ports, base, NULL);
-			hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
+			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->pci_sub_devid = d->sub_devid;
 		hwif->channel = port;
 		if (!hwif->irq)
 			hwif->irq = pciirq;
@@ -402,37 +753,80 @@
 			}
 		}
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF))
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
 			hwif->irq = hwif->channel ? 15 : 14;
-
+			goto bypass_umc_dma;
+		}
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
+			goto bypass_piix_dma;
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680))
+			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))
+		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_PDC20268R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) ||
+		    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_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)
  	 			 */
-				hwif->autodma = 0;	/* default DMA off if we had to configure it here */
+		    		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)
-				ide_setup_dma(hwif, dma_base, 8);
-			else
+			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;
@@ -442,6 +836,100 @@
 		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;
+		for (findev=pci_devices; findev; findev=findev->next) {
+			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);
+}
+
+__initfunc(static void 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"};
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	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);
+	for (findev=pci_devices; findev; findev=findev->next) {
+		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 1
+				/* 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.
@@ -454,44 +942,31 @@
 
 	if (!pci_present())
 		return;
-
-#ifdef CONFIG_IDEDMA_AUTO
-	autodma_default = 1;
-	for(dev = pci_devices; dev; dev=dev->next) {
+	for (dev = pci_devices; dev; dev=dev->next) {
 		devid.vid = dev->vendor;
 		devid.did = dev->device;
-		if (IDE_PCI_DEVID_EQ(devid, DEVID_450NX)) {
-			autodma_default = 0;
-			break;
-		}
-		/*
-		 *	Don't try and tune a VIA 82C586 or 586A
-		 */
-		if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_IDE))
-		{
-			autodma_default = 0;
-			break;
-		}
-		if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_OLDIDE))
-		{
-			autodma_default = 0;
-			break;
-		}
-	}
-#endif
 
-	for(dev = pci_devices; dev; dev=dev->next) {
-		devid.vid = dev->vendor;
-		devid.did = dev->device;
 		for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+
+		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &(d->sub_devid.vid));
+		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &(d->sub_devid.did));
+		
 		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))
-			continue;	/* OPTI Viper-M uses same devid for functions 0 and 1 */
+			continue;
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+			continue;	/* CY82C693 is more than only a IDE controller */
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
+			continue;	/* UM8886A/BF pair */
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
+			hpt366_device_order_fixup(dev, d);
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+			pdc20270_device_order_fixup(dev, d);
 		else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 			if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 				printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
-					d->name, dev->bus->number, dev->devfn, devid.vid, devid.did);
+				       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);
diff -urN linux-2.2.20-pristine/drivers/block/ide-pmac.c linux-2.2.20/drivers/block/ide-pmac.c
--- linux-2.2.20-pristine/drivers/block/ide-pmac.c	Fri Nov  2 08:39:06 2001
+++ linux-2.2.20/drivers/block/ide-pmac.c	Mon Nov 26 13:14:23 2001
@@ -24,10 +24,11 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
-#include <asm/ide.h>
+//	#include <asm/ide.h>
 #include <asm/mediabay.h>
 #include <asm/feature.h>
 #ifdef CONFIG_PMAC_PBOOK
@@ -35,7 +36,7 @@
 #include <asm/pmu.h>
 #include <asm/irq.h>
 #endif
-#include "ide.h"
+
 #include "ide_modes.h"
 
 #undef IDE_PMAC_DEBUG
@@ -288,8 +289,7 @@
 	return 0;
 }
 
-__initfunc(void
-pmac_ide_probe(void))
+__initfunc(void pmac_ide_probe(void))
 {
 	struct device_node *np;
 	int i;
diff -urN linux-2.2.20-pristine/drivers/block/ide-probe.c linux-2.2.20/drivers/block/ide-probe.c
--- linux-2.2.20-pristine/drivers/block/ide-probe.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ide-probe.c	Wed Nov 28 00:29:46 2001
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-probe.c	Version 1.04  March 10, 1999
+ *  linux/drivers/block/ide-probe.c	Version 1.05  July 3, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -18,8 +18,11 @@
  *			 by Andrea Arcangeli
  * Version 1.03		fix for (hwif->chipset == ide_4drives)
  * Version 1.04		fixed buggy treatments of known flash memory cards
- * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
- * chip.
+ *
+ * Version 1.05		fix for (hwif->chipset == ide_pdc4030)
+ *			added ide6/7/8/9
+ *			allowed for secondary flash card to be detectable
+ *			 with new flag : drive->ata_flash : 1;
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -38,24 +41,29 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include "ide.h"
-
 static inline void do_identify (ide_drive_t *drive, byte cmd)
 {
 	int bswap = 1;
 	struct hd_driveid *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;
+	}
+
 	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
 	ide__sti();	/* local CPU only */
 	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:
@@ -83,6 +91,9 @@
 	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! */
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
@@ -96,8 +107,7 @@
 #ifdef CONFIG_BLK_DEV_PDC4030
 		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
-			drive->present = 0;
-			return;
+			goto err_misc;
 		}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 		switch (type) {
@@ -121,7 +131,7 @@
 					break;
 				}
 #endif
-				printk ("CDROM");
+				printk ("CD/DVD-ROM");
 				break;
 			case ide_tape:
 				printk ("TAPE");
@@ -150,25 +160,24 @@
 	 */
 	if (drive_is_flashcard(drive)) {
 		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
-		mate->present = 0;
-		mate->noprobe = 1;
+		if (!mate->ata_flash) {
+			mate->present = 0;
+			mate->noprobe = 1;
+		}
 	}
 	drive->media = ide_disk;
 	printk("ATA DISK drive\n");
+	QUIRK_LIST(HWIF(drive),drive);
 	return;
-}
 
-/*
- * Delay for *at least* 50ms.  As we don't know how much time is left
- * until the next tick occurs, we wait an extra tick to be safe.
- * This is used only during the probing/polling for drives at boot time.
- */
-static void delay_50ms (void)
-{
-	unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
-	while (0 < (signed long)(timeout - jiffies));
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+	return;
 }
 
+#if 0
 /*
  * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
  * and waits for a response.  It also monitors irqs while this is
@@ -186,30 +195,37 @@
 	unsigned long timeout;
 	unsigned long irqs = 0;
 	byte s, a;
+  
+	if (IDE_CONTROL_REG) {
+		if (!HWIF(drive)->irq) {		/* already got an IRQ? */
+			probe_irq_off(probe_irq_on());	/* clear dangling irqs */
+			irqs = probe_irq_on();		/* start monitoring irqs */
+			OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		}
 
-	if (!HWIF(drive)->irq) {		/* already got an IRQ? */
-		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
-		irqs = probe_irq_on();		/* start monitoring irqs */
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		ide_delay_50ms();				/* take a deep breath */
+		a = IN_BYTE(IDE_ALTSTATUS_REG);
+		s = IN_BYTE(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 */
+		} else {
+			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+		}
+	} else {
+		ide_delay_50ms();
+		hd_status = IDE_STATUS_REG;
 	}
 
-	delay_50ms();				/* take a deep breath */
-	a = IN_BYTE(IDE_ALTSTATUS_REG);
-	s = IN_BYTE(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 */
-	} else
-		hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
-
 	/* set features register for atapi identify command */
 	if((cmd == WIN_PIDENTIFY))
 	        OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap mode */
 
 #if CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern int pdc4030_cmd(ide_drive_t *, byte);
-		if (pdc4030_cmd(drive,PROMISE_IDENTIFY)) {
+	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 (irqs)
 				(void) probe_irq_off(irqs);
 			return 1;
@@ -225,10 +241,10 @@
 				(void) probe_irq_off(irqs);
 			return 1;	/* drive timed-out */
 		}
-		delay_50ms();		/* give drive a breather */
+		ide_delay_50ms();		/* give drive a breather */
 	} while (IN_BYTE(hd_status) & BUSY_STAT);
 
-	delay_50ms();		/* wait for IRQ and DRQ_STAT */
+	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
 	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
 		unsigned long flags;
 		__save_flags(flags);	/* local CPU only */
@@ -239,7 +255,7 @@
 		__restore_flags(flags);	/* local CPU only */
 	} else
 		rc = 2;			/* drive refused ID */
-	if (!HWIF(drive)->irq) {
+	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
 		irqs = probe_irq_off(irqs);	/* get our irq number */
 		if (irqs > 0) {
 			HWIF(drive)->irq = irqs; /* save it for later */
@@ -265,6 +281,118 @@
 	return rc;
 }
 
+#else
+/*
+ * 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)
+{
+	int rc;
+	ide_ioreg_t hd_status;
+	unsigned long timeout;
+	byte s, a;
+
+	if (IDE_CONTROL_REG) {
+		/* take a deep breath */
+		ide_delay_50ms();
+		a = IN_BYTE(IDE_ALTSTATUS_REG);
+		s = IN_BYTE(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 */
+		} else {
+			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+		}
+	} else {
+		ide_delay_50ms();
+		hd_status = IDE_STATUS_REG;
+	}
+
+	/* 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 */
+
+#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)) {
+			return 1;
+		}
+	} else
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+	timeout += jiffies;
+	do {
+		if (0 < (signed long)(jiffies - timeout)) {
+			return 1;	/* drive timed-out */
+		}
+		ide_delay_50ms();		/* give drive a breather */
+	} while (IN_BYTE(hd_status) & BUSY_STAT);
+
+	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
+	if (OK_STAT(GET_STAT(),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 */
+	return rc;
+}
+
+static int try_to_identify (ide_drive_t *drive, byte cmd)
+{
+	int retval;
+	int autoprobe = 0;
+	unsigned long cookie = 0;
+
+	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+		autoprobe = 1;
+		cookie = probe_irq_on();
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+	}
+
+	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 */
+		udelay(5);
+		irq = probe_irq_off(cookie);
+		if (!HWIF(drive)->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);
+#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);
+					CMD640_DUMP_REGS;
+				}
+#endif /* CMD640_DUMP_REGS */
+#endif /* CONFIG_BLK_DEV_CMD640 */
+			}
+		}
+	}
+	return retval;
+}
+
+#endif
+
 /*
  * 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
@@ -294,13 +422,13 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
+	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
 	SELECT_DRIVE(hwif,drive);
-	delay_50ms();
+	ide_delay_50ms();
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		if (drive->select.b.unit != 0) {
 			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			delay_50ms();		/* allow BUSY_STAT to assert & clear */
+			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
 		}
 		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
 	}
@@ -313,13 +441,13 @@
 		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
 			unsigned long timeout;
 			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
-			delay_50ms();
+			ide_delay_50ms();
 			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
-			delay_50ms();
+			ide_delay_50ms();
 			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
 			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
-				delay_50ms();
+				ide_delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
@@ -330,13 +458,42 @@
 	}
 	if (drive->select.b.unit != 0) {
 		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-		delay_50ms();
+		ide_delay_50ms();
 		(void) GET_STAT();		/* ensure drive irq is clear */
 	}
 	return rc;
 }
 
 /*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+	unsigned long timeout;
+
+	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
+	SELECT_DRIVE(HWIF(drive), drive);
+	ide_delay_50ms();
+	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (jiffies > timeout) {
+			printk("failed (timeout)\n");
+			return;
+		}
+		ide_delay_50ms();
+	} while (GET_STAT() & BUSY_STAT);
+	ide_delay_50ms();
+	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
+		printk("failed (status = 0x%02x)\n", GET_STAT());
+	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 */
+	}
+}
+
+/*
  * probe_for_drive() tests for existence of a given drive using do_probe().
  *
  * Returns:	0  no device was found
@@ -349,6 +506,8 @@
 	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? */
@@ -365,64 +524,70 @@
 }
 
 /*
- * 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 -- 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.  A non-zero value
- * means we have an AT controller hard disk for that drive.
- *
- * Of course, there is no guarantee that either drive is actually on the
- * "primary" IDE interface, but we don't bother trying to sort that out here.
- * 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
+ * Calculate the region that this interface occupies,
+ * handling interfaces where the registers may not be
+ * ordered sanely.  We deal with the CONTROL register
+ * separately.
  */
-static void probe_cmos_for_drives (ide_hwif_t *hwif)
+static int hwif_check_regions (ide_hwif_t *hwif)
 {
-#ifdef __i386__
-	unsigned long flags;
-	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
-	int unit;
+	int region_errors = 0;
 
-#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);
-	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
-	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	/* Extract drive geometry from CMOS+BIOS if not already setup */
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-		if ((cmos_disks & (0xf0 >> (unit*4)))
-		    && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
-			unsigned char head = *(BIOS+2);
-			unsigned char sect = *(BIOS+14);
-			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
-				drive->cyl   = drive->bios_cyl  = cyl;
-				drive->head  = drive->bios_head = head;
-				drive->sect  = drive->bios_sect = sect;
-				drive->ctl   = *(BIOS+8);
-				drive->present = 1;
-			} else
-				printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n",
-				       unit, cyl, head, sect);
-		}
-		BIOS += 16;
-	}
-#endif
+	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);
+
+	if (hwif->io_ports[IDE_CONTROL_OFFSET])
+		region_errors += ide_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);
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+	/*
+	 * If any errors are return, we drop the hwif interface.
+	 */
+	return(region_errors);
+}
+
+static void hwif_register (ide_hwif_t *hwif)
+{
+	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->straight8 = 1;
+		goto jump_straight8;
+	}
+
+	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);
+
+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) */
 }
 
 /*
@@ -436,14 +601,19 @@
 
 	if (hwif->noprobe)
 		return;
-	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
+#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);
-	if ((hwif->chipset != ide_4drives || !hwif->mate->present)
+	}
+#endif
+
+	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
-	 && (hwif->chipset != ide_pdc4030 || hwif->channel == 0)
+	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
-	 && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)))
-	{
+	    (hwif_check_regions(hwif))) {
 		int msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
@@ -470,12 +640,11 @@
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
 			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
-				ide_request_region(hwif->io_ports[IDE_DATA_OFFSET],  8, hwif->name);
-				ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+				hwif_register(hwif);
 			}
 		}
 	}
-	if (hwif->reset) {
+	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 		unsigned long timeout = jiffies + WAIT_WORSTCASE;
 		byte stat;
 
@@ -484,7 +653,7 @@
 		udelay(10);
 		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		do {
-			delay_50ms();
+			ide_delay_50ms();
 			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
 		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
 
@@ -596,7 +765,15 @@
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-		int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+#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;
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
 		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
@@ -635,7 +812,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
 #elif defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %s", hwif->name,
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET],
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
@@ -662,18 +839,35 @@
 	unsigned int unit, units, minors;
 	int *bs, *max_sect, *max_ra;
 
+#if 0
+	units = MAX_DRIVES;
+#else
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
 		if (hwif->drives[units-1].present)
 			break;
 	}
+#endif
+
 	minors    = units * (1<<PARTN_BITS);
 	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	if (!gd->sizes)
+		goto err_kmalloc_gd_sizes;
 	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!gd->part)
+		goto err_kmalloc_gd_part;
 	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!bs)
+		goto err_kmalloc_gs;
 	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_sect)
+		goto err_kmalloc_max_sect;
 	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_ra)
+		goto err_kmalloc_max_ra;
 
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
@@ -683,7 +877,12 @@
 	max_readahead[hwif->major] = max_ra;
 	for (unit = 0; unit < minors; ++unit) {
 		*bs++ = BLOCK_SIZE;
-		*max_sect++ = MAX_SECTORS;
+#ifdef CONFIG_BLK_DEV_PDC4030
+		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+#else
+		/* IDE can do up to 128K but limit to 64K per request. */
+		*max_sect++ = 128;
+#endif
 		*max_ra++ = MAX_READAHEAD;
 	}
 
@@ -704,9 +903,26 @@
 	hwif->gd = *gdp = gd;			/* link onto tail of list */
 
 	for (unit = 0; unit < units; ++unit) {
-		if (hwif->drives[unit].present)
+		if (hwif->drives[unit].present) {
+			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
 			ide_add_generic_settings(hwif->drives + unit);
+		}
 	}
+	return;
+
+err_kmalloc_max_ra:
+	kfree(max_sect);
+err_kmalloc_max_sect:
+	kfree(bs);
+err_kmalloc_gs:
+	kfree(gd->part);
+err_kmalloc_gd_part:
+	kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	return;
 }
 
 static int hwif_init (ide_hwif_t *hwif)
@@ -716,7 +932,8 @@
 	if (!hwif->present)
 		return 0;
 	if (!hwif->irq) {
-		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
+		{
 			printk("%s: DISABLED, NO IRQ\n", hwif->name);
 			return (hwif->present = 0);
 		}
@@ -746,6 +963,18 @@
 #if MAX_HWIFS > 5
 	case IDE5_MAJOR: rfn = &do_ide5_request; break;
 #endif
+#if MAX_HWIFS > 6
+	case IDE6_MAJOR: rfn = &do_ide6_request; break;
+#endif
+#if MAX_HWIFS > 7
+	case IDE7_MAJOR: rfn = &do_ide7_request; break;
+#endif
+#if MAX_HWIFS > 8
+	case IDE8_MAJOR: rfn = &do_ide8_request; break;
+#endif
+#if MAX_HWIFS > 9
+	case IDE9_MAJOR: rfn = &do_ide9_request; break;
+#endif
 	default:
 		printk("%s: request_fn NOT DEFINED\n", hwif->name);
 		return (hwif->present = 0);
@@ -767,7 +996,7 @@
 			(void) unregister_blkdev (hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
-		if(init_irq (hwif)) 
+		if (init_irq (hwif)) 
 		{
 			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 				hwif->name, i, hwif->irq);
@@ -821,12 +1050,15 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
-	ide_register_module(&ideprobe_module);
+	if (!ide_probe)
+		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 #ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
 int init_module (void)
 {
 	unsigned int index;
@@ -834,15 +1066,14 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		ide_unregister(index);
 	ideprobe_init();
-#ifdef CONFIG_PROC_FS
-	proc_ide_destroy();	/* Avoid multiple entry in /proc */
-	proc_ide_create();
-#endif
+	create_proc_ide_interfaces();
+	ide_xlate_1024_hook = ide_xlate_1024;
 	return 0;
 }
 
 void cleanup_module (void)
 {
-	ide_unregister_module(&ideprobe_module);
+	ide_probe = NULL;
+	ide_xlate_1024_hook = 0;
 }
 #endif /* MODULE */
diff -urN linux-2.2.20-pristine/drivers/block/ide-proc.c linux-2.2.20/drivers/block/ide-proc.c
--- linux-2.2.20-pristine/drivers/block/ide-proc.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ide-proc.c	Tue Nov 27 13:35:18 2001
@@ -65,13 +65,67 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
 
 #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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, int) = NULL;
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -103,6 +157,8 @@
 	return -EINVAL;
 }
 
+static struct proc_dir_entry * proc_ide_root = NULL;
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -206,7 +262,7 @@
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 			if (for_real) {
 #if 0
-				printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
+				printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
 #endif
 				if (is_pci) {
 #ifdef CONFIG_BLK_DEV_IDEPCI
@@ -232,6 +288,27 @@
 					}
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 				} else {	/* not pci */
+#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+
+/*
+ * Geert Uytterhoeven
+ *
+ * unless you can explain me what it really does.
+ * On m68k, we don't have outw() and outl() yet,
+ * and I need a good reason to implement it.
+ *
+ * BTW, IMHO the main remaining portability problem with the IDE driver
+ * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
+ *
+ * I think all accesses should be done using
+ *
+ *     ide_in[bwl](ide_device_instance, offset)
+ *     ide_out[bwl](ide_device_instance, value, offset)
+ *
+ * so the architecture specific code can #define ide_{in,out}[bwl] to the
+ * appropriate function.
+ *
+ */
 					switch (digits) {
 						case 2:	outb(val, reg);
 							break;
@@ -240,6 +317,7 @@
 						case 8:	outl(val, reg);
 							break;
 					}
+#endif /* !__mc68000__ && !CONFIG_APUS */
 				}
 			}
 		}
@@ -304,7 +382,7 @@
 
 	while (p) {
 		driver = (ide_driver_t *) p->info;
-		if (p->type == IDE_DRIVER_MODULE && driver)
+		if (driver)
 			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
 		p = p->next;
 	}
@@ -367,7 +445,15 @@
 
 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
 {
-	return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.sector_count = 0x01;
+	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_ide_read_identify
@@ -376,8 +462,8 @@
 	ide_drive_t	*drive = (ide_drive_t *)data;
 	int		len = 0, i = 0;
 
-	if (!proc_ide_get_identify(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+	if (drive && !proc_ide_get_identify(drive, page)) {
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -386,6 +472,8 @@
 		} while (i < (SECTOR_WORDS * 2));
 		len = out - page;
 	}
+	else
+		len = sprintf(page, "\n");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -517,10 +605,8 @@
 	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);
 }
@@ -628,21 +714,30 @@
 	return sprintf(page, "ide%d/%s", n, de->name);
 }
 
-static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root)
+static void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
+		ide_driver_t *driver = drive->driver;
 
 		if (!drive->present)
 			continue;
-		drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
 		if (drive->proc)
-			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+			continue;
 
-		ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root);
+		drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+		if (drive->proc) {
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+			if (driver) {
+				ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+				ide_add_proc_entries(drive->proc, driver->proc, drive);
+			}
+		}
+		ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, proc_ide_root);
 		if (!ent) return;
 		ent->data = drive;
 		ent->readlink_proc = proc_ide_readlink;
@@ -650,6 +745,33 @@
 	}
 }
 
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	ide_driver_t *driver = drive->driver;
+
+	if (drive->proc) {
+		if (driver)
+			ide_remove_proc_entries(drive->proc, driver->proc);
+		ide_remove_proc_entries(drive->proc, generic_drive_entries);
+		remove_proc_entry(drive->name, proc_ide_root);
+		remove_proc_entry(drive->name, hwif->proc);
+		drive->proc = NULL;
+	}
+}
+
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+//		ide_driver_t *driver = drive->driver;
+
+		if (drive->proc)
+			destroy_proc_ide_device(hwif, drive);
+	}
+}
+
 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 },
@@ -658,33 +780,135 @@
 	{ NULL,	0, NULL, NULL }
 };
 
-static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+void create_proc_ide_interfaces(void)
 {
 	int	h;
-	struct proc_dir_entry *hwif_ent;
 
 	for (h = 0; h < MAX_HWIFS; h++) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
+		int exist = (hwif->proc != NULL);
 
 		if (!hwif->present)
 			continue;
-		hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
-		if (!hwif_ent) return;
-		ide_add_proc_entries(hwif_ent, hwif_entries, hwif);
-		create_proc_ide_drives(hwif, hwif_ent, parent);
+		if (!exist)
+			hwif->proc = create_proc_entry(hwif->name, S_IFDIR, proc_ide_root);
+		if (!hwif->proc)
+			return;
+		if (!exist)
+			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
+		create_proc_ide_drives(hwif);
+	}
+}
+
+static void destroy_proc_ide_interfaces(void)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+#if 0
+		if (!hwif->present)
+			continue;
+#endif
+		if (!hwif->proc)
+			continue;
+		else {
+			destroy_proc_ide_drives(hwif);
+			ide_remove_proc_entries(hwif->proc, hwif_entries);
+			remove_proc_entry(hwif->name, proc_ide_root);
+			hwif->proc = NULL;
+		}
 	}
 }
 
 void proc_ide_create(void)
 {
-	struct proc_dir_entry *root, *ent;
-	root = create_proc_entry("ide", S_IFDIR, 0);
-	if (!root) return;
-	create_proc_ide_interfaces(root);
+	struct proc_dir_entry *ent;
+	proc_ide_root = create_proc_entry("ide", S_IFDIR, 0);
+	if (!proc_ide_root) return;
+	create_proc_ide_interfaces();
 
-	ent = create_proc_entry("drivers", 0, root);
+	ent = create_proc_entry("drivers", 0, proc_ide_root);
 	if (!ent) return;
 	ent->read_proc  = proc_ide_read_drivers;
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	if ((aec62xx_display_info) && (aec62xx_proc)) {
+		ent = create_proc_entry("aec62xx", 0, proc_ide_root);
+		ent->get_info = aec62xx_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_AEC62XX */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+	if ((ali_display_info) && (ali_proc)) {
+		ent = create_proc_entry("ali", 0, proc_ide_root);
+		ent->get_info = ali_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD74XX
+	if ((amd74xx_display_info) && (amd74xx_proc)) {
+		ent = create_proc_entry("amd74xx", 0, proc_ide_root);
+		ent->get_info = amd74xx_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_AMD74XX */
+#ifdef CONFIG_BLK_DEV_CMD64X
+	if ((cmd64x_display_info) && (cmd64x_proc)) {
+		ent = create_proc_entry("cmd64x", 0, proc_ide_root);
+		ent->get_info = cmd64x_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+	if ((cs5530_display_info) && (cs5530_proc)) {
+		ent = create_proc_entry("cs5530", 0, proc_ide_root);
+		ent->get_info =cs5530_display_info ;
+	}
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+	if ((hpt34x_display_info) && (hpt34x_proc)) {
+		ent = create_proc_entry("hpt34x", 0, proc_ide_root);
+		ent->get_info = hpt34x_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+	if ((hpt366_display_info) && (hpt366_proc)) {
+		ent = create_proc_entry("hpt366", 0, proc_ide_root);
+		ent->get_info = hpt366_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+	if ((pdc202xx_display_info) && (pdc202xx_proc)) {
+		ent = create_proc_entry("pdc202xx", 0, proc_ide_root);
+		ent->get_info = pdc202xx_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_PDC202XX */
+#ifdef CONFIG_BLK_DEV_PIIX
+	if ((piix_display_info) && (piix_proc)) {
+		ent = create_proc_entry("piix", 0, proc_ide_root);
+		ent->get_info = piix_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_PIIX */
+#ifdef CONFIG_BLK_DEV_SVWKS
+	if ((svwks_display_info) && (svwks_proc)) {
+		ent = create_proc_entry("svwks", 0, proc_ide_root);
+                ent->get_info = svwks_display_info;
+        }
+#endif /* CONFIG_BLK_DEV_SVWKS */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	if ((sis_display_info) && (sis_proc)) {
+		ent = create_proc_entry("sis", 0, proc_ide_root);
+		ent->get_info = sis_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_SLC90E66
+	if ((slc90e66_display_info) && (slc90e66_proc)) {
+		ent = create_proc_entry("slc90e66", 0, proc_ide_root);
+		ent->get_info = slc90e66_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_SLC90E66 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	if ((via_display_info) && (via_proc)) {
+		ent = create_proc_entry("via", 0, proc_ide_root);
+		ent->get_info = via_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
 }
 
 void proc_ide_destroy(void)
@@ -693,6 +917,60 @@
 	 * 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 */
+
 	remove_proc_entry("ide/drivers", 0);
+	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
diff -urN linux-2.2.20-pristine/drivers/block/ide-tape.c linux-2.2.20/drivers/block/ide-tape.c
--- linux-2.2.20-pristine/drivers/block/ide-tape.c	Sun Mar 25 08:31:24 2001
+++ linux-2.2.20/drivers/block/ide-tape.c	Tue Nov 27 12:14:12 2001
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.15		Jul   4, 1999
+ * linux/drivers/block/ide-tape.c	Version 1.16g		Dec, 2000
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -216,7 +216,76 @@
  *                       Replace cli()/sti() with hwgroup spinlocks.
  * Ver 1.15  Mar 25 99   Fix SMP race condition by replacing hwgroup
  *                        spinlock with private per-tape spinlock.
- *                       Fix use of freed memory.
+ * Ver 1.16  Sep  1 99   Add OnStream tape support.
+ *                       Abort read pipeline on EOD.
+ *                       Wait for the tape to become ready in case it returns
+ *                        "in the process of becoming ready" on open().
+ *                       Fix zero padding of the last written block in
+ *                        case the tape block size is larger than PAGE_SIZE.
+ *                       Decrease the default disconnection time to tn.
+ * Ver 1.16e Oct  3 99   Minor fixes.
+ * Ver 1.16e1 Oct 13 99  Patches by Arnold Niessen,
+ *                          niessen@iae.nl / arnold.niessen@philips.com
+ *                   GO-1)  Undefined code in idetape_read_position
+ *				according to Gadi's email
+ *                   AJN-1) Minor fix asc == 11 should be asc == 0x11
+ *                               in idetape_issue_packet_command (did effect
+ *                               debugging output only)
+ *                   AJN-2) Added more debugging output, and
+ *                              added ide-tape: where missing. I would also
+ *				like to add tape->name where possible
+ *                   AJN-3) Added different debug_level's 
+ *                              via /proc/ide/hdc/settings
+ * 				"debug_level" determines amount of debugging output;
+ * 				can be changed using /proc/ide/hdx/settings
+ * 				0 : almost no debugging output
+ * 				1 : 0+output errors only
+ * 				2 : 1+output all sensekey/asc
+ * 				3 : 2+follow all chrdev related procedures
+ * 				4 : 3+follow all procedures
+ * 				5 : 4+include pc_stack rq_stack info
+ * 				6 : 5+USE_COUNT updates
+ *                   AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ *				from 5 to 10 minutes
+ *                   AJN-5) Changed maximum number of blocks to skip when
+ *                              reading tapes with multiple consecutive write
+ *                              errors from 100 to 1000 in idetape_get_logical_blk
+ *                   Proposed changes to code:
+ *                   1) output "logical_blk_num" via /proc
+ *                   2) output "current_operation" via /proc
+ *                   3) Either solve or document the fact that `mt rewind' is
+ *                      required after reading from /dev/nhtx to be
+ *			able to rmmod the idetape module;
+ *			Also, sometimes an application finishes but the
+ *			device remains `busy' for some time. Same cause ?
+ *                   Proposed changes to release-notes:
+ *		     4) write a simple `quickstart' section in the
+ *                      release notes; I volunteer if you don't want to
+ * 		     5) include a pointer to video4linux in the doc
+ *                      to stimulate video applications
+ *                   6) release notes lines 331 and 362: explain what happens
+ *			if the application data rate is higher than 1100 KB/s; 
+ *			similar approach to lower-than-500 kB/s ?
+ *		     7) 6.6 Comparison; wouldn't it be better to allow different 
+ *			strategies for read and write ?
+ *			Wouldn't it be better to control the tape buffer
+ *			contents instead of the bandwidth ?
+ *		     8) line 536: replace will by would (if I understand
+ *			this section correctly, a hypothetical and unwanted situation
+ *			 is being described)
+ * Ver 1.16f Dec 15 99   Change place of the secondary OnStream header frames.
+ * Ver 1.16g Nov/Dec 2000  Marcel Mol, marcel@mesa.nl
+ *			- Add idetape_onstream_mode_sense_tape_parameter_page
+ *			  function to get tape capacity in frames: tape->capacity.
+ *			- Add support for DI-50 drives( or any DI- drive).
+ *			- 'workaround' for read error/blank block arround block 3000.
+ *			- Implement Early warning for end of media for Onstream.
+ *			- Cosmetic code changes.
+ *			- idetape_position_tape should not use SKIP during
+ *			  Onstream read recovery.
+ *			- Add capacity, logical_blk_num and first/last_frame_position
+ *			  to /proc/.../settings.
+ *
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -326,7 +395,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.13"
+#define IDETAPE_VERSION "1.16g"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -341,27 +410,150 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 
+#define NO_LONGER_REQUIRED	(1)
+
+/****************************************************************************
+ *	OnStream support
+ */
+#define ONSTREAM_DEBUG		(0)
+#define OS_CONFIG_PARTITION	(0xff)
+#define OS_DATA_PARTITION	(0)
+#define OS_PARTITION_VERSION	(1)
+#define ONSTREAM_EW   300
+
+/*
+ * partition
+ */
+typedef struct os_partition_s {
+	__u8	partition_num;
+	__u8	par_desc_ver;
+	__u16	wrt_pass_cntr;
+	__u32	first_frame_addr;
+	__u32	last_frame_addr;
+	__u32	eod_frame_addr;
+} os_partition_t;
+
+/*
+ * DAT entry
+ */
+typedef struct os_dat_entry_s {
+	__u32	blk_sz;
+	__u16	blk_cnt;
+	__u8	flags;
+	__u8	reserved;
+} os_dat_entry_t;
+
+/*
+ * DAT
+ */
+#define OS_DAT_FLAGS_DATA	(0xc)
+#define OS_DAT_FLAGS_MARK	(0x1)
+
+typedef struct os_dat_s {
+	__u8		dat_sz;
+	__u8		reserved1;
+	__u8		entry_cnt;
+	__u8		reserved3;
+	os_dat_entry_t	dat_list[16];
+} os_dat_t;
+
+/*
+ * Frame types
+ */
+#define OS_FRAME_TYPE_FILL	(0)
+#define OS_FRAME_TYPE_EOD	(1 << 0)
+#define OS_FRAME_TYPE_MARKER	(1 << 1)
+#define OS_FRAME_TYPE_HEADER	(1 << 3)
+#define OS_FRAME_TYPE_DATA	(1 << 7)
+
+/*
+ * AUX
+ */
+typedef struct os_aux_s {
+	__u32		format_id;		/* hardware compability AUX is based on */
+	char		application_sig[4];	/* driver used to write this media */
+	__u32		hdwr;			/* reserved */
+	__u32		update_frame_cntr;	/* for configuration frame */
+	__u8		frame_type;
+	__u8		frame_type_reserved;
+	__u8		reserved_18_19[2];
+	os_partition_t	partition;
+	__u8		reserved_36_43[8];
+	__u32		frame_seq_num;
+	__u32		logical_blk_num_high;
+	__u32		logical_blk_num;
+	os_dat_t	dat;
+	__u8		reserved188_191[4];
+	__u32		filemark_cnt;
+	__u32		phys_fm;
+	__u32		last_mark_addr;
+	__u8		reserved204_223[20];
+
+	/*
+	 * __u8		app_specific[32];
+	 *
+	 * Linux specific fields:
+	 */
+	__u32		next_mark_addr;		/* when known, points to next marker */
+	__u8		linux_specific[28];
+
+	__u8		reserved_256_511[256];
+} os_aux_t;
+
+typedef struct os_header_s {
+	char		ident_str[8];
+	__u8		major_rev;
+	__u8		minor_rev;
+	__u8		reserved10_15[6];
+	__u8		par_num;
+	__u8		reserved1_3[3];
+	os_partition_t	partition;
+} os_header_t;
+
 /*
- *	Main Linux ide driver include file
+ *	OnStream Tape Parameters Page
  */
-#include "ide.h"
+typedef struct {
+	unsigned	page_code	:6;	/* Page code - Should be 0x2b */
+	unsigned	reserved1_6	:1;
+	unsigned	ps		:1;
+	u8		reserved2;
+	u8		density;		/* kbpi */
+	u8		reserved3,reserved4;
+	u16		segtrk;                 /* segment of per track */
+	u16		trks;                   /* tracks per tape */
+	u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
+} onstream_tape_paramtr_page_t;
 
 /*
- *	For general magnetic tape device compatibility.
+ * OnStream ADRL frame
+ */
+#define OS_FRAME_SIZE	(32 * 1024 + 512)
+#define OS_DATA_SIZE	(32 * 1024)
+#define OS_AUX_SIZE	(512)
+ 
+/*
+ * internal error codes for onstream
  */
+#define OS_PART_ERROR    2
+#define OS_WRITE_ERROR   1
+/***************** end OnStream ********************************************/
+
 #include <linux/mtio.h>
 
 /**************************** Tunable parameters *****************************/
 
+
 /*
  *	Pipelined mode parameters.
  *
@@ -376,33 +568,11 @@
  *
  *	Setting the following parameter to 0 will disable the pipelined mode.
  */
-#define IDETAPE_MIN_PIPELINE_STAGES	100
-#define IDETAPE_MAX_PIPELINE_STAGES	200
+#define IDETAPE_MIN_PIPELINE_STAGES	200
+#define IDETAPE_MAX_PIPELINE_STAGES	400
 #define IDETAPE_INCREASE_STAGES_RATE	 20
 
 /*
- *	Assuming the tape shares an interface with another device, the default
- *	behavior is to service our pending pipeline requests as soon as
- *	possible, but to gracefully postpone them in favor of the other device
- *	when the tape is busy. This has the potential to maximize our
- *	throughput and in the same time, to make efficient use of the IDE bus.
- *
- *	Note that when we transfer data to / from the tape, we co-operate with
- *	the relatively fast tape buffers and the tape will perform the
- *	actual media access in the background, without blocking the IDE
- *	bus. This means that as long as the maximum IDE bus throughput is much
- *	higher than the sum of our maximum throughput and the maximum
- *	throughput of the other device, we should probably leave the default
- *	behavior.
- *
- *	However, if it is still desired to give the other device a share even
- *	in our own (small) bus bandwidth, you can set IDETAPE_LOW_TAPE_PRIORITY
- *	to 1. This will let the other device finish *all* its pending requests
- *	before we even check if we can service our next pending request.
- */
-#define IDETAPE_LOW_TAPE_PRIORITY	0
-
-/*
  *	The following are used to debug the driver:
  *
  *	Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
@@ -445,6 +615,20 @@
 #define IDETAPE_PC_STACK		(10 + IDETAPE_MAX_PC_RETRIES)
 
 /*
+ *	Some tape drives require a long irq timeout
+ */
+#define IDETAPE_WAIT_CMD		(60*HZ)
+
+/*
+ *	The following parameter is used to select the point in the internal
+ *	tape fifo in which we will start to refill the buffer. Decreasing
+ *	the following parameter will improve the system's latency and
+ *	interactive response, while using a high value might improve sytem
+ *	throughput.
+ */
+#define IDETAPE_FIFO_THRESHOLD 		2
+
+/*
  *	DSC polling parameters.
  *
  *	Polling for DSC (a single bit in the status register) is a very
@@ -476,20 +660,6 @@
  */
  
 /*
- *	The following parameter is used to select the point in the internal
- *	tape fifo in which we will start to refill the buffer. Decreasing
- *	the following parameter will improve the system's latency and
- *	interactive response, while using a high value might improve sytem
- *	throughput.
- */
-#define IDETAPE_FIFO_THRESHOLD 		2
-
-/*
- *	Some tape drives require a long irq timeout
- */
-#define IDETAPE_WAIT_CMD		(60*HZ)
-
-/*
  *	DSC timings.
  */
 #define IDETAPE_DSC_RW_MIN		5*HZ/100	/* 50 msec */
@@ -502,6 +672,25 @@
 
 /*************************** End of tunable parameters ***********************/
 
+/*
+ *	Debugging/Performance analysis
+ *
+ *	I/O trace support
+ */
+#define USE_IOTRACE	0
+#if USE_IOTRACE
+#include <linux/io_trace.h>
+#define IO_IDETAPE_FIFO	500
+#endif
+
+/*
+ *	Read/Write error simulation
+ */
+#define SIMULATE_ERRORS			0
+
+/*
+ *	For general magnetic tape device compatibility.
+ */
 typedef enum {
 	idetape_direction_none,
 	idetape_direction_read,
@@ -525,7 +714,7 @@
 	byte *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 */
-	unsigned long flags;			/* Status/Action bit flags */
+	unsigned int flags;			/* Status/Action bit flags */
 } idetape_pc_t;
 
 /*
@@ -542,55 +731,19 @@
  *	Capabilities and Mechanical Status Page
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	u8	reserved1_67	:2;
-	u8	page_code	:6;	/* Page code - Should be 0x2a */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-	u8	page_code	:6;	/* Page code - Should be 0x2a */
-	u8	reserved1_67	:2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
+	unsigned	page_code	:6;	/* Page code - Should be 0x2a */
+	unsigned	reserved1_67	:2;
 	u8		page_length;		/* Page Length - Should be 0x12 */
 	u8		reserved2, reserved3;
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	reserved4_67	:2;
-	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
-	unsigned	reserved4_1234	:4;
-	unsigned	ro		:1;	/* Read Only Mode */
-
-	unsigned	reserved5_67	:2;
-	unsigned	qfa		:1;	/* Supports the QFA two partition formats */
-	unsigned	reserved5_4	:1;
-	unsigned	efmt		:1;	/* Supports ERASE command initiated formatting */
-	unsigned	reserved5_012	:3;
-
-	unsigned	cmprs		:1;	/* Supports data compression */
-	unsigned	ecc		:1;	/* Supports error correction */
-	unsigned	reserved6_45	:2;	/* Reserved */	
-	unsigned	eject		:1;	/* The device can eject the volume */
-	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
-	unsigned	locked		:1;	/* The volume is locked */
-	unsigned	lock		:1;	/* Supports locking the volume */
-
-	unsigned	slowb		:1;	/* The device restricts the byte count for PIO */
-	unsigned	reserved7_3_6	:4;
-	unsigned	blk1024		:1;	/* Supports 1024 bytes block size */
-	unsigned	blk512		:1;	/* Supports 512 bytes block size */
-	unsigned	reserved7_0	:1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	ro		:1;	/* Read Only Mode */
 	unsigned	reserved4_1234	:4;
 	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
 	unsigned	reserved4_67	:2;
-
 	unsigned	reserved5_012	:3;
 	unsigned	efmt		:1;	/* Supports ERASE command initiated formatting */
 	unsigned	reserved5_4	:1;
 	unsigned	qfa		:1;	/* Supports the QFA two partition formats */
 	unsigned	reserved5_67	:2;
-
 	unsigned	lock		:1;	/* Supports locking the volume */
 	unsigned	locked		:1;	/* The volume is locked */
 	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
@@ -598,14 +751,13 @@
 	unsigned	reserved6_45	:2;	/* Reserved */	
 	unsigned	ecc		:1;	/* Supports error correction */
 	unsigned	cmprs		:1;	/* Supports data compression */
-
 	unsigned	reserved7_0	:1;
 	unsigned	blk512		:1;	/* Supports 512 bytes block size */
 	unsigned	blk1024		:1;	/* Supports 1024 bytes block size */
 	unsigned	reserved7_3_6	:4;
-	unsigned	slowb		:1;	/* The device restricts the byte count for PIO */
-#endif
+	unsigned	blk32768	:1;	/* slowb - the device restricts the byte count for PIO */
 						/* transfers for slow buffer memory ??? */
+						/* Also 32768 block size in some cases */
 	u16		max_speed;		/* Maximum speed supported in KBps */
 	u8		reserved10, reserved11;
 	u16		ctl;			/* Continuous Transfer Limit in blocks */
@@ -615,15 +767,60 @@
 } idetape_capabilities_page_t;
 
 /*
+ *	Block Size Page
+ */
+typedef struct {
+	unsigned	page_code	:6;	/* Page code - Should be 0x30 */
+	unsigned	reserved1_6	:1;
+	unsigned	ps		:1;
+	u8		page_length;		/* Page Length - Should be 2 */
+	u8		reserved2;
+	unsigned	play32		:1;
+	unsigned	play32_5	:1;
+	unsigned	reserved2_23	:2;
+	unsigned	record32	:1;
+	unsigned	record32_5	:1;
+	unsigned	reserved2_6	:1;
+	unsigned	one		:1;
+} idetape_block_size_page_t;
+
+/*
  *	A pipeline stage.
  */
 typedef struct idetape_stage_s {
 	struct request rq;			/* The corresponding request */
 	struct buffer_head *bh;			/* The data buffers */
 	struct idetape_stage_s *next;		/* Pointer to the next stage */
+	os_aux_t *aux;				/* OnStream aux ptr */
 } idetape_stage_t;
 
 /*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+	unsigned	error_code	:7;	/* Current of deferred errors */
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	u8		reserved1	:8;	/* Segment Number - Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	filemark 	:1;	/* Filemark */
+	u32		information __attribute__ ((packed));
+	u8		asl;			/* Additional sense length (n-7) */
+	u32		command_specific;	/* Additional command specific information */
+	u8		asc;			/* Additional Sense Code */
+	u8		ascq;			/* Additional Sense Code Qualifier */
+	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	u8		sk_specific2;		/* Sense Key Specific */
+	u8		sk_specific3;		/* Sense Key Specific */
+	u8		pad[2];			/* Padding to 20 bytes */
+} idetape_request_sense_result_t;
+
+
+/*
  *	Most of our global data which we need to save even as we leave the
  *	driver due to an interrupt or a timer event is stored in a variable
  *	of type idetape_tape_t, defined below.
@@ -645,7 +842,7 @@
 	 *	NULL if we do not need to retry any packet command. This is
 	 *	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 */
@@ -672,10 +869,12 @@
 	unsigned long dsc_timeout;		/* Maximum waiting time */
 
 	/*
-	 *	Position information
+	 *	Read position information
 	 */
 	byte partition;
-	unsigned int block_address;		/* Current block */
+	unsigned int first_frame_position;		/* Current block */
+	unsigned int last_frame_position;
+	unsigned int blocks_in_buffer;
 
 	/*
 	 *	Last error information
@@ -716,7 +915,7 @@
 	struct buffer_head *bh;
 	char *b_data;
 	int b_count;
-	
+
 	/*
 	 *	Pipeline parameters.
 	 *
@@ -734,11 +933,125 @@
 	int pages_per_stage;
 	int excess_bh_size;			/* Wasted space in each stage */
 
-	unsigned long flags;			/* Status/Action flags */
+	unsigned int flags;			/* Status/Action flags */
 	spinlock_t spinlock;			/* protects the ide-tape queue */
+
+	/*
+	 * Measures average tape speed
+	 */
+	unsigned long avg_time;
+	int avg_size;
+	int avg_speed;
+
+	idetape_request_sense_result_t sense;	/* last sense information */
+
+	char vendor_id[10];
+	char product_id[18];
+	char firmware_revision[6];
+	int firmware_revision_num;
+
+	int door_locked;			/* the door is currently 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 */
+	struct semaphore *sem;
+	int onstream_write_error;		/* write error recovery active */
+	int header_ok;				/* header frame verified ok */
+	int linux_media;			/* reading linux-specifc media */
+	int linux_media_version;
+	char application_sig[5];		/* application signature */
+	int filemark_cnt;
+	int first_mark_addr;
+	int last_mark_addr;
+	int eod_frame_addr;
+	unsigned long cmd_start_time;
+	unsigned long max_cmd_time;
+	unsigned capacity;
+
+	/*
+	 * 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 */
+	int writes_since_buffer_fill;
+	int reads_since_buffer_fill;
+
+	/*
+	 * Limit the number of times a request can
+	 * be postponed, to avoid an infinite postpone
+	 * deadlock.
+	 */
+	int postpone_cnt;			/* request postpone count limit */
+
+	/*
+	 * Measures number of frames:
+	 *
+	 * 1. written/read to/from the driver pipeline (pipeline_head).
+	 * 2. written/read to/from the tape buffers (buffer_head).
+	 * 3. written/read by the tape to/from the media (tape_head).
+	 */
+	int pipeline_head;
+	int buffer_head;
+	int tape_head;
+	int last_tape_head;
+
+	/*
+	 * Speed control at the tape buffers input/output
+	 */
+	unsigned long insert_time;
+	int insert_size;
+	int insert_speed;
+	int max_insert_speed;
+	int measure_insert_time;
+
+	/*
+	 * Measure tape still time, in milliseconds
+	 */
+	unsigned long tape_still_time_begin;
+	int tape_still_time;
+
+	/*
+	 * 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 restart_speed_control_req;
+
+	/*
+	 * Debug_level determines amount of debugging output;
+	 * can be changed using /proc/ide/hdx/settings
+	 * 0 : almost no debugging output
+	 * 1 : 0+output errors only
+	 * 2 : 1+output all sensekey/asc
+	 * 3 : 2+follow all chrdev related procedures
+	 * 4 : 3+follow all procedures
+	 * 5 : 4+include pc_stack rq_stack info
+	 * 6 : 5+USE_COUNT updates
+	 */
+	int debug_level; 
 } idetape_tape_t;
 
 /*
+ *	Tape door status
+ */
+#define DOOR_UNLOCKED			0
+#define DOOR_LOCKED			1
+#define DOOR_EXPLICITLY_LOCKED		2
+
+/*
  *	Tape flag bits values.
  */
 #define IDETAPE_IGNORE_DSC		0
@@ -748,6 +1061,8 @@
 #define IDETAPE_DETECT_BS		4	/* Attempt to auto-detect the current user block size */
 #define IDETAPE_FILEMARK		5	/* Currently on a filemark */
 #define IDETAPE_DRQ_INTERRUPT		6	/* DRQ interrupt device */
+#define IDETAPE_READ_ERROR		7
+#define IDETAPE_PIPELINE_ACTIVE		8	/* pipeline active */
 
 /*
  *	Supported ATAPI tape drives packet commands
@@ -762,9 +1077,18 @@
 #define IDETAPE_INQUIRY_CMD		0x12
 #define IDETAPE_ERASE_CMD		0x19
 #define IDETAPE_MODE_SENSE_CMD		0x1a
+#define IDETAPE_MODE_SELECT_CMD		0x15
 #define IDETAPE_LOAD_UNLOAD_CMD		0x1b
+#define IDETAPE_PREVENT_CMD		0x1e
 #define IDETAPE_LOCATE_CMD		0x2b
 #define IDETAPE_READ_POSITION_CMD	0x34
+#define IDETAPE_READ_BUFFER_CMD		0x3c
+#define IDETAPE_SET_SPEED_CMD		0xbb
+
+/*
+ *	Some defines for the READ BUFFER command
+ */
+#define IDETAPE_RETRIEVE_FAULTY_BLOCK	6
 
 /*
  *	Some defines for the SPACE command
@@ -803,8 +1127,10 @@
 #define IDETAPE_READ_RQ			92
 #define IDETAPE_WRITE_RQ		93
 #define IDETAPE_ABORTED_WRITE_RQ	94
+#define IDETAPE_ABORTED_READ_RQ		95
+#define IDETAPE_READ_BUFFER_RQ		96
 
-#define IDETAPE_LAST_RQ			94
+#define IDETAPE_LAST_RQ			96
 
 /*
  *	A macro which can be used to check if a we support a given
@@ -826,16 +1152,6 @@
 typedef union {
 	unsigned all			:8;
 	struct {
-#if 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;	/* Buffer availability / 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 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned check		:1;	/* Error occurred */
 		unsigned idx		:1;	/* Reserved */
 		unsigned corr		:1;	/* Correctable error occurred */
@@ -844,7 +1160,6 @@
 		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 */
-#endif
 	} b;
 } idetape_status_reg_t;
 
@@ -854,19 +1169,11 @@
 typedef union {
 	unsigned all			:8;
 	struct {
-#if 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 */
-#elif 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 */
-#endif
 	} b;
 } idetape_error_reg_t;
 
@@ -876,17 +1183,10 @@
 typedef union {
 	unsigned all			:8;
 	struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA of PIO */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA of PIO */
+		unsigned dma		:1;	/* Using DMA or PIO */
 		unsigned reserved321	:3;	/* Reserved */
 		unsigned reserved654	:3;	/* Reserved (Tag Type) */
 		unsigned reserved7	:1;	/* Reserved */
-#endif
 	} b;
 } idetape_feature_reg_t;
 
@@ -896,13 +1196,8 @@
 typedef union {
 	unsigned all			:16;
 	struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned low		:8;	/* LSB */
 		unsigned high		:8;	/* MSB */
-#endif
 	} b;
 } idetape_bcount_reg_t;
 
@@ -912,15 +1207,9 @@
 typedef union {
 	unsigned all			:8;
 	struct {
-#if 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) */
-#elif 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 */
-#endif
 	} b;
 } idetape_ireason_reg_t;
 
@@ -930,19 +1219,11 @@
 typedef union {	
 	unsigned all			:8;
 	struct {
-#if 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 sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		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 */
-#endif
 	} b;
 } idetape_drivesel_reg_t;
 
@@ -952,19 +1233,11 @@
 typedef union {			
 	unsigned all			:8;
 	struct {
-#if 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 */
-#elif 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 */
-#endif
 	} b;
 } idetape_control_reg_t;
 
@@ -982,15 +1255,6 @@
  *	the ATAPI IDENTIFY DEVICE command.
  */
 struct idetape_id_gcw {	
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned protocol		:2;	/* Protocol type */
-	unsigned reserved13		:1;	/* Reserved */
-	unsigned device_type		:5;	/* Device type */
-	unsigned removable		:1;	/* Removable media */
-	unsigned drq_type		:2;	/* Command packet DRQ type */
-	unsigned reserved234		:3;	/* Reserved */
-	unsigned packet_size		:2;	/* Packet Size */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned packet_size		:2;	/* Packet Size */
 	unsigned reserved234		:3;	/* Reserved */
 	unsigned drq_type		:2;	/* Command packet DRQ type */
@@ -998,50 +1262,23 @@
 	unsigned device_type		:5;	/* Device type */
 	unsigned reserved13		:1;	/* Reserved */
 	unsigned protocol		:2;	/* Protocol type */
-#endif
 };
 
 /*
  *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-	unsigned	device_type	:5;	/* Peripheral Device Type */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	device_type	:5;	/* Peripheral Device Type */
 	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	rmb		:1;	/* Removable Medium Bit */
-	unsigned	reserved1_6t0	:7;	/* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved1_6t0	:7;	/* Reserved */
 	unsigned	rmb		:1;	/* Removable Medium Bit */
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	iso_version	:2;	/* ISO Version */
-	unsigned	ecma_version	:3;	/* ECMA Version */
-	unsigned	ansi_version	:3;	/* ANSI Version */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	ansi_version	:3;	/* ANSI Version */
 	unsigned	ecma_version	:3;	/* ECMA Version */
 	unsigned	iso_version	:2;	/* ISO Version */
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	reserved3_7	:1;	/* AENC - Reserved */
-	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
-	unsigned	reserved3_45	:2;	/* Reserved */
-	unsigned	response_format :4;	/* Response Data Format */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	response_format :4;	/* Response Data Format */
 	unsigned	reserved3_45	:2;	/* Reserved */
 	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
 	unsigned	reserved3_7	:1;	/* AENC - Reserved */
-#endif
 	u8		additional_length;	/* Additional Length (total_length-4) */
 	u8		rsv5, rsv6, rsv7;	/* Reserved */
 	u8		vendor_id[8];		/* Vendor Identification */
@@ -1056,19 +1293,11 @@
  *	READ POSITION packet command - Data Format (From Table 6-57)
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	bop		:1;	/* Beginning Of Partition */
-	unsigned	eop		:1;	/* End Of Partition */
-	unsigned	reserved0_543	:3;	/* Reserved */
-	unsigned	bpu		:1;	/* Block Position Unknown */	
-	unsigned	reserved0_10	:2;	/* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved0_10	:2;	/* Reserved */
 	unsigned	bpu		:1;	/* Block Position Unknown */	
 	unsigned	reserved0_543	:3;	/* Reserved */
 	unsigned	eop		:1;	/* End Of Partition */
 	unsigned	bop		:1;	/* Beginning Of Partition */
-#endif
 	u8		partition;		/* Partition Number */
 	u8		reserved2, reserved3;	/* Reserved */
 	u32		first_block;		/* First Block Location */
@@ -1079,65 +1308,24 @@
 } idetape_read_position_result_t;
 
 /*
- *	REQUEST SENSE packet command result - Data Format.
+ *	Follows structures which are related to the SELECT SENSE / MODE SENSE
+ *	packet commands. Those packet commands are still not supported
+ *	by ide-tape.
+ */
+#define	IDETAPE_CAPABILITIES_PAGE	0x2a
+#define IDETAPE_PARAMTR_PAGE		0x2b   /* onstream only */
+#define IDETAPE_BLOCK_SIZE_PAGE		0x30
+#define IDETAPE_BUFFER_FILLING_PAGE	0x33
+
+/*
+ *	Mode Parameter Header for the MODE SENSE packet command
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
-	unsigned	error_code	:7;	/* Current of deferred errors */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned	error_code	:7;	/* Current of deferred errors */
-	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
-#endif
-
-	u8		reserved1	:8;	/* Segment Number - Reserved */
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	filemark 	:1;	/* Filemark */
-	unsigned	eom		:1;	/* End Of Medium */
-	unsigned	ili		:1;	/* Incorrect Length Indicator */
-	unsigned	reserved2_4	:1;	/* Reserved */
-	unsigned	sense_key	:4;	/* Sense Key */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned	sense_key	:4;	/* Sense Key */
-	unsigned	reserved2_4	:1;	/* Reserved */
-	unsigned	ili		:1;	/* Incorrect Length Indicator */
-	unsigned	eom		:1;	/* End Of Medium */
-	unsigned	filemark 	:1;	/* Filemark */
-#endif
-	u32		information __attribute__ ((packed));
-	u8		asl;			/* Additional sense length (n-7) */
-	u32		command_specific;	/* Additional command specific information */
-	u8		asc;			/* Additional Sense Code */
-	u8		ascq;			/* Additional Sense Code Qualifier */
-	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
-	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
-	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
-#endif
-	u8		sk_specific2;		/* Sense Key Specific */
-	u8		sk_specific3;		/* Sense Key Specific */
-	u8		pad[2];			/* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-/*
- *	Follows structures which are related to the SELECT SENSE / MODE SENSE
- *	packet commands. Those packet commands are still not supported
- *	by ide-tape.
- */
-#define	IDETAPE_CAPABILITIES_PAGE	0x2a
-
-/*
- *	Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
-	u8		mode_data_length;	/* Length of the following data transfer */
-	u8		medium_type;		/* Medium Type */
-	u8		dsp;			/* Device Specific Parameter */
-	u8		bdl;			/* Block Descriptor Length */
-} idetape_mode_parameter_header_t;
+	u8		mode_data_length;	/* Length of the following data transfer */
+	u8		medium_type;		/* Medium Type */
+	u8		dsp;			/* Device Specific Parameter */
+	u8		bdl;			/* Block Descriptor Length */
+} idetape_mode_parameter_header_t;
 
 /*
  *	Mode Parameter Block Descriptor the MODE SENSE packet command
@@ -1155,35 +1343,16 @@
  *	The Data Compression Page, as returned by the MODE SENSE packet command.
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	ps		:1;
-	unsigned	reserved0	:1;	/* Reserved */
-	unsigned	page_code	:6;	/* Page Code - Should be 0xf */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	page_code	:6;	/* Page Code - Should be 0xf */
 	unsigned	reserved0	:1;	/* Reserved */
 	unsigned	ps		:1;
-#endif
 	u8		page_length;		/* Page Length - Should be 14 */
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	dce		:1;	/* Data Compression Enable */
-	unsigned	dcc		:1;	/* Data Compression Capable */
-	unsigned	reserved2	:6;	/* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved2	:6;	/* Reserved */
 	unsigned	dcc		:1;	/* Data Compression Capable */
 	unsigned	dce		:1;	/* Data Compression Enable */
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	dde		:1;	/* Data Decompression Enable */
-	unsigned	red		:2;	/* Report Exception on Decompression */
-	unsigned	reserved3	:5;	/* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved3	:5;	/* Reserved */
 	unsigned	red		:2;	/* Report Exception on Decompression */
 	unsigned	dde		:1;	/* Data Decompression Enable */
-#endif
 	u32		ca;			/* Compression Algorithm */
 	u32		da;			/* Decompression Algorithm */
 	u8		reserved[4];		/* Reserved */
@@ -1193,31 +1362,17 @@
  *	The Medium Partition Page, as returned by the MODE SENSE packet command.
  */
 typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	ps		:1;
-	unsigned	reserved1_6	:1;	/* Reserved */
-	unsigned	page_code	:6;	/* Page Code - Should be 0x11 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	page_code	:6;	/* Page Code - Should be 0x11 */
 	unsigned	reserved1_6	:1;	/* Reserved */
 	unsigned	ps		:1;
-#endif
 	u8		page_length;		/* Page Length - Should be 6 */
 	u8		map;			/* Maximum Additional Partitions - Should be 0 */
 	u8		apd;			/* Additional Partitions Defined - Should be 0 */
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unsigned	fdp		:1;	/* Fixed Data Partitions */
-	unsigned	sdp		:1;	/* Should be 0 */
-	unsigned	idp		:1;	/* Should be 0 */
-	unsigned	psum		:2;	/* Should be 0 */
-	unsigned	reserved4_012	:3;	/* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved4_012	:3;	/* Reserved */
 	unsigned	psum		:2;	/* Should be 0 */
 	unsigned	idp		:1;	/* Should be 0 */
 	unsigned	sdp		:1;	/* Should be 0 */
 	unsigned	fdp		:1;	/* Fixed Data Partitions */
-#endif
 	u8		mfr;			/* Medium Format Recognition */
 	u8		reserved[2];		/* Reserved */
 } idetape_medium_partition_page_t;
@@ -1239,6 +1394,24 @@
 static int idetape_chrdev_present = 0;
 
 /*
+ *      Function declarations
+ *
+ */
+static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug);
+static int idetape_chrdev_release (struct inode *inode, struct file *filp);
+static void idetape_write_release (struct inode *inode, struct file *filp);
+
+#if ONSTREAM_DEBUG || IDETAPE_DEBUG_LOG
+void idetape_pd(idetape_tape_t *tape, int debug_level, char * msg)
+{
+	if (tape->debug_level >= debug_level)
+		printk (KERN_INFO "ide-tape: %s: %s logical %u first pos %u last pos %u cur_frames %u bufblocks %u stages %u\n",
+			msg, tape->name, tape->logical_blk_num, tape->first_frame_position, tape->last_frame_position,
+			tape->cur_frames, tape->blocks_in_buffer, tape->nr_stages);
+}
+#endif
+	
+/*
  *	Too bad. The drive wants to send us data which we are not ready to accept.
  *	Just throw it away.
  */
@@ -1256,7 +1429,7 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+			printk (KERN_ERR "ide-tape: input_buffer: bh == NULL\n");
 			idetape_discard_data (drive, bcount);
 			return;
 		}
@@ -1281,13 +1454,15 @@
 	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: output_buffer: bh == NULL\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (pc->b_count, bcount);
 		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 		if (!pc->b_count) {
 			pc->bh = bh = bh->b_reqnext;
 			if (bh) {
@@ -1309,7 +1484,7 @@
 	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: update_buffers: bh == NULL\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -1324,46 +1499,6 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
- *	idetape_postpone_request postpones the current request so that
- *	ide.c will be able to service requests from another device on
- *	the same hwgroup while we are polling for DSC.
- */
-static void idetape_postpone_request (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	tape->postponed_rq = HWGROUP(drive)->rq;
-	ide_stall_queue(drive, tape->dsc_polling_frequency);
-}
-
-/*
- *	idetape_queue_pc_head generates a new packet command request in front
- *	of the request queue, before the current request, so that it will be
- *	processed immediately, on the next pass through the driver.
- *
- *	idetape_queue_pc_head is called from the request handling part of
- *	the driver (the "bottom" part). Safe storage for the request should
- *	be allocated with idetape_next_pc_storage and idetape_next_rq_storage
- *	before calling idetape_queue_pc_head.
- *
- *	Memory for those requests is pre-allocated at initialization time, and
- *	is limited to IDETAPE_PC_STACK requests. We assume that we have enough
- *	space for the maximum possible number of inter-dependent packet commands.
- *
- *	The higher level of the driver - The ioctl handler and the character
- *	device handling functions should queue request to the lower level part
- *	and wait for their completion using idetape_queue_pc_tail or
- *	idetape_queue_rw_tail.
- */
-static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
-{
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
-	rq->cmd = IDETAPE_PC_RQ1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
-}
-
-/*
  *	idetape_next_pc_storage returns a pointer to a place in which we can
  *	safely store a packet command, even though we intend to leave the
  *	driver. A storage space for a maximum of IDETAPE_PC_STACK packet
@@ -1374,7 +1509,8 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
-	printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+	if (tape->debug_level >= 5)
+		printk (KERN_INFO "ide-tape: next_pc_storage: pc_stack_index=%d\n",tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
 	if (tape->pc_stack_index==IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
@@ -1399,7 +1535,8 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_LOG
-	printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+	if (tape->debug_level >= 5)
+