]> git.pld-linux.org Git - packages/kernel.git/commitdiff
5a816be02b0b0e9bad7735809902dd70 linux-2.4.19-rc1-ac7-ide.patch
authorcieciwa <cieciwa@pld-linux.org>
Fri, 19 Jul 2002 09:02:23 +0000 (09:02 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    linux-2.4.19-rc1-ac7-ide.patch -> 1.1

linux-2.4.19-rc1-ac7-ide.patch [new file with mode: 0644]

diff --git a/linux-2.4.19-rc1-ac7-ide.patch b/linux-2.4.19-rc1-ac7-ide.patch
new file mode 100644 (file)
index 0000000..dc265fa
--- /dev/null
@@ -0,0 +1,27055 @@
+diff -Nur linux.org/drivers/ide/Config.in linux/drivers/ide/Config.in
+--- linux.org/drivers/ide/Config.in    Mon Oct  8 20:40:13 2001
++++ linux/drivers/ide/Config.in        Thu Jul 18 14:24:32 2002
+@@ -14,6 +14,7 @@
+    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
++   dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
+    define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
+    dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
+@@ -32,6 +33,9 @@
+    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
++   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
++   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
++
+    comment 'IDE chipset support/bugfixes'
+    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
+       dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
+@@ -43,27 +47,27 @@
+        if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+           bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
+           bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
+-#         bool '    Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+-          define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+           bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
++          dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
++            dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
+           define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+-#         dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
++          dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+           dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+-
+           dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
+           dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+           dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
+-          dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    CMD64X, CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
+           dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+-          dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+           if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
+              dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
+              dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
+@@ -72,23 +76,22 @@
+              dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
+              dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
+           fi
+-          dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+           dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+-          dep_bool '    PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    Pacific Digital ADMA100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
+           dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
+-          dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
++          dep_bool '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
++          dep_bool '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+           dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+-          dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
++          dep_bool '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+           dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
++          if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
++             bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
++          fi
+          fi
+-
+-#      dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
+-
+-       if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
+-          bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+-       fi
+       fi
+       if [ "$CONFIG_ALL_PPC" = "y" ]; then
+        bool '    Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+@@ -101,6 +104,9 @@
+          define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC
+        fi
+       fi
++      if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then
++       bool '  SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM
++      fi
+       if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+        dep_bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN
+        dep_bool '      ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE
+@@ -113,7 +119,7 @@
+        dep_mbool '    Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL
+       fi
+       if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-       dep_mbool '  Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
++       dep_mbool '  Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
+       fi
+       if [ "$CONFIG_ATARI" = "y" ]; then
+        dep_bool '  Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI
+@@ -173,6 +179,7 @@
+ else
+   define_bool CONFIG_DMA_NONPCI n
+ fi
++
+ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
+      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+diff -Nur linux.org/drivers/ide/Makefile linux/drivers/ide/Makefile
+--- linux.org/drivers/ide/Makefile     Tue Oct  9 18:18:37 2001
++++ linux/drivers/ide/Makefile Thu Jul 18 14:24:33 2002
+@@ -10,7 +10,7 @@
+ O_TARGET := idedriver.o
+-export-objs           := ide.o ide-features.o ataraid.o
++export-objs           := ide-taskfile.o ide.o ide-probe.o ataraid.o
+ list-multi            := ide-mod.o ide-probe-mod.o
+ obj-y         :=
+@@ -24,8 +24,10 @@
+ obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
+ obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
+ obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
++
+ obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
++ide-obj-$(CONFIG_BLK_DEV_ADMA100)     += adma100.o
+ ide-obj-$(CONFIG_BLK_DEV_AEC62XX)     += aec62xx.o
+ ide-obj-$(CONFIG_BLK_DEV_ALI14XX)     += ali14xx.o
+ ide-obj-$(CONFIG_BLK_DEV_ALI15X3)     += alim15x3.o
+@@ -43,18 +45,18 @@
+ ide-obj-$(CONFIG_BLK_DEV_HPT366)      += hpt366.o
+ ide-obj-$(CONFIG_BLK_DEV_HT6560B)     += ht6560b.o
+ ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)  += icside.o
+-ide-obj-$(CONFIG_BLK_DEV_ADMA)                += ide-adma.o
+ ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)  += ide-dma.o
++ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)  += ide-m8xx.o
+ ide-obj-$(CONFIG_BLK_DEV_IDEPCI)      += ide-pci.o
+ ide-obj-$(CONFIG_BLK_DEV_ISAPNP)      += ide-pnp.o
+ ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)    += ide-pmac.o
++ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM)   += ide-swarm.o
+ ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)     += macide.o
+ ide-obj-$(CONFIG_BLK_DEV_NS87415)     += ns87415.o
+ ide-obj-$(CONFIG_BLK_DEV_OPTI621)     += opti621.o
+ ide-obj-$(CONFIG_BLK_DEV_SVWKS)               += serverworks.o
+ ide-obj-$(CONFIG_BLK_DEV_PDC202XX)    += pdc202xx.o
+ ide-obj-$(CONFIG_BLK_DEV_PDC4030)     += pdc4030.o
+-ide-obj-$(CONFIG_BLK_DEV_PDC_ADMA)    += pdcadma.o
+ ide-obj-$(CONFIG_BLK_DEV_PIIX)                += piix.o
+ ide-obj-$(CONFIG_BLK_DEV_QD65XX)      += qd65xx.o
+ ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)  += rapide.o
+@@ -65,17 +67,16 @@
+ ide-obj-$(CONFIG_BLK_DEV_TRM290)      += trm290.o
+ ide-obj-$(CONFIG_BLK_DEV_UMC8672)     += umc8672.o
+ ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)   += via82cxxx.o
+-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)  += ide-m8xx.o
+ # The virtualised raid layers MUST come after the ide itself or bad stuff
+ # will happen.
+-obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o
++obj-$(CONFIG_BLK_DEV_ATARAID)         += ataraid.o
+ obj-$(CONFIG_BLK_DEV_ATARAID_PDC)     += pdcraid.o
+ obj-$(CONFIG_BLK_DEV_ATARAID_HPT)     += hptraid.o
+ ide-obj-$(CONFIG_PROC_FS)             += ide-proc.o
+-ide-mod-objs          := ide.o ide-features.o $(ide-obj-y)
++ide-mod-objs          := ide-taskfile.o ide.o $(ide-obj-y)
+ ide-probe-mod-objs    := ide-probe.o ide-geometry.o
+ include $(TOPDIR)/Rules.make
+diff -Nur linux.org/drivers/ide/adma100.c linux/drivers/ide/adma100.c
+--- linux.org/drivers/ide/adma100.c    Thu Jan  1 01:00:00 1970
++++ linux/drivers/ide/adma100.c        Thu Jul 18 14:24:33 2002
+@@ -0,0 +1,30 @@
++/*
++ *  linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards
++ *
++ *     Created 09 Apr 2002 by Mark Lord
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++#include <linux/mm.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++#include <linux/ide.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <asm/io.h>
++
++void __init ide_init_adma100 (ide_hwif_t *hwif)
++{
++      u32  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
++      void *v_admctl;
++
++      hwif->autodma = 0;              // not compatible with normal IDE DMA transfers
++      hwif->dma_base = 0;             // disable DMA completely
++      hwif->io_ports[IDE_CONTROL_OFFSET] += 4;        // chip needs offset of 6 instead of 2
++      v_admctl = ioremap_nocache(phy_admctl, 1024);   // map config regs, so we can turn on drive IRQs
++      *((unsigned short *)v_admctl) &= 3;             // enable aIEN; preserve PIO mode
++      iounmap(v_admctl);                              // all done; unmap config regs
++}
+diff -Nur linux.org/drivers/ide/aec62xx.c linux/drivers/ide/aec62xx.c
+--- linux.org/drivers/ide/aec62xx.c    Tue Jun 20 16:52:36 2000
++++ linux/drivers/ide/aec62xx.c        Thu Jul 18 14:24:33 2002
+@@ -1,8 +1,7 @@
+ /*
+- * linux/drivers/ide/aec62xx.c                Version 0.09    June. 9, 2000
++ * linux/drivers/ide/aec62xx.c                Version 0.11    March 27, 2002
+  *
+- * Copyright (C) 1999-2000    Andre Hedrick (andre@linux-ide.org)
+- * May be copied or modified under the terms of the GNU General Public License
++ * Copyright (C) 1999-2002    Andre Hedrick <andre@linux-ide.org>
+  *
+  */
+@@ -48,154 +47,209 @@
+ static int aec62xx_get_info(char *, char **, off_t, int);
+ extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+-static struct pci_dev *bmide_dev;
+-static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+-{
+-      char *p = buffer;
+-
+-      u32 bibma = pci_resource_start(bmide_dev, 4);
+-      u8 c0 = 0, c1 = 0;
+-      u8 art = 0, uart = 0;
++#define AEC_MAX_DEVS          5
+-      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;
+-      }
++static struct pci_dev *aec_devs[AEC_MAX_DEVS];
++static int n_aec_devs;
+-        /*
+-         * 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 ");
++#undef DEBUG_AEC_REGS
+-      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",
++static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
++{
++      char *p = buffer;
++      char *chipset_nums[] = {"error", "error", "error", "error",
++                              "error", "error", "850UF",   "860",
++                               "860R",   "865",  "865R", "error"  };
++//    char *modes_33[] = {};
++//    char *modes_34[] = {};
++      int i;
++
++      for (i = 0; i < n_aec_devs; i++) {
++              struct pci_dev *dev     = aec_devs[i];
++      //      u32 iobase              = dev->resource[4].start;
++              u32 iobase              = pci_resource_start(dev, 4);
++              u8 c0                   = inb_p(iobase + 0x02);
++              u8 c1                   = inb_p(iobase + 0x0a);
++              u8 art                  = 0;
++#ifdef DEBUG_AEC_REGS
++              u8 uart                 = 0;
++#endif /* DEBUG_AEC_REGS */
++
++              p += sprintf(p, "\nController: %d\n", i);
++              p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
++
++              p += sprintf(p, "--------------- Primary Channel "
++                              "---------------- Secondary Channel "
++                              "-------------\n");
++              (void) pci_read_config_byte(dev, 0x4a, &art);
++              p += sprintf(p, "                %sabled ",
++                      (art&0x02)?" en":"dis");
++              p += sprintf(p, "                        %sabled\n",
++                      (art&0x04)?" en":"dis");
++              p += sprintf(p, "--------------- drive0 --------- drive1 "
++                              "-------- drive0 ---------- drive1 ------\n");
++              p += sprintf(p, "DMA enabled:    %s              %s ",
++                      (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
++              p += sprintf(p, "            %s               %s\n",
++                      (c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
++
++              if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
++                      (void) pci_read_config_byte(dev, 0x54, &art);
++                      p += sprintf(p, "DMA Mode:       %s(%s)",
+                               (c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+-                              (art&0x02)?"2":(art&0x01)?"1":"0",
++                              (art&0x02)?"2":(art&0x01)?"1":"0");
++                      p += sprintf(p, "          %s(%s)",
+                               (c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+-                              (art&0x08)?"2":(art&0x04)?"1":"0",
++                              (art&0x08)?"2":(art&0x04)?"1":"0");
++                      p += sprintf(p, "         %s(%s)",
+                               (c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+-                              (art&0x20)?"2":(art&0x10)?"1":"0",
++                              (art&0x20)?"2":(art&0x10)?"1":"0");
++                      p += sprintf(p, "           %s(%s)\n",
+                               (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+                               (art&0x80)?"2":(art&0x40)?"1":"0");
+-                      (void) pci_read_config_byte(bmide_dev, 0x40, &art);
++#ifdef DEBUG_AEC_REGS
++                      (void) pci_read_config_byte(dev, 0x40, &art);
+                       p += sprintf(p, "Active:         0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x42, &art);
++                      (void) pci_read_config_byte(dev, 0x42, &art);
+                       p += sprintf(p, "             0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x44, &art);
++                      (void) pci_read_config_byte(dev, 0x44, &art);
+                       p += sprintf(p, "            0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x46, &art);
++                      (void) pci_read_config_byte(dev, 0x46, &art);
+                       p += sprintf(p, "              0x%02x\n", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x41, &art);
++                      (void) pci_read_config_byte(dev, 0x41, &art);
+                       p += sprintf(p, "Recovery:       0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x43, &art);
++                      (void) pci_read_config_byte(dev, 0x43, &art);
+                       p += sprintf(p, "             0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x45, &art);
++                      (void) pci_read_config_byte(dev, 0x45, &art);
+                       p += sprintf(p, "            0x%02x", art);
+-                      (void) pci_read_config_byte(bmide_dev, 0x47, &art);
++                      (void) pci_read_config_byte(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)",
++#endif /* DEBUG_AEC_REGS */
++              } else {
++                      /*
++                       * case PCI_DEVICE_ID_ARTOP_ATP860:
++                       * case PCI_DEVICE_ID_ARTOP_ATP860R:
++                       * case PCI_DEVICE_ID_ARTOP_ATP865:
++                       * case PCI_DEVICE_ID_ARTOP_ATP865R:
++                       */
++                      (void) pci_read_config_byte(dev, 0x44, &art);
++                      p += sprintf(p, "DMA Mode:       %s(%s)",
+                               (c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+-                              ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
++                              ((art&0x07)==0x07)?"6":
++                              ((art&0x06)==0x06)?"5":
++                              ((art&0x05)==0x05)?"4":
++                              ((art&0x04)==0x04)?"3":
++                              ((art&0x03)==0x03)?"2":
++                              ((art&0x02)==0x02)?"1":
++                              ((art&0x01)==0x01)?"0":"?");
++                      p += sprintf(p, "          %s(%s)",
+                               (c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+-                              ((art&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",
++                              ((art&0x70)==0x70)?"6":
++                              ((art&0x60)==0x60)?"5":
++                              ((art&0x50)==0x50)?"4":
++                              ((art&0x40)==0x40)?"3":
++                              ((art&0x30)==0x30)?"2":
++                              ((art&0x20)==0x20)?"1":
++                              ((art&0x10)==0x10)?"0":"?");
++                      (void) pci_read_config_byte(dev, 0x45, &art);
++                      p += sprintf(p, "         %s(%s)",
+                               (c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+-                              ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
++                              ((art&0x07)==0x07)?"6":
++                              ((art&0x06)==0x06)?"5":
++                              ((art&0x05)==0x05)?"4":
++                              ((art&0x04)==0x04)?"3":
++                              ((art&0x03)==0x03)?"2":
++                              ((art&0x02)==0x02)?"1":
++                              ((art&0x01)==0x01)?"0":"?");
++                      p += sprintf(p, "           %s(%s)\n",
+                               (c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+-                              ((art&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);
++                              ((art&0x70)==0x70)?"6":
++                              ((art&0x60)==0x60)?"5":
++                              ((art&0x50)==0x50)?"4":
++                              ((art&0x40)==0x40)?"3":
++                              ((art&0x30)==0x30)?"2":
++                              ((art&0x20)==0x20)?"1":
++                              ((art&0x10)==0x10)?"0":"?");
++#ifdef DEBUG_AEC_REGS
++                      (void) pci_read_config_byte(dev, 0x40, &art);
+                       p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x41, &art);
++                      (void) pci_read_config_byte(dev, 0x41, &art);
+                       p += sprintf(p, "             0x%02x", HIGH_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x42, &art);
++                      (void) pci_read_config_byte(dev, 0x42, &art);
+                       p += sprintf(p, "            0x%02x", HIGH_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x43, &art);
++                      (void) pci_read_config_byte(dev, 0x43, &art);
+                       p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x40, &art);
++                      (void) pci_read_config_byte(dev, 0x40, &art);
+                       p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x41, &art);
++                      (void) pci_read_config_byte(dev, 0x41, &art);
+                       p += sprintf(p, "             0x%02x", LOW_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x42, &art);
++                      (void) pci_read_config_byte(dev, 0x42, &art);
+                       p += sprintf(p, "            0x%02x", LOW_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x43, &art);
++                      (void) pci_read_config_byte(dev, 0x43, &art);
+                       p += sprintf(p, "              0x%02x\n", LOW_4(art));
+-                      (void) pci_read_config_byte(bmide_dev, 0x49, &uart);
++                      (void) pci_read_config_byte(dev, 0x49, &uart);
+                       p += sprintf(p, "reg49h = 0x%02x ", uart);
+-                      (void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
++                      (void) pci_read_config_byte(dev, 0x4a, &uart);
+                       p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+-                      break;
+-              default:
+-                      break;
++#endif /* DEBUG_AEC_REGS */
++              }
+       }
+-
+       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;
++      byte            chipset_settings;
++      byte            ultra_settings;
+ };
+-struct chipset_bus_clock_list_entry aec62xx_base [] = {
++struct chipset_bus_clock_list_entry aec6xxx_33_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    },
++      {       XFER_UDMA_6,    0x31,   0x07    },
++      {       XFER_UDMA_5,    0x31,   0x06    },
++      {       XFER_UDMA_4,    0x31,   0x05    },
++      {       XFER_UDMA_3,    0x31,   0x04    },
++      {       XFER_UDMA_2,    0x31,   0x03    },
++      {       XFER_UDMA_1,    0x31,   0x02    },
++      {       XFER_UDMA_0,    0x31,   0x01    },
++
++      {       XFER_MW_DMA_2,  0x31,   0x00    },
++      {       XFER_MW_DMA_1,  0x31,   0x00    },
++      {       XFER_MW_DMA_0,  0x0a,   0x00    },
+ #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    }
++      {       XFER_PIO_4,     0x31,   0x00    },
++      {       XFER_PIO_3,     0x33,   0x00    },
++      {       XFER_PIO_2,     0x08,   0x00    },
++      {       XFER_PIO_1,     0x0a,   0x00    },
++      {       XFER_PIO_0,     0x00,   0x00    },
++      {       0,              0x00,   0x00    }
+ };
+-extern char *ide_xfer_verbose (byte xfer_rate);
++struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      {       XFER_UDMA_6,    0x41,   0x06    },
++      {       XFER_UDMA_5,    0x41,   0x05    },
++      {       XFER_UDMA_4,    0x41,   0x04    },
++      {       XFER_UDMA_3,    0x41,   0x03    },
++      {       XFER_UDMA_2,    0x41,   0x02    },
++      {       XFER_UDMA_1,    0x41,   0x01    },
++      {       XFER_UDMA_0,    0x41,   0x01    },
++
++      {       XFER_MW_DMA_2,  0x41,   0x00    },
++      {       XFER_MW_DMA_1,  0x42,   0x00    },
++      {       XFER_MW_DMA_0,  0x7a,   0x00    },
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++      {       XFER_PIO_4,     0x41,   0x00    },
++      {       XFER_PIO_3,     0x43,   0x00    },
++      {       XFER_PIO_2,     0x78,   0x00    },
++      {       XFER_PIO_1,     0x7a,   0x00    },
++      {       XFER_PIO_0,     0x70,   0x00    },
++      {       0,              0x00,   0x00    }
++};
+ /*
+  * TO DO: active tuning and correction of cards without a bios.
+@@ -203,31 +257,73 @@
+ 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 chipset_table->chipset_settings;
+               }
+-      return 0x00;
++      return chipset_table->chipset_settings;
+ }
+ 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 chipset_table->ultra_settings;
+               }
+-      return 0x00;
++      return chipset_table->ultra_settings;
++}
++
++static byte aec62xx_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0x00;
++
++      if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
++              mode |= 0x01;
++      } else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP860) ||
++                 (dev->device == PCI_DEVICE_ID_ARTOP_ATP860R)) {
++              mode |= 0x02;
++      } else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
++                 (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
++              u32 bmide = pci_resource_start(dev, 4);
++              if (IN_BYTE(bmide+2) & 0x10)
++                      mode |= 0x04;
++              else
++                      mode |= 0x03;
++      }
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte aec62xx_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = aec62xx_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
+ }
+-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
++static int aec6210_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+-      int err                 = 0;
++      byte speed              = aec62xx_ratefilter(drive, xferspeed);
+       unsigned short d_conf   = 0x0000;
+       byte ultra              = 0x00;
+       byte ultra_conf         = 0x00;
+@@ -236,11 +332,10 @@
+       byte tmp2               = 0x00;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
+-
++      local_irq_save(flags);
+       pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+-      tmp0 = pci_bus_clock_list(speed, aec62xx_base);
++      tmp0 = pci_bus_clock_list(speed,
++              (struct chipset_bus_clock_list_entry *) dev->driver_data);
+       SPLIT_BYTE(tmp0,tmp1,tmp2);
+       MAKE_WORD(d_conf,tmp1,tmp2);
+       pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+@@ -249,23 +344,21 @@
+       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);
++      ultra_conf = pci_bus_clock_list_ultra(speed,
++              (struct chipset_bus_clock_list_entry *) dev->driver_data);
+       tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+       pci_write_config_byte(dev, 0x54, tmp2);
+-
+-      __restore_flags(flags); /* local CPU only */
+-
+-      err = ide_config_drive_speed(drive, speed);
+-      return(err);
++      local_irq_restore(flags);
++      return(ide_config_drive_speed(drive, speed));
+ }
+-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
++static int aec6260_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       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 speed              = aec62xx_ratefilter(drive, xferspeed);
+       byte drive_conf         = 0x00;
+       byte ultra_conf         = 0x00;
+       byte ultra              = 0x00;
+@@ -273,143 +366,91 @@
+       byte tmp2               = 0x00;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
+-
++      local_irq_save(flags);
+       pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+-      drive_conf = pci_bus_clock_list(speed, aec62xx_base);
++      drive_conf = pci_bus_clock_list(speed,
++              (struct chipset_bus_clock_list_entry *) dev->driver_data);
+       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);
++      ultra_conf = pci_bus_clock_list_ultra(speed,
++              (struct chipset_bus_clock_list_entry *) dev->driver_data);
+       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);
++      local_irq_restore(flags);
++      return(ide_config_drive_speed(drive, speed));
+ }
+-
+ 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));
++      switch (HWIF(drive)->pci_dev->device) {
++              case PCI_DEVICE_ID_ARTOP_ATP865:
++              case PCI_DEVICE_ID_ARTOP_ATP865R:
++              case PCI_DEVICE_ID_ARTOP_ATP860:
++              case PCI_DEVICE_ID_ARTOP_ATP860R:
++                      return ((int) aec6260_tune_chipset(drive, speed));
++              case PCI_DEVICE_ID_ARTOP_ATP850UF:
++                      return ((int) aec6210_tune_chipset(drive, speed));
++              default:
++                      return -1;
+       }
+ }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
++static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       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);
++      byte mode               = aec62xx_ratemask(drive);
++      byte speed;
+       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);
++      
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
+-      outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+-      (void) aec6260_tune_chipset(drive, speed);
++      (void) aec62xx_tune_chipset(drive, speed);
+-      return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
++      return ((int)   ((id->dma_ultra >> 11) & 15) ? 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);
+-      }
++//    return ((int) ide_dma_on);
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+@@ -427,16 +468,7 @@
+               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;
+-        }
++      (void) aec62xx_tune_chipset(drive, speed);
+ }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+@@ -453,9 +485,9 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x001F) {
++                      if (id->dma_ultra & 0x007F) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, 1);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -465,7 +497,7 @@
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+-                              dma_func = config_chipset_for_dma(drive, 0);
++                              dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+@@ -474,7 +506,7 @@
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, 0);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -494,49 +526,81 @@
+  */
+ int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++
+       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) {
++                      switch(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;
++                              case PCI_DEVICE_ID_ARTOP_ATP865:
++                              case PCI_DEVICE_ID_ARTOP_ATP865R:
++                                      printk(" AEC62XX time out ");
++#if 0
++                                      {
++                                              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;
++#endif
+                               default:
+                                       break;
+                       }
+               default:
+                       break;
+       }
++#if 0
++      {
++              ide_hwif_t *hwif        = HWIF(drive);
++              struct pci_dev *dev     = hwif->pci_dev;
++              unsigned long dma_base  = hwif->dma_base;
++              byte tmp1               = 0x00;
++              byte tmp2               = 0x00;
++
++              pci_read_config_byte(dev, 0x44, &tmp1);
++              pci_read_config_byte(dev, 0x45, &tmp2);
++              printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
++              if (hwif->channel)
++                      dma_base -= 0x08;
++              tmp1=IN_BYTE(dma_base+2) & 0x10;
++              printk(" AEC6280 133=%x ",tmp1);
++      }
++#endif
+       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)
+ {
++      int bus_speed = system_bus_clock();
++
+       if (dev->resource[PCI_ROM_RESOURCE].start) {
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+               printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+       }
++      aec_devs[n_aec_devs++] = dev;
++
+ #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 */
++      if (bus_speed <= 33)
++              dev->driver_data = (void *) aec6xxx_33_base;
++      else
++              dev->driver_data = (void *) aec6xxx_34_base;
++
+       return dev->irq;
+ }
+@@ -551,32 +615,56 @@
+ void __init ide_init_aec62xx (ide_hwif_t *hwif)
+ {
+-#ifdef CONFIG_AEC62XX_TUNING
++      hwif->autodma = 0;
+       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;
++
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &aec62xx_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-#endif /* CONFIG_AEC62XX_TUNING */
++
++
+ }
+ void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+ {
+-#ifdef CONFIG_AEC62XX_TUNING
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte reg54h             = 0;
+       unsigned long flags;
+-      byte reg54h = 0;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      spin_lock_irqsave(&io_request_lock, flags);
++      pci_read_config_byte(dev, 0x54, &reg54h);
++      pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      ide_setup_dma(hwif, dmabase, 8);
++}
+-      pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+-      pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
++extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+-      __restore_flags(flags); /* local CPU only */
+-#endif /* CONFIG_AEC62XX_TUNING */
+-      ide_setup_dma(hwif, dmabase, 8);
++void __init fixup_device_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      u32 bar4reg = pci_resource_start(dev, 4);
++
++      if (IN_BYTE(bar4reg+2) & 0x10) {
++              strcpy(d->name, "AEC6880");
++              if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
++                      strcpy(d->name, "AEC6880R");
++      } else {
++              strcpy(d->name, "AEC6280");
++              if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
++                      strcpy(d->name, "AEC6280R");
++      }
++
++      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 -Nur linux.org/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c
+--- linux.org/drivers/ide/ali14xx.c    Mon Jul 16 01:22:23 2001
++++ linux/drivers/ide/ali14xx.c        Thu Jul 18 14:24:33 2002
+@@ -95,7 +95,7 @@
+ static inline byte inReg (byte reg)
+ {
+       outb_p(reg, regPort);
+-      return inb(dataPort);
++      return IN_BYTE(dataPort);
+ }
+ /*
+@@ -137,15 +137,14 @@
+       /* stuff timing parameters into controller registers */
+       driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(regOn, basePort);
+       outReg(param1, regTab[driveNum].reg1);
+       outReg(param2, regTab[driveNum].reg2);
+       outReg(param3, regTab[driveNum].reg3);
+       outReg(param4, regTab[driveNum].reg4);
+       outb_p(regOff, basePort);
+-      restore_flags(flags);   /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ /*
+@@ -157,19 +156,18 @@
+       byte t;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       for (i = 0; i < ALI_NUM_PORTS; ++i) {
+               basePort = ports[i];
+-              regOff = inb(basePort);
++              regOff = IN_BYTE(basePort);
+               for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+                       outb_p(regOn, basePort);
+-                      if (inb(basePort) == regOn) {
++                      if (IN_BYTE(basePort) == regOn) {
+                               regPort = basePort + 4;
+                               dataPort = basePort + 8;
+                               t = inReg(0) & 0xf0;
+                               outb_p(regOff, basePort);
+-                              __restore_flags(flags); /* local CPU only */
++                              local_irq_restore(flags);
+                               if (t != 0x50)
+                                       return 0;
+                               return 1;  /* success */
+@@ -177,7 +175,7 @@
+               }
+               outb_p(regOff, basePort);
+       }
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       return 0;
+ }
+@@ -189,15 +187,14 @@
+       byte t;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       outb_p(regOn, basePort);
+       for (p = initData; p->reg != 0; ++p)
+               outReg(p->data, p->reg);
+       outb_p(0x01, regPort);
+-      t = inb(regPort) & 0x01;
++      t = IN_BYTE(regPort) & 0x01;
+       outb_p(regOff, basePort);
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       return t;
+ }
+diff -Nur linux.org/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c
+--- linux.org/drivers/ide/alim15x3.c   Mon Jul 16 01:22:23 2001
++++ linux/drivers/ide/alim15x3.c       Thu Jul 18 14:24:33 2002
+@@ -89,8 +89,8 @@
+        * at that point bibma+0x2 et bibma+0xa are byte
+        * registers to investigate:
+        */
+-      c0 = inb((unsigned short)bibma + 0x02);
+-      c1 = inb((unsigned short)bibma + 0x0a);
++      c0 = IN_BYTE((unsigned short)bibma + 0x02);
++      c1 = IN_BYTE((unsigned short)bibma + 0x0a);
+       p += sprintf(p,
+               "\n                                Ali M15x3 Chipset.\n");
+@@ -112,16 +112,20 @@
+               (reg53h & 0x80) ? " OVERRD." : "." );
+       p += sprintf(p,
+-              "-------------------primary channel-------------------secondary channel---------\n\n");
++              "-------------------primary channel"
++              "-------------------secondary channel"
++              "---------\n\n");
+       pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+       p += sprintf(p,
+-              "channel status:       %s                               %s\n",
++              "channel status:       %s"
++              "                               %s\n",
+               (reg53h & 0x20) ? "On " : "Off",
+               (reg53h & 0x10) ? "On " : "Off" );
+       p += sprintf(p,
+-              "both channels togth:  %s                               %s\n",
++              "both channels togth:  %s"
++              "                               %s\n",
+               (c0&0x80) ? "No " : "Yes",
+               (c1&0x80) ? "No " : "Yes" );
+@@ -134,24 +138,29 @@
+       pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+       p += sprintf(p,
+-              "Add. Setup Timing:    %dT                                %dT\n",
++              "Add. Setup Timing:    %dT"
++              "                                %dT\n",
+               (reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+               (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+       pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+       p += sprintf(p,
+-              "Command Act. Count:   %dT                                %dT\n"
+-              "Command Rec. Count:   %dT                               %dT\n\n",
++              "Command Act. Count:   %dT"
++              "                                %dT\n"
++              "Command Rec. Count:   %dT"
++              "                               %dT\n\n",
+               (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+               (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+               (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+               (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+       p += sprintf(p,
+-              "----------------drive0-----------drive1------------drive0-----------drive1------\n\n");
++              "----------------drive0-----------drive1"
++              "------------drive0-----------drive1------\n\n");
+       p += sprintf(p,
+-              "DMA enabled:      %s              %s               %s              %s\n",
++              "DMA enabled:      %s              %s"
++              "               %s              %s\n",
+               (c0&0x20) ? "Yes" : "No ",
+               (c0&0x40) ? "Yes" : "No ",
+               (c1&0x20) ? "Yes" : "No ",
+@@ -159,7 +168,8 @@
+       pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+-      q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
++      q = "FIFO threshold:   %2d Words         %2d Words"
++              "          %2d Words         %2d Words\n";
+       if (rev < 0xc1) {
+               if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+                       p += sprintf(p, q, 8, 8, 8, 8);
+@@ -180,7 +190,8 @@
+ #if 0
+       p += sprintf(p, 
+-              "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
++              "FIFO threshold:   %2d Words         %2d Words"
++              "          %2d Words         %2d Words\n",
+               (reg5xh & 0x03) + 12,
+               ((reg5xh & 0x30)>>4) + 12,
+               (reg5yh & 0x03) + 12,
+@@ -200,9 +211,12 @@
+       pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+       p += sprintf(p,/*
+-              "------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
+-              "Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
+-              "Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
++              "------------------drive0-----------drive1"
++              "------------drive0-----------drive1------\n")*/
++              "Dt RW act. Cnt    %2dT              %2dT"
++              "               %2dT              %2dT\n"
++              "Dt RW rec. Cnt    %2dT              %2dT"
++              "               %2dT              %2dT\n\n",
+               (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+               (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+               (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+@@ -213,13 +227,16 @@
+               (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+       p += sprintf(p,
+-              "-----------------------------------UDMA Timings--------------------------------\n\n");
++              "-----------------------------------UDMA Timings"
++              "--------------------------------\n\n");
+       pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+       p += sprintf(p,
+-              "UDMA:             %s               %s                %s               %s\n"
+-              "UDMA timings:     %s             %s              %s             %s\n\n",
++              "UDMA:             %s               %s"
++              "                %s               %s\n"
++              "UDMA timings:     %s             %s"
++              "              %s             %s\n\n",
+               (reg5xh & 0x08) ? "OK" : "No",
+               (reg5xh & 0x80) ? "OK" : "No",
+               (reg5yh & 0x08) ? "OK" : "No",
+@@ -248,7 +265,7 @@
+       byte s_clc, a_clc, r_clc;
+       unsigned long flags;
+       int bus_speed = system_bus_clock();
+-      int port = hwif->index ? 0x5c : 0x58;
++      int port = hwif->channel ? 0x5c : 0x58;
+       int portFIFO = hwif->channel ? 0x55 : 0x54;
+       byte cd_dma_fifo = 0;
+@@ -272,21 +289,20 @@
+               if (r_clc >= 16)
+                       r_clc = 0;
+       }
+-      __save_flags(flags);
+-      __cli();
++      local_irq_save(flags);
+       
+       /* 
+        * PIO mode => ATA FIFO on, ATAPI FIFO off
+        */
+       pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+       if (drive->media==ide_disk) {
+-              if (hwif->index) {
++              if (hwif->channel) {
+                       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) {
++              if (hwif->channel) {
+                       pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+               } else {
+                       pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+@@ -295,7 +311,7 @@
+       
+       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);
++      local_irq_restore(flags);
+       /*
+        * setup   active  rec
+@@ -309,14 +325,79 @@
+ }
+-static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
++static byte ali15x3_can_ultra (ide_drive_t *drive)
+ {
+-      ide_hwif_t *hwif = HWIF(drive);
++#ifndef CONFIG_WDC_ALI15X3
++      struct hd_driveid *id   = drive->id;
++#endif /* CONFIG_WDC_ALI15X3 */
++
++      if (m5229_revision <= 0x20) {
++              return 0;
++      } else if ((m5229_revision < 0xC2) &&
++#ifndef CONFIG_WDC_ALI15X3
++                 ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
++                  (drive->media!=ide_disk))) {
++#else /* CONFIG_WDC_ALI15X3 */
++                 (drive->media!=ide_disk)) {
++#endif /* CONFIG_WDC_ALI15X3 */
++              return 0;
++      } else {
++              return 1;
++      }
++}
++
++static byte ali15x3_ratemask (ide_drive_t *drive)
++{
++//    struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0x00;
++      byte can_ultra          = ali15x3_can_ultra(drive);
++
++      if ((m5229_revision >= 0xC4) && (can_ultra)) {
++              mode |= 0x03;
++      } else if ((m5229_revision >= 0xC2) && (can_ultra)) {
++              mode |= 0x02;
++      } else if (can_ultra) {
++              mode |= 0x01;
++      } else {
++              return (mode &= ~0xFF);
++      }
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte ali15x3_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = ali15x3_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
++static int ali15x3_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
++      byte speed              = ali15x3_ratefilter(drive, xferspeed);
+       byte unit               = (drive->select.b.unit & 0x01);
+       byte tmpbyte            = 0x00;
+-      int m5229_udma          = hwif->channel? 0x57 : 0x56;
+-      int err                 = 0;
++      int m5229_udma          = (hwif->channel) ? 0x57 : 0x56;
+       if (speed < XFER_UDMA_0) {
+               byte ultra_enable       = (unit) ? 0x7f : 0xf7;
+@@ -326,18 +407,11 @@
+               pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+               tmpbyte &= ultra_enable;
+               pci_write_config_byte(dev, m5229_udma, tmpbyte);
+-      }
+-
+-      err = ide_config_drive_speed(drive, speed);
++              if (speed < XFER_SW_DMA_0)
++                      ali15x3_tune_drive(drive, speed);
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (speed >= XFER_SW_DMA_0) {
+-              unsigned long dma_base = hwif->dma_base;
+-
+-              outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+-      }
+-
+-      if (speed >= XFER_UDMA_0) {
++      } else {
+               pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+               tmpbyte &= (0x0f << ((1-unit) << 2));
+               /*
+@@ -350,89 +424,58 @@
+                       tmpbyte |= 1;
+                       pci_write_config_byte(dev, 0x4b, tmpbyte);
+               }
+-      }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-
+-      drive->current_speed = speed;
+-
+-      return (err);
+-}
+-
+-static void config_chipset_for_pio (ide_drive_t *drive)
+-{
+-      ali15x3_tune_drive(drive, 5);
++      }
++      return (ide_config_drive_speed(drive, speed));
+ }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
++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);
+-      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);
++      byte mode               = ali15x3_ratemask(drive);
++      byte speed              = 0;
++
++      switch(mode) {
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
+       (void) ali15x3_tune_chipset(drive, speed);
+-
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
+-
+-      rval = (int)(   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
++//    return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
++      return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+-
+-      return rval;
+-}
+-
+-static byte ali15x3_can_ultra (ide_drive_t *drive)
+-{
+-#ifndef CONFIG_WDC_ALI15X3
+-      struct hd_driveid *id   = drive->id;
+-#endif /* CONFIG_WDC_ALI15X3 */
+-
+-      if (m5229_revision <= 0x20) {
+-              return 0;
+-      } else if ((m5229_revision < 0xC2) &&
+-#ifndef CONFIG_WDC_ALI15X3
+-                 ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+-                  (drive->media!=ide_disk))) {
+-#else /* CONFIG_WDC_ALI15X3 */
+-                 (drive->media!=ide_disk)) {
+-#endif /* CONFIG_WDC_ALI15X3 */
+-              return 0;
+-      } else {
+-              return 1;
+-      }
+ }
+ static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+@@ -440,11 +483,12 @@
+       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);
++      drive->init_speed = 0;
++
+       if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -453,9 +497,9 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x003F) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, can_ultra_dma);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -465,7 +509,7 @@
+                       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);
++                              dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+@@ -474,7 +518,7 @@
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, can_ultra_dma);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -484,7 +528,7 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              config_chipset_for_pio(drive);
++              hwif->tuneproc(drive, 5);
+       }
+       return hwif->dmaproc(dma_func, drive);
+ }
+@@ -495,7 +539,8 @@
+               case ide_dma_check:
+                       return ali15x3_config_drive_for_dma(drive);
+               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:
+@@ -505,10 +550,17 @@
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
++#define ALI_INIT_CODE_TEST
++
+ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
+ {
+       unsigned long fixdma_base = pci_resource_start(dev, 4);
++#ifdef ALI_INIT_CODE_TEST
++      unsigned long flags;
++      byte tmpbyte;
++#endif /* ALI_INIT_CODE_TEST */
++
+       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);
+@@ -521,9 +573,9 @@
+               /*
+                * enable DMA capable bit, and "not" simplex only
+                */
+-              outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
++              OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
+-              if (inb(fixdma_base+2) & 0x80)
++              if (IN_BYTE(fixdma_base+2) & 0x80)
+                       printk("%s: simplex device: DMA will fail!!\n", name);
+       }
+@@ -535,6 +587,55 @@
+       }
+ #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
++#ifdef ALI_INIT_CODE_TEST
++      local_irq_save(flags);
++
++      if (m5229_revision >= 0xC2) {
++              /*
++               * 1543C-B?, 1535, 1535D, 1553
++               * Note 1: not all "motherboard" support this detection
++               * Note 2: if no udma 66 device, the detection may "error".
++               *         but in this case, we will not set the device to
++               *         ultra 66, the detection result is not important
++               */
++
++              /*
++               * enable "Cable Detection", m5229, 0x4b, bit3
++               */
++              pci_read_config_byte(dev, 0x4b, &tmpbyte);
++              pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
++
++              /*
++               * set south-bridge's enable bit, m1533, 0x79
++               */
++              pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
++              if (m5229_revision == 0xC2) {
++                      /*
++                       * 1543C-B0 (m1533, 0x79, bit 2)
++                       */
++                      pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
++              } else if (m5229_revision >= 0xC3) {
++                      /*
++                       * 1553/1535 (m1533, 0x79, bit 1)
++                       */
++                      pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
++              }
++      } 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);
++      }
++
++      local_irq_save(flags);
++#endif /* ALI_INIT_CODE_TEST */
++
+       return 0;
+ }
+@@ -552,10 +653,10 @@
+       unsigned long flags;
+       byte tmpbyte;
+-      __save_flags(flags);
+-      __cli();
++      local_irq_save(flags);
+       if (m5229_revision >= 0xC2) {
++#ifndef ALI_INIT_CODE_TEST
+               /*
+                * 1543C-B?, 1535, 1535D, 1553
+                * Note 1: not all "motherboard" support this detection
+@@ -585,6 +686,7 @@
+                        */
+                       pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+               }
++#endif /* ALI_INIT_CODE_TEST */
+               /*
+                * Ultra66 cable detection (from Host View)
+                * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+@@ -605,6 +707,7 @@
+                */
+               ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+       } else {
++#ifndef ALI_INIT_CODE_TEST
+               /*
+                * revision 0x20 (1543-E, 1543-F)
+                * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+@@ -615,6 +718,7 @@
+                * clear bit 7
+                */
+               pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
++#endif /* ALI_INIT_CODE_TEST */
+               /*
+                * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+                */
+@@ -633,7 +737,7 @@
+       pci_write_config_byte(dev, 0x53, tmpbyte);
+-      __restore_flags(flags);
++      local_irq_restore(flags);
+       return(ata66);
+ }
+@@ -657,7 +761,8 @@
+               ideic = ideic & 0x03;
+               /* get IRQ for IDE Controller */
+-              if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
++              if ((hwif->channel && ideic == 0x03) ||
++                  (!hwif->channel && !ideic)) {
+                       /*
+                        * get SIRQ1 routing table
+                        */
+@@ -675,24 +780,26 @@
+       }
+ #endif /* CONFIG_SPARC64 */
++      hwif->autodma = 0;
+       hwif->tuneproc = &ali15x3_tune_drive;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+       hwif->speedproc = &ali15x3_tune_chipset;
++      if (!hwif->dma_base)
++              return;
++
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
++      if (m5229_revision >= 0x20) {
+               /*
+                * M1543C or newer for DMAing
+                */
+               hwif->dmaproc = &ali15x3_dmaproc;
+-              hwif->autodma = 1;
++#ifdef CONFIG_IDEDMA_AUTO
++              if (!noautodma)
++                      hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+       }
+-
+-      if (noautodma)
+-              hwif->autodma = 0;
+-#else
+-      hwif->autodma = 0;
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
+@@ -703,3 +810,16 @@
+       }
+       ide_setup_dma(hwif, dmabase, 8);
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_ali15x3 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      if (dev->resource[0].start != 0x01F1)
++              ide_register_xp_fix(dev);
++
++      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 -Nur linux.org/drivers/ide/amd74xx.c linux/drivers/ide/amd74xx.c
+--- linux.org/drivers/ide/amd74xx.c    Mon Aug 13 23:56:19 2001
++++ linux/drivers/ide/amd74xx.c        Thu Jul 18 14:24:33 2002
+@@ -34,7 +34,6 @@
+ static int amd74xx_get_info(char *, char **, off_t, int);
+ extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+ static struct pci_dev *bmide_dev;
+ static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
+@@ -47,16 +46,22 @@
+        * 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);
++      c0 = IN_BYTE((unsigned short)bibma + 0x02);
++      c1 = IN_BYTE((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",
++      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",
++      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");
+@@ -69,39 +74,85 @@
+ byte amd74xx_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
++static int amd74xx_mode5_check (struct pci_dev *dev)
++{
++      switch(dev->device) {
++              case PCI_DEVICE_ID_AMD_VIPER_7411:
++              case PCI_DEVICE_ID_AMD_VIPER_7441:
++                      return 1;
++              default:
++                      return 0;
++      }
++}
+ static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
+ {
+       unsigned int class_rev;
+-      if (dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
+-              return 0;
++      if (amd74xx_mode5_check(dev))
++              return 1;
+       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)
++static int amd74xx_swdma_error (ide_drive_t *drive)
+ {
+       printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
+       return 0;
+ }
++static byte amd74xx_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
++      byte mode = 0x00;
++
++        switch(dev->device) {
++              case PCI_DEVICE_ID_AMD_VIPER_7441:
++              case PCI_DEVICE_ID_AMD_VIPER_7411:      { mode |= 0x03; break; }
++              case PCI_DEVICE_ID_AMD_VIPER_7409:      { mode |= 0x02; break; }
++              case PCI_DEVICE_ID_AMD_COBRA_7401:      { mode |= 0x01; break; }
++              default:
++                      return (mode &= ~0xFF);
++      }
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte amd74xx_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = amd74xx_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      // while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
+ /*
+  * Here is where all the hard work goes to program the chipset.
+- *
+  */
+-static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed)
++static int amd74xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       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 speed              = amd74xx_ratefilter(drive, xferspeed);
+       byte drive_pci          = 0x00;
+       byte drive_pci2         = 0x00;
+       byte ultra_timing       = 0x00;
+@@ -121,32 +172,19 @@
+       pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
+       pci_read_config_byte(dev, 0x4c, &pio_timing);
+-#ifdef DEBUG
+-      printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+-              drive->name, ultra_timing, dma_pio_timing, pio_timing);
+-#endif
+-
+       ultra_timing    &= ~0xC7;
+       dma_pio_timing  &= ~0xFF;
+       pio_timing      &= ~(0x03 << drive->dn);
+-#ifdef DEBUG
+-      printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+-              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:
+-#undef __CAN_MODE_5
+-#ifdef __CAN_MODE_5
+                       ultra_timing |= 0x46;
+                       dma_pio_timing |= 0x20;
+                       break;
+-#else
+-                      printk("%s: setting to mode 4, driver problems in mode 5.\n", drive->name);
+-                      speed = XFER_UDMA_4;
+-#endif /* __CAN_MODE_5 */
+               case XFER_UDMA_4:
+                       ultra_timing |= 0x45;
+                       dma_pio_timing |= 0x20;
+@@ -212,75 +250,19 @@
+       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(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
+-              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;
++      return (ide_config_drive_speed(drive, speed));
+ }
+ static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
+ {
+       byte speed;
++      pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       switch(pio) {
+               case 4:         speed = XFER_PIO_4;break;
+               case 3:         speed = XFER_PIO_3;break;
+@@ -299,52 +281,69 @@
+  */
+ 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) ? 1 : 0;
+-      byte speed              = 0x00;
++      struct hd_driveid *id   = drive->id;
++      byte mode               = amd74xx_ratemask(drive);
++      byte swdma              = amd74xx_swdma_check(HWIF(drive)->pci_dev);
++      byte speed              = 0;
+       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);
++      amd74xx_tune_drive(drive, 5);
++      
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if ((id->dma_1word & 0x0004) && (swdma))
++                              { speed = XFER_SW_DMA_2; break; }
++                      if ((id->dma_1word & 0x0002) && (swdma))
++                              { speed = XFER_SW_DMA_1; break; }
++                      if ((id->dma_1word & 0x0001) && (swdma))
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
+       (void) amd74xx_tune_chipset(drive, 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 :
++//    return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
++      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) && (swdma)) ? 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;
++      struct hd_driveid *id   = drive->id;
++      ide_hwif_t *hwif        = HWIF(drive);
+       ide_dma_action_t dma_func = ide_dma_on;
+-      if (id && (id->capability & 1) && HWIF(drive)->autodma) {
++      drive->init_speed = 0;
++
++      if (id && (id->capability & 1) && hwif->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       dma_func = ide_dma_off;
+@@ -352,7 +351,7 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x003F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+@@ -385,8 +384,7 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-
+-              config_chipset_for_pio(drive);
++              amd74xx_tune_drive(drive, 5);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
+@@ -424,9 +422,9 @@
+               /*
+                * enable DMA capable bit, and "not" simplex only
+                */
+-              outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
++              OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
+-              if (inb(fixdma_base+2) & 0x80)
++              if (IN_BYTE(fixdma_base+2) & 0x80)
+                       printk("%s: simplex device: DMA will fail!!\n", name);
+       }
+ #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+@@ -442,17 +440,43 @@
+ unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
+ {
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte cable_80_pin[2]    = { 0, 0 };
++      byte ata66              = 0;
++      byte tmpbyte;
++
++      /*
++       * Ultra66 cable detection (from Host View)
++       * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
++       */
++      pci_read_config_byte(dev, 0x42, &tmpbyte);
++
++      /*
++       * 0x42, bit0 is 1 => primary channel
++       * has 80-pin (from host view)
++       */
++      if (tmpbyte & 0x01) cable_80_pin[0] = 1;
++
++      /*
++       * 0x42, bit2 is 1 => secondary channel
++       * has 80-pin (from host view)
++       */
++      if (tmpbyte & 0x04) cable_80_pin[1] = 1;
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_AMD_VIPER_7441:
++              case PCI_DEVICE_ID_AMD_VIPER_7411:
++                      ata66 = (hwif->channel) ?
++                              cable_80_pin[1] :
++                              cable_80_pin[0];
++              default:
++                      break;
++      }
+ #ifdef CONFIG_AMD74XX_OVERRIDE
+-      byte ata66 = 1;
++      return(1);
+ #else
+-      byte ata66 = 0;
++      return (unsigned int) ata66;
+ #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)
+@@ -460,22 +484,19 @@
+       hwif->tuneproc = &amd74xx_tune_drive;
+       hwif->speedproc = &amd74xx_tune_chipset;
+-#ifndef CONFIG_BLK_DEV_IDEDMA
+-      hwif->drives[0].autotune = 1;
+-      hwif->drives[1].autotune = 1;
+-      hwif->autodma = 0;
+-      return;
+-#else
+-
+-      if (hwif->dma_base) {
+-              hwif->dmaproc = &amd74xx_dmaproc;
+-              if (!noautodma)
+-                      hwif->autodma = 1;
+-      } else {
+-              hwif->autodma = 0;
++      if (!hwif->dma_base) {
+               hwif->drives[0].autotune = 1;
+               hwif->drives[1].autotune = 1;
++              hwif->autodma = 0;
++              return;
+       }
++
++#ifndef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &amd74xx_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
+@@ -483,3 +504,16 @@
+ {
+       ide_setup_dma(hwif, dmabase, 8);
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_amd74xx (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      if (dev->resource[0].start != 0x01F1)
++              ide_register_xp_fix(dev);
++
++      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 -Nur linux.org/drivers/ide/ataraid.c linux/drivers/ide/ataraid.c
+--- linux.org/drivers/ide/ataraid.c    Thu Oct 25 22:58:35 2001
++++ linux/drivers/ide/ataraid.c        Thu Jul 18 14:24:33 2002
+@@ -123,8 +123,7 @@
+               ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+               if (!ptr) {
+                       __set_current_state(TASK_RUNNING);
+-                      current->policy |= SCHED_YIELD;
+-                      schedule();             
++                      yield();
+               }
+       }
+       return ptr;
+@@ -139,8 +138,7 @@
+               ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+               if (!ptr) {
+                       __set_current_state(TASK_RUNNING);
+-                      current->policy |= SCHED_YIELD;
+-                      schedule();             
++                      yield();
+               }
+       }
+       return ptr;
+diff -Nur linux.org/drivers/ide/buddha.c linux/drivers/ide/buddha.c
+--- linux.org/drivers/ide/buddha.c     Thu Oct 25 22:53:47 2001
++++ linux/drivers/ide/buddha.c Thu Jul 18 14:23:00 2002
+@@ -1,10 +1,10 @@
+ /*
+  *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+  *
+- *    Copyright (C) 1997 by Geert Uytterhoeven
++ *    Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+  *
+- *  This driver was written by based on the specifications in README.buddha and
+- *  the X-Surf info from Inside_XSurf.txt available at 
++ *  This driver was written based on the specifications in README.buddha and
++ *  the X-Surf info from Inside_XSurf.txt available at
+  *  http://www.jschoenfeld.com
+  *
+  *  This file is subject to the terms and conditions of the GNU General Public
+@@ -52,7 +52,7 @@
+     BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+ };
+-static const u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
++static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+      XSURF_BASE1, XSURF_BASE2
+ };
+@@ -97,7 +97,7 @@
+     BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+ };
+-static const int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
++static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+     XSURF_IRQ1, XSURF_IRQ2
+ };
+@@ -108,8 +108,9 @@
+      *  Board information
+      */
+-enum BuddhaType_Enum {BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF};
+-typedef enum BuddhaType_Enum BuddhaType;
++typedef enum BuddhaType_Enum {
++    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
++} BuddhaType;
+     /*
+@@ -175,15 +176,20 @@
+                       if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+                               continue;
+                       if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
++                              goto fail_base2;
++                      if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
++                              release_mem_region(board+XSURF_BASE2, 0x1000);
++fail_base2:
++                              release_mem_region(board+XSURF_BASE1, 0x1000);
+                               continue;
+-                      if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE"))
+-                              continue;
++                      }
+               }         
+               buddha_board = ZTWO_VADDR(board);
+               
+               /* write to BUDDHA_IRQ_MR to enable the board IRQ */
+               /* X-Surf doesn't have this.  IRQs are always on */
+-              if(type != BOARD_XSURF) *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0;
++              if (type != BOARD_XSURF)
++                      z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+               
+               for(i=0;i<buddha_num_hwifs;i++) {
+                       if(type != BOARD_XSURF) {
+diff -Nur linux.org/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c
+--- linux.org/drivers/ide/cmd640.c     Sat Feb 17 01:02:36 2001
++++ linux/drivers/ide/cmd640.c Thu Jul 18 14:24:33 2002
+@@ -217,11 +217,10 @@
+ {
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
+-      outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
++      spin_lock_irqsave(&io_request_lock, flags);
++      outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+       outb_p(val, (reg & 3) | 0xcfc);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ static byte get_cmd640_reg_pci1 (unsigned short reg)
+@@ -229,11 +228,10 @@
+       byte b;
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
+-      outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
++      spin_lock_irqsave(&io_request_lock, flags);
++      outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+       b = inb_p((reg & 3) | 0xcfc);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return b;
+ }
+@@ -243,12 +241,11 @@
+ {
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(0x10, 0xcf8);
+       outb_p(val, cmd640_key + reg);
+       outb_p(0, 0xcf8);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ static byte get_cmd640_reg_pci2 (unsigned short reg)
+@@ -256,12 +253,11 @@
+       byte b;
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(0x10, 0xcf8);
+       b = inb_p(cmd640_key + reg);
+       outb_p(0, 0xcf8);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return b;
+ }
+@@ -271,11 +267,10 @@
+ {
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(reg, cmd640_key);
+       outb_p(val, cmd640_key + 4);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ static byte get_cmd640_reg_vlb (unsigned short reg)
+@@ -283,11 +278,10 @@
+       byte b;
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(reg, cmd640_key);
+       b = inb_p(cmd640_key + 4);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return b;
+ }
+@@ -315,7 +309,9 @@
+ {
+       get_cmd640_reg = get_cmd640_reg_pci1;
+       put_cmd640_reg = put_cmd640_reg_pci1;
+-      for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
++      for (cmd640_key = 0x80000000;
++           cmd640_key <= 0x8000f800;
++           cmd640_key += 0x800) {
+               if (match_pci_cmd640_device())
+                       return 1; /* success */
+       }
+@@ -364,8 +360,7 @@
+ {
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);        /* select drive0 */
+       udelay(100);
+@@ -373,11 +368,11 @@
+               outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+               udelay(100);
+               if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+-                      restore_flags(flags);
++                      spin_unlock_irqrestore(&io_request_lock, flags);
+                       return 0; /* nothing responded */
+               }
+       }
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return 1; /* success */
+ }
+@@ -458,8 +453,7 @@
+       byte b;
+       unsigned long flags;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       b = get_cmd640_reg(reg);
+       if (mode) {     /* want prefetch on? */
+ #if CMD640_PREFETCH_MASKS
+@@ -475,7 +469,7 @@
+               b |= prefetch_masks[index];     /* disable prefetch */
+       }
+       put_cmd640_reg(reg, b);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ /*
+@@ -576,8 +570,7 @@
+       /*
+        * Now that everything is ready, program the new timings
+        */
+-      save_flags (flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       /*
+        * Program the address_setup clocks into ARTTIM reg,
+        * and then the active/recovery counts into the DRWTIM reg
+@@ -586,7 +579,7 @@
+       setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
+       put_cmd640_reg(arttim_regs[index], setup_count);
+       put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ /*
+@@ -692,6 +685,41 @@
+ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
++static int pci_conf1(void)
++{
++      u32 tmp;
++      unsigned long flags;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      OUT_BYTE(0x01, 0xCFB);
++      tmp = inl(0xCF8);
++      outl(0x80000000, 0xCF8);
++      if (inl(0xCF8) == 0x80000000) {
++              outl(tmp, 0xCF8);
++              spin_unlock_irqrestore(&io_request_lock, flags);
++              return 1;
++      }
++      outl(tmp, 0xCF8);
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return 0;
++}
++
++static int pci_conf2(void)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      OUT_BYTE(0x00, 0xCFB);
++      OUT_BYTE(0x00, 0xCF8);
++      OUT_BYTE(0x00, 0xCFA);
++      if (IN_BYTE(0xCF8) == 0x00 && IN_BYTE(0xCF8) == 0x00) {
++              spin_unlock_irqrestore(&io_request_lock, flags);
++              return 1;
++      }
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return 0;
++}
++
+ /*
+  * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+  */
+@@ -709,9 +737,11 @@
+               bus_type = "VLB";
+       } else {
+               cmd640_vlb = 0;
+-              if (probe_for_cmd640_pci1())
++              /* Find out what kind of PCI probing is supported otherwise
++                 Justin Gibbs will sulk.. */
++              if (pci_conf1() && probe_for_cmd640_pci1())
+                       bus_type = "PCI (type1)";
+-              else if (probe_for_cmd640_pci2())
++              else if (pci_conf2() && probe_for_cmd640_pci2())
+                       bus_type = "PCI (type2)";
+               else
+                       return 0;
+diff -Nur linux.org/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c
+--- linux.org/drivers/ide/cmd64x.c     Fri Jul 28 01:40:57 2000
++++ linux/drivers/ide/cmd64x.c Thu Jul 18 14:24:33 2002
+@@ -8,9 +8,10 @@
+  *           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>
++ * Copyright (C) 1998         Eddie C. Dost  (ecd@skynet.be)
++ * Copyright (C) 1998         David S. Miller (davem@redhat.com)
++ *
++ * Copyright (C) 1999-2002    Andre Hedrick <andre@linux-ide.org>
+  */
+ #include <linux/config.h>
+@@ -32,7 +33,7 @@
+ #define CMD_DEBUG 0
+ #if CMD_DEBUG
+-#define cmdprintk(x...)       printk(##x)
++#define cmdprintk(x...)       printk(x)
+ #else
+ #define cmdprintk(x...)
+ #endif
+@@ -85,81 +86,97 @@
+ #include <linux/stat.h>
+ #include <linux/proc_fs.h>
++static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
++static char * print_sii_get_info(char *, struct pci_dev *, int);
+ static int cmd64x_get_info(char *, char **, off_t, int);
+ extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+-static struct pci_dev *bmide_dev;
+-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
++byte cmd64x_proc = 0;
++
++#define CMD_MAX_DEVS          5
++
++static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
++static int n_cmd_devs;
++
++#undef DEBUG_CMD_REGS
++
++static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+ {
+-      char *p = buffer;
++      char *p = buf;
++
+       u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;  /* primary */
+       u8 reg57 = 0, reg58 = 0, reg5b;                 /* secondary */
+       u8 reg72 = 0, reg73 = 0;                        /* primary */
+       u8 reg7a = 0, reg7b = 0;                        /* secondary */
+       u8 reg50 = 0, reg71 = 0;                        /* extra */
++#ifdef DEBUG_CMD_REGS
+       u8 hi_byte = 0, lo_byte = 0;
++#endif /* DEBUG_CMD_REGS */
+-      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",
++      p += sprintf(p, "\nController: %d\n", index);
++      p += sprintf(p, "CMD%x Chipset.\n", dev->device);
++      (void) pci_read_config_byte(dev, CFR,       &reg50);
++      (void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
++      (void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
++      (void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
++      (void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
++      (void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
++      (void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
++      (void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
++      (void) pci_read_config_byte(dev, MRDMODE,   &reg71);
++      (void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
++      (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
++      (void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
++      (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
++
++      p += sprintf(p, "--------------- Primary Channel "
++                      "---------------- Secondary Channel "
++                      "-------------\n");
++      p += sprintf(p, "                %sabled           "
++                      "              %sabled\n",
++              (reg72&0x80)?"dis":" en",
++              (reg7a&0x80)?"dis":" en");
++      p += sprintf(p, "--------------- drive0 "
++              "--------- drive1 -------- drive0 "
++              "---------- drive1 ------\n");
++      p += sprintf(p, "DMA enabled:    %s              %s"
++                      "             %s               %s\n",
++              (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
++              (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
++
++      p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+               (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+-              (reg72&0x20)?(  ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+-                              ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+-                              ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+-                              ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?",
++              (reg72&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"):"?",
++              (reg72&0x40)?(
++                      ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
++                      ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
++                      ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
++                      ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
++                      "X"):"?");
++      p += sprintf(p, "         %s(%s)           %s(%s)\n",
+               (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+-              (reg7a&0x20)?(  ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+-                              ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+-                              ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+-                              ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?",
++              (reg7a&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",
+-              "?", "?", "?", "?");
++              (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");
+@@ -170,35 +187,58 @@
+               (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+               (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
++#ifdef DEBUG_CMD_REGS
+       SPLIT_BYTE(reg50, hi_byte, lo_byte);
+-      p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
++      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);
++      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);
++      p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
++                      "LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
++#endif /* DEBUG_CMD_REGS */
+-      return p-buffer;        /* => must be less than 4k! */
++      return (char *)p;
+ }
+-#if 0
+-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
++static char * print_sii_get_info (char *buf, struct pci_dev *dev, int index)
+ {
+       char *p = buf;
+-      p += sprintf(p, "thingy stuff\n");
++
++      p += sprintf(p, "\nController: %d\n", index);
++      p += sprintf(p, "SII%x Chipset.\n", dev->device);
++
++      p += sprintf(p, "--------------- Primary Channel "
++                      "---------------- Secondary Channel "
++                      "-------------\n");
++      p += sprintf(p, "--------------- drive0 --------- drive1 "
++                      "-------- drive0 ---------- drive1 ------\n");
++      p += sprintf(p, "PIO Mode:       %s                %s"
++                      "               %s                 %s\n",
++                      "?", "?", "?", "?");
+       return (char *)p;
+ }
+-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
++
++static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+       char *p = buffer;
+-      p = cmd64x_chipset_data(buffer, bmide_dev);
+-      return p-buffer;        /* hoping it is less than 4K... */
++      int i;
++
++      p += sprintf(p, "\n");
++      for (i = 0; i < n_cmd_devs; i++) {
++              struct pci_dev *dev     = cmd_devs[i];
++
++              if (dev->device <= PCI_DEVICE_ID_CMD_649)
++                      p = print_cmd64x_get_info(p, dev, i);
++              else
++                      p = print_sii_get_info(p, dev, i);
++      }
++      return p-buffer;        /* => must be 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:
+  */
+@@ -214,6 +254,7 @@
+ static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+ {
+       unsigned long flags;
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
+       ide_drive_t *drives = HWIF(drive)->drives;
+       byte temp_b;
+       static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+@@ -252,25 +293,29 @@
+       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);
++      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();
++      local_irq_save(flags);
+       /*
+        * Program the address_setup clocks into ARTTIM reg,
+        * and then the active/recovery counts into the DRWTIM reg
+        */
+-      (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
+-      (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
++      (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
++      (void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+               ((byte) setup_count) | (temp_b & 0x3f));
+-      (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
++      (void) pci_write_config_byte(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);
++      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]);
++      local_irq_restore(flags);
+ }
+ /*
+@@ -294,7 +339,8 @@
+               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");
++                      cmdprintk("%s: %sabled cmd640 prefetch\n",
++                              drive->name, mode_wanted ? "en" : "dis");
+                       return;
+       }
+@@ -303,8 +349,8 @@
+       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.
++       * 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;
+@@ -334,21 +380,137 @@
+        * (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)
++       *      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",
++      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)
++static byte cmd64x_ratemask (ide_drive_t *drive)
+ {
+-      byte speed= 0x00;
+-      byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0x00;
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_CMD_680:     { mode |= 0x04; break; }
++              case PCI_DEVICE_ID_CMD_649:     { mode |= 0x03; break; }
++              case PCI_DEVICE_ID_CMD_648:     { mode |= 0x02; break; }
++              case PCI_DEVICE_ID_CMD_643:     { mode |= 0x01; break; }
++
++              case PCI_DEVICE_ID_CMD_646:
++              {
++                      unsigned int class_rev  = 0;
++                      pci_read_config_dword(dev,
++                              PCI_CLASS_REVISION, &class_rev);
++                      class_rev &= 0xff;
++              /*
++               * UltraDMA only supported on PCI646U and PCI646U2, which
++               * correspond to revisions 0x03, 0x05 and 0x07 respectively.
++               * Actually, although the CMD tech support people won't
++               * tell me the details, the 0x03 revision cannot support
++               * UDMA correctly without hardware modifications, and even
++               * then it only works with Quantum disks due to some
++               * hold time assumptions in the 646U part which are fixed
++               * in the 646U2.
++               *
++               * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
++               */
++                      switch(class_rev) {
++                              case 0x07:
++                              case 0x05:      { mode |= 0x01; break; }
++                              case 0x03:
++                              case 0x01:
++                              default:        { mode |= 0x00; break; }
++                      }
++              }
++      }
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte cmd64x_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = cmd64x_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
++static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
++{
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte addr_mask          = (hwif->channel) ? 0xB2 : 0xA2;
++      unsigned short          timing;
++
++      pci_read_config_word(dev, addr_mask, &timing);
++
++      switch (timing) {
++              case 0x10c1:    return 4;
++              case 0x10c3:    return 3;
++              case 0x1281:    return 2;
++              case 0x2283:    return 1;
++              case 0x328a:
++              default:        return 0;
++      }
++}
++
++static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte                    drive_pci;
++      unsigned short          speedt;
++
++      switch (drive->dn) {
++              case 0: drive_pci = 0xA4; break;
++              case 1: drive_pci = 0xA6; break;
++              case 2: drive_pci = 0xB4; break;
++              case 3: drive_pci = 0xB6; break;
++              default: return;
++        }
++
++      pci_read_config_word(dev, drive_pci, &speedt);
++
++      /* cheat for now and use the docs */
++//    switch(cmd680_taskfile_timing(hwif)) {
++      switch(mode_wanted) {
++              case 4:         speedt = 0x10c1; break;
++              case 3:         speedt = 0x10C3; break;
++              case 2:         speedt = 0x1104; break;
++              case 1:         speedt = 0x2283; break;
++              case 0:
++              default:        speedt = 0x328A; break;
++      }
++      pci_write_config_word(dev, drive_pci, speedt);
++}
++
++static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
++{
++      byte speed      = 0x00;
++      byte set_pio    = ide_get_best_pio_mode(drive, 4, 5, NULL);
+       cmd64x_tuneproc(drive, set_pio);
+       speed = XFER_PIO_0 + set_pio;
+@@ -356,20 +518,60 @@
+               (void) ide_config_drive_speed(drive, speed);
+ }
+-static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
++static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      u8 unit                 = (drive->select.b.unit & 0x01);
++      u8 addr_mask            = (hwif->channel) ? 0x84 : 0x80;
++      u8 speed                = 0x00;
++      u8 mode_pci             = 0x00;
++      u8 channel_timings      = cmd680_taskfile_timing(hwif);
++      u8 set_pio              = ide_get_best_pio_mode(drive, 4, 5, NULL);
++
++      pci_read_config_byte(dev, addr_mask, &mode_pci);
++      mode_pci &= ~((unit) ? 0x30 : 0x03);
++
++      /* WARNING PIO timing mess is going to happen b/w devices, argh */
++      if ((channel_timings != set_pio) && (set_pio > channel_timings))
++              set_pio = channel_timings;
++
++      cmd680_tuneproc(drive, set_pio);
++      speed = XFER_PIO_0 + set_pio;
++      if (set_speed)
++              (void) ide_config_drive_speed(drive, speed);
++}
++
++static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
++{
++      switch(HWIF(drive)->pci_dev->device) {
++              case PCI_DEVICE_ID_CMD_680:
++                      config_cmd680_chipset_for_pio(drive, set_speed);
++                      return;
++              default:
++                      break;
++      }
++      config_cmd64x_chipset_for_pio(drive, set_speed);
++}
++
++static int cmd64x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+ #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 unit                 = (drive->select.b.unit & 0x01);
+       u8 pciU                 = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+       u8 pciD                 = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+       u8 regU                 = 0;
+       u8 regD                 = 0;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
+-      if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))      return 1;
++      u8 speed                = cmd64x_ratefilter(drive, xferspeed);
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      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);
+@@ -377,10 +579,12 @@
+       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);
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
+       switch(speed) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
+               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;
+@@ -393,10 +597,6 @@
+               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;
+@@ -410,84 +610,180 @@
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+       (void) pci_write_config_byte(dev, pciU, regU);
++      regD |= (unit ? 0x40 : 0x20);
++      (void) pci_write_config_byte(dev, pciD, regD);
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-      err = ide_config_drive_speed(drive, speed);
++      return (ide_config_drive_speed(drive, speed));
++}
+-      drive->current_speed = speed;
++static int cmd680_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      u8 addr_mask            = (hwif->channel) ? 0x84 : 0x80;
++      u8 unit                 = (drive->select.b.unit & 0x01);
++      u8 speed                = cmd64x_ratefilter(drive, xferspeed);
++      u8 dma_pci              = 0;
++      u8 udma_pci             = 0;
++      u8 mode_pci             = 0;
++      u8 scsc                 = 0;
++      u16 ultra               = 0;
++      u16 multi               = 0;
++
++        pci_read_config_byte(dev, addr_mask, &mode_pci);
++      pci_read_config_byte(dev, 0x8A, &scsc);
++
++        switch (drive->dn) {
++              case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
++              case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
++              case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
++              case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
++              default: return 1;
++      }
++      pci_read_config_byte(dev, addr_mask, &mode_pci);
++      mode_pci &= ~((unit) ? 0x30 : 0x03);
++      pci_read_config_word(dev, dma_pci, &multi);
++      pci_read_config_word(dev, udma_pci, &ultra);
++
++      if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
++              pci_write_config_byte(dev, 0x8A, scsc|0x01);
++              pci_read_config_byte(dev, 0x8A, &scsc);
++#if 0
++              /* if 133 clock fails, switch to 2xbus clock */
++              if (!(scsc & 0x01))
++                      pci_write_config_byte(dev, 0x8A, scsc|0x10);
++#endif
++      }
++
++      switch(speed) {
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      regD |= (unit ? 0x40 : 0x20);
+-      (void) pci_write_config_byte(dev, pciD, regD);
++              case XFER_UDMA_6:
++                      if ((scsc & 0x30) == 0x00)
++                              goto speed_break;
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= 0x01;
++                      break;
++speed_break :
++                      speed = XFER_UDMA_5;
++              case XFER_UDMA_5:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
++                      break;
++              case XFER_UDMA_4:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
++                      break;
++              case XFER_UDMA_3:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
++                      break;
++              case XFER_UDMA_2:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
++                      break;
++              case XFER_UDMA_1:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
++                      break;
++              case XFER_UDMA_0:
++                      multi = 0x10C1;
++                      ultra &= ~0x3F;
++                      ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
++                      break;
++              case XFER_MW_DMA_2:
++                      multi = 0x10C1;
++                      break;
++              case XFER_MW_DMA_1:
++                      multi = 0x10C2;
++                      break;
++              case XFER_MW_DMA_0:
++                      multi = 0x2208;
++                      break;
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
++              case XFER_PIO_4:        cmd680_tuneproc(drive, 4); break;
++              case XFER_PIO_3:        cmd680_tuneproc(drive, 3); break;
++              case XFER_PIO_2:        cmd680_tuneproc(drive, 2); break;
++              case XFER_PIO_1:        cmd680_tuneproc(drive, 1); break;
++              case XFER_PIO_0:        cmd680_tuneproc(drive, 0); break;
++              default:
++                      return 1;
++      }
++      
++      if (speed >= XFER_MW_DMA_0) 
++              config_cmd680_chipset_for_pio(drive, 0);
++
++      if (speed >= XFER_UDMA_0)
++              mode_pci |= ((unit) ? 0x30 : 0x03);
++      else if (speed >= XFER_MW_DMA_0)
++              mode_pci |= ((unit) ? 0x20 : 0x02);
++      else
++              mode_pci |= ((unit) ? 0x10 : 0x01);
++
++      pci_write_config_byte(dev, addr_mask, mode_pci);
++      pci_write_config_word(dev, dma_pci, multi);
++      pci_write_config_word(dev, udma_pci, ultra);
+-      return err;
++      return (ide_config_drive_speed(drive, speed));
+ }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
++static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
+       ide_hwif_t *hwif        = HWIF(drive);
+-      struct pci_dev *dev     = hwif->pci_dev;
+-
++      byte mode               = cmd64x_ratemask(drive);
+       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");
++              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;
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      { set_pio = 1; break; }
+       }
+       if (!drive->init_speed)
+@@ -498,10 +794,11 @@
+       if (set_pio)
+               return ((int) ide_dma_off_quietly);
+-      if (cmd64x_tune_chipset(drive, speed))
++      if (hwif->speedproc(drive, speed))
+               return ((int) ide_dma_off);
+-      rval = (int)(   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
++      rval = (int)(   ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
++                      ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+@@ -514,33 +811,8 @@
+ {
+       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 */
+@@ -549,10 +821,10 @@
+                       goto fast_ata_pio;
+               }
+               dma_func = ide_dma_off_quietly;
+-              if ((id->field_valid & 4) && (can_ultra_33)) {
+-                      if (id->dma_ultra & 0x002F) {
++              if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
++                      if (id->dma_ultra & 0x007F) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -562,7 +834,7 @@
+                       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);
++                              dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+@@ -571,7 +843,7 @@
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, class_rev, 0);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -586,47 +858,76 @@
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
++static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
++{
++      switch (func) {
++              case ide_dma_check:
++                      return cmd64x_config_drive_for_dma(drive);
++              default:
++                      break;
++      }
++      /* Other cases are done by generic IDE-DMA code. */
++        return ide_dmaproc(func, drive);
++}
++
++static int cmd64x_alt_dma_status (struct pci_dev *dev)
++{
++      switch(dev->device) {
++              case PCI_DEVICE_ID_CMD_648:
++              case PCI_DEVICE_ID_CMD_649:
++                      return 1;
++              default:
++                      break;
++      }
++      return 0;
++}
++
+ static int cmd64x_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;
++      ide_hwif_t *hwif        = HWIF(drive);
++      byte mask               = (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
++      unsigned long dma_base  = hwif->dma_base;
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte alt_dma_stat       = cmd64x_alt_dma_status(dev);
+       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) {
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
++                      /* get DMA status */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* clear the INTR & ERROR bits */
++                      OUT_BYTE(dma_stat|6, dma_base+2);
++                      if (alt_dma_stat) {
+                               byte dma_intr   = 0;
+-                              byte dma_mask   = (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+-                              byte dma_reg    = (HWIF(drive)->channel) ? ARTTIM2 : CFR;
++                              byte dma_mask   = (hwif->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
++                              byte dma_reg    = (hwif->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 */
++                              /* clear the INTR bit */
++                              (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+                       }
+-                      ide_destroy_dmatable(drive);            /* purge DMA mappings */
+-                      return (dma_stat & 7) != 4;             /* verify good DMA status */
++                      /* purge DMA mappings */
++                      ide_destroy_dmatable(drive);
++                      /* verify good DMA status */
++                      return (dma_stat & 7) != 4;
+               case ide_dma_test_irq:  /* returns 1 if dma irq issued, 0 otherwise */
+-                      dma_stat = inb(dma_base+2);
++                      dma_stat = IN_BYTE(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);
++                      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 */
++                      /* return 1 if INTR asserted */
++                      return (dma_stat & 4) == 4;
+               default:
+                       break;
+       }
+@@ -649,11 +950,16 @@
+                       return cmd64x_config_drive_for_dma(drive);
+               case ide_dma_end:
+                       drive->waiting_for_dma = 0;
+-                      dma_stat = inb(dma_base+2);             /* get DMA status */
+-                      outb(inb(dma_base)&~1, dma_base);       /* stop DMA */
+-                      outb(dma_stat|6, dma_base+2);           /* clear the INTR & ERROR bits */
+-                      ide_destroy_dmatable(drive);            /* and free any DMA resources */
+-                      return (dma_stat & 7) != 4;             /* verify good DMA status */
++                      /* get DMA status */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
++                      /* clear the INTR & ERROR bits */
++                      OUT_BYTE(dma_stat|6, dma_base+2);
++                      /* and free any DMA resources */
++                      ide_destroy_dmatable(drive);
++                      /* verify good DMA status */
++                      return (dma_stat & 7) != 4;
+               default:
+                       break;
+       }
+@@ -663,7 +969,87 @@
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
++static int cmd680_busproc (ide_drive_t * drive, int state)
++{
++#if 0
++      ide_hwif_t *hwif        = HWIF(drive);
++      u8 addr_mask            = (hwif->channel) ? 0xB0 : 0xA0;
++      u32 stat_config         = 0;
++
++        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
++
++      if (!hwif)
++              return -EINVAL;
++
++      switch (state) {
++              case BUSSTATE_ON:
++                      hwif->drives[0].failures = 0;
++                      hwif->drives[1].failures = 0;
++                      break;
++              case BUSSTATE_OFF:
++                      hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
++                      hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
++                      break;
++              case BUSSTATE_TRISTATE:
++                      hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
++                      hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
++                      break;
++              default:
++                      return 0;
++      }
++      hwif->bus_state = state;
++#endif
++      return 0;
++}
++
++void cmd680_reset (ide_drive_t *drive)
++{
++#if 0
++      ide_hwif_t *hwif        = HWIF(drive);
++      u8 addr_mask            = (hwif->channel) ? 0xB0 : 0xA0;
++      byte reset              = 0;
++
++      pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
++      pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
++#endif
++}
++
++unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
++{
++      u8 tmpbyte      = 0;    
++      pci_write_config_byte(dev, 0x80, 0x00);
++      pci_write_config_byte(dev, 0x84, 0x00);
++      pci_read_config_byte(dev, 0x8A, &tmpbyte);
++      pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
++#if 0
++      /* if 133 clock fails, switch to 2xbus clock */ 
++      if (!(tmpbyte & 0x01)) {
++              pci_read_config_byte(dev, 0x8A, &tmpbyte);
++              pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);         
++      }
++#endif
++      pci_write_config_word(dev, 0xA2, 0x328A);
++      pci_write_config_dword(dev, 0xA4, 0x328A);
++      pci_write_config_dword(dev, 0xA8, 0x4392);
++      pci_write_config_dword(dev, 0xAC, 0x4009);
++      pci_write_config_word(dev, 0xB2, 0x328A);
++      pci_write_config_dword(dev, 0xB4, 0x328A);
++      pci_write_config_dword(dev, 0xB8, 0x4392);
++      pci_write_config_dword(dev, 0xBC, 0x4009);
++
++      cmd_devs[n_cmd_devs++] = dev;
++
++#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
++      if (!cmd64x_proc) {
++              cmd64x_proc = 1;
++              cmd64x_display_info = &cmd64x_get_info;
++      }
++#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
++
++      return 0;
++}
++
++unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
+ {
+       unsigned char mrdmode;
+       unsigned int class_rev;
+@@ -741,10 +1127,11 @@
+       (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+ #endif /* CONFIG_PPC */
++      cmd_devs[n_cmd_devs++] = dev;
++
+ #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 */
+@@ -752,7 +1139,27 @@
+       return 0;
+ }
+-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
++unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
++{
++      switch(dev->device) {
++              case PCI_DEVICE_ID_CMD_680:
++                      return cmd680_pci_init (dev, name);
++              default:
++                      break;
++      }
++      return cmd64x_pci_init (dev, name);
++}
++
++unsigned int cmd680_ata66 (ide_hwif_t *hwif)
++{
++      byte ata66      = 0;
++      byte addr_mask  = (hwif->channel) ? 0xB0 : 0xA0;
++
++      pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
++      return (ata66 & 0x01) ? 1 : 0;
++}
++
++unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
+ {
+       byte ata66 = 0;
+       byte mask = (hwif->channel) ? 0x02 : 0x01;
+@@ -761,6 +1168,17 @@
+       return (ata66 & mask) ? 1 : 0;
+ }
++unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
++{
++      switch(hwif->pci_dev->device) {
++              case PCI_DEVICE_ID_CMD_680:
++                      return cmd680_ata66(hwif);
++              default:
++                      break;
++      }
++      return cmd64x_ata66(hwif);
++}
++
+ void __init ide_init_cmd64x (ide_hwif_t *hwif)
+ {
+       struct pci_dev *dev     = hwif->pci_dev;
+@@ -769,31 +1187,50 @@
+       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_680:
++                      hwif->busproc   = &cmd680_busproc;
++#ifdef CONFIG_BLK_DEV_IDEDMA
++                      if (hwif->dma_base)
++                              hwif->dmaproc   = &cmd680_dmaproc;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++                      hwif->resetproc = &cmd680_reset;
++                      hwif->speedproc = &cmd680_tune_chipset;
++                      hwif->tuneproc  = &cmd680_tuneproc;
++                      break;
+               case PCI_DEVICE_ID_CMD_649:
+               case PCI_DEVICE_ID_CMD_648:
+               case PCI_DEVICE_ID_CMD_643:
+-                      hwif->dmaproc = &cmd64x_dmaproc;
++#ifdef CONFIG_BLK_DEV_IDEDMA
++                      if (hwif->dma_base)
++                              hwif->dmaproc   = &cmd64x_dmaproc;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++                      hwif->tuneproc  = &cmd64x_tuneproc;
++                      hwif->speedproc = &cmd64x_tune_chipset;
+                       break;
+               case PCI_DEVICE_ID_CMD_646:
+                       hwif->chipset = ide_cmd646;
+-                      if (class_rev == 0x01) {
+-                              hwif->dmaproc = &cmd646_1_dmaproc;
+-                      } else {
+-                              hwif->dmaproc = &cmd64x_dmaproc;
++#ifdef CONFIG_BLK_DEV_IDEDMA
++                      if (hwif->dma_base) {
++                              if (class_rev == 0x01)
++                                      hwif->dmaproc = &cmd646_1_dmaproc;
++                              else
++                                      hwif->dmaproc = &cmd64x_dmaproc;
+                       }
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++                      hwif->tuneproc  = &cmd64x_tuneproc;
++                      hwif->speedproc = &cmd64x_tune_chipset;
+                       break;
+               default:
+                       break;
+       }
+-#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IDEDMA_AUTO)
++      if (hwif->dma_base)
++              if (!noautodma)
++                      hwif->autodma = 1;
++#endif /* CONFIG_BLK_DEV_IDEDMA && CONFIG_IDEDMA_AUTO*/
+ }
+diff -Nur linux.org/drivers/ide/cs5530.c linux/drivers/ide/cs5530.c
+--- linux.org/drivers/ide/cs5530.c     Wed Jan  3 01:58:45 2001
++++ linux/drivers/ide/cs5530.c Thu Jul 18 14:24:33 2002
+@@ -37,7 +37,6 @@
+ static int cs5530_get_info(char *, char **, off_t, int);
+ extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+ static struct pci_dev *bmide_dev;
+ static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+@@ -54,13 +53,19 @@
+       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",
++      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",
++      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 " );
+@@ -74,19 +79,14 @@
+ byte cs5530_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-
+ /*
+  * Set a new transfer mode at the drive
+  */
+ int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
+ {
+-      int error = 0;
+-
+-      printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+-      error = ide_config_drive_speed(drive, mode);
+-
+-      return error;
++      printk("%s: cs5530_set_xfer_mode(%s)\n",
++              drive->name, ide_xfer_verbose(mode));
++      return (ide_config_drive_speed(drive, mode));
+ }
+ /*
+@@ -115,12 +115,13 @@
+ {
+       ide_hwif_t      *hwif = HWIF(drive);
+       unsigned int    format, basereg = CS5530_BASEREG(hwif);
+-      static byte     modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
++      static byte     modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+               format = (inl(basereg+4) >> 31) & 1;
+-              outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3));
++              outl(cs5530_pio_timings[format][pio],
++                      basereg+(drive->select.b.unit<<3));
+       }
+ }
+@@ -138,12 +139,13 @@
+       struct hd_driveid       *id = drive->id;
+       unsigned int            basereg, reg, timings;
+-
+       /*
+        * Default to DMA-off in case we run into trouble here.
+        */
+-      (void)hwif->dmaproc(ide_dma_off_quietly, drive);        /* turn off DMA while we fiddle */
+-      outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
++      (void)hwif->dmaproc(ide_dma_off_quietly, drive);
++      /* turn off DMA while we fiddle */
++      (void)hwif->dmaproc(ide_dma_host_off, drive);
++      /* clear DMA_capable bit */
+       /*
+        * The CS5530 specifies that two drives sharing a cable cannot
+@@ -156,10 +158,13 @@
+        */
+       if (mate->present) {
+               struct hd_driveid *mateid = mate->id;
+-              if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) {
+-                      if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
++              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))
++                      else if ((mateid->field_valid & 2) &&
++                               (mateid->dma_mword & 7))
+                               udma_ok = 0;
+                       else
+                               udma_ok = 1;
+@@ -170,7 +175,8 @@
+        * Now see what the current drive is capable of,
+        * selecting UDMA only if the mate said it was ok.
+        */
+-      if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) {
++      if (id && (id->capability & 1) && hwif->autodma &&
++          !hwif->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;
+@@ -206,11 +212,12 @@
+               case XFER_MW_DMA_1:     timings = 0x00012121; break;
+               case XFER_MW_DMA_2:     timings = 0x00002020; break;
+               default:
+-                      printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode);
++                      printk("%s: cs5530_config_dma: huh? mode=%02x\n",
++                              drive->name, mode);
+                       return 1;       /* failure */
+       }
+       basereg = CS5530_BASEREG(hwif);
+-      reg = inl(basereg+4);                   /* get drive0 config register */
++      reg = inl(basereg+4);           /* get drive0 config register */
+       timings |= reg & 0x80000000;            /* preserve PIO format bit */
+       if (unit == 0) {                        /* are we configuring drive0? */
+               outl(timings, basereg+4);       /* write drive0 config register */
+@@ -222,7 +229,8 @@
+               outl(reg,     basereg+4);       /* write drive0 config register */
+               outl(timings, basereg+12);      /* write drive1 config register */
+       }
+-      outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */
++      (void)hwif->dmaproc(ide_dma_host_on, drive);
++      /* set DMA_capable bit */
+       /*
+        * Finally, turn DMA on in software, and exit.
+@@ -286,8 +294,8 @@
+               return 0;
+       }
+-      save_flags(flags);
+-      cli();  /* all CPUs (there should only be one CPU with this chipset) */
++      spin_lock_irqsave(&io_request_lock, flags);
++              /* all CPUs (there should only be one CPU with this chipset) */
+       /*
+        * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+@@ -333,7 +341,7 @@
+       pci_write_config_byte(master_0, 0x42, 0x00);
+       pci_write_config_byte(master_0, 0x43, 0xc1);
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return 0;
+ }
+@@ -344,31 +352,35 @@
+  */
+ void __init ide_init_cs5530 (ide_hwif_t *hwif)
+ {
++      unsigned int basereg, d0_timings;
++      hwif->autodma = 0;
++
+       if (hwif->mate)
+               hwif->serialized = hwif->mate->serialized = 1;
+-      if (!hwif->dma_base) {
+-              hwif->autodma = 0;
+-      } else {
+-              unsigned int basereg, d0_timings;
++
++      hwif->tuneproc = &cs5530_tuneproc;
++      basereg = CS5530_BASEREG(hwif);
++      d0_timings = inl(basereg+0);
++      if (CS5530_BAD_PIO(d0_timings)) {
++              /* PIO timings not initialized? */
++              outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
++              if (!hwif->drives[0].autotune)
++                      hwif->drives[0].autotune = 1;
++                      /* needs autotuning later */
++      }
++      if (CS5530_BAD_PIO(inl(basereg+8))) {
++      /* PIO timings not initialized? */
++              outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
++              if (!hwif->drives[1].autotune)
++                      hwif->drives[1].autotune = 1;
++                      /* needs autotuning later */
++      }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-              hwif->dmaproc  = &cs5530_dmaproc;
+-#else
+-              hwif->autodma = 0;
++      hwif->dmaproc  = &cs5530_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-
+-              hwif->tuneproc = &cs5530_tuneproc;
+-              basereg = CS5530_BASEREG(hwif);
+-              d0_timings = inl(basereg+0);
+-              if (CS5530_BAD_PIO(d0_timings)) {       /* PIO timings not initialized? */
+-                      outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+-                      if (!hwif->drives[0].autotune)
+-                              hwif->drives[0].autotune = 1;   /* needs autotuning later */
+-              }
+-              if (CS5530_BAD_PIO(inl(basereg+8))) {   /* PIO timings not initialized? */
+-                      outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+-                      if (!hwif->drives[1].autotune)
+-                              hwif->drives[1].autotune = 1;   /* needs autotuning later */
+-              }
+-      }
+ }
+diff -Nur linux.org/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c
+--- linux.org/drivers/ide/cy82c693.c   Sun May 20 02:43:06 2001
++++ linux/drivers/ide/cy82c693.c       Thu Jul 18 14:24:33 2002
+@@ -105,10 +105,10 @@
+ /* 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) */
++        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;
+ /*
+@@ -183,24 +183,26 @@
+  */
+ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+ {
+-        byte index;
++      byte index;
+       byte data;
+-        if (mode>2)   /* make sure we set a valid mode */
++      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;
++      index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+ #if CY82C693_DEBUG_LOGS
+-              /* for debug let's show the previous values */
++      /* 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));
++      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);
+@@ -209,7 +211,9 @@
+       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);
++      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 */
+       /* 
+@@ -227,7 +231,8 @@
+       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);
++      printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
++              drive->name, data);
+ #endif /* CY82C693_DEBUG_INFO */
+ }
+@@ -318,7 +323,10 @@
+               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);
++      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 */
+@@ -371,7 +379,10 @@
+       }       
+ #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);
++      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 */
+ }
+@@ -391,7 +402,7 @@
+ #endif /* CY82C693_SETDMA_CLOCK */ 
+       /* write info about this verion of the driver */
+-      printk (KERN_INFO CY82_VERSION "\n");
++      printk(KERN_INFO CY82_VERSION "\n");
+ #ifdef CY82C693_SETDMA_CLOCK
+        /* okay let's set the DMA clock speed */
+@@ -400,7 +411,8 @@
+         data = IN_BYTE(CY82_DATA_PORT);
+ #if CY82C693_DEBUG_INFO
+-      printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
++      printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
++              name, data);
+ #endif /* CY82C693_DEBUG_INFO */
+         /*
+@@ -421,7 +433,8 @@
+         OUT_BYTE(data, CY82_DATA_PORT);
+ #if CY82C693_DEBUG_INFO
+-      printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
++      printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
++              name, data);
+ #endif /* CY82C693_DEBUG_INFO */
+ #endif /* CY82C693_SETDMA_CLOCK */
+@@ -439,11 +452,27 @@
+       hwif->drives[1].autotune = 1;
+       hwif->autodma = 0;
++      if (!hwif->dma_base)
++              return;
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (hwif->dma_base) {
+-              hwif->dmaproc = &cy82c693_dmaproc;
+-              if (!noautodma)
+-                      hwif->autodma = 1;
+-      }
++      hwif->dmaproc = &cy82c693_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_cy82c693 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++        if ((!(PCI_FUNC(dev->devfn) & 1) ||
++          (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
++              return; /* CY82C693 is more than only a IDE controller */
++
++      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 -Nur linux.org/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c
+--- linux.org/drivers/ide/dtc2278.c    Fri Apr 14 07:54:26 2000
++++ linux/drivers/ide/dtc2278.c        Thu Jul 18 14:24:33 2002
+@@ -57,14 +57,14 @@
+       int i;
+       for(i = 0; i < 3; ++i) {
+-              inb(0x3f6);
++              IN_BYTE(0x3f6);
+               outb_p(b,0xb0);
+-              inb(0x3f6);
++              IN_BYTE(0x3f6);
+               outb_p(c,0xb4);
+-              inb(0x3f6);
+-              if(inb(0xb4) == c) {
++              IN_BYTE(0x3f6);
++              if(IN_BYTE(0xb4) == c) {
+                       outb_p(7,0xb0);
+-                      inb(0x3f6);
++                      IN_BYTE(0x3f6);
+                       return; /* success */
+               }
+       }
+@@ -77,14 +77,13 @@
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       if (pio >= 3) {
+-              save_flags(flags);      /* all CPUs */
+-              cli();                  /* all CPUs */
++              spin_lock_irqsave(&io_request_lock, flags);
+               /*
+                * This enables PIO mode4 (3?) on the first interface
+                */
+               sub22(1,0xc3);
+               sub22(0,0xa0);
+-              restore_flags(flags);   /* all CPUs */
++              spin_unlock_irqrestore(&io_request_lock, flags);
+       } else {
+               /* we don't know how to set it back again.. */
+       }
+@@ -100,15 +99,14 @@
+ {
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       /*
+        * This enables the second interface
+        */
+       outb_p(4,0xb0);
+-      inb(0x3f6);
++      IN_BYTE(0x3f6);
+       outb_p(0x20,0xb4);
+-      inb(0x3f6);
++      IN_BYTE(0x3f6);
+ #ifdef ALWAYS_SET_DTC2278_PIO_MODE
+       /*
+        * This enables PIO mode4 (3?) on the first interface
+@@ -117,7 +115,7 @@
+       sub22(1,0xc3);
+       sub22(0,0xa0);
+ #endif
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       ide_hwifs[0].serialized = 1;
+       ide_hwifs[1].serialized = 1;
+diff -Nur linux.org/drivers/ide/falconide.c linux/drivers/ide/falconide.c
+--- linux.org/drivers/ide/falconide.c  Thu Oct 25 22:53:47 2001
++++ linux/drivers/ide/falconide.c      Thu Jul 18 14:23:00 2002
+@@ -7,7 +7,7 @@
+  *  License.  See the file COPYING in the main directory of this archive for
+  *  more details.
+  */
+-#include <linux/config.h>
++
+ #include <linux/types.h>
+ #include <linux/mm.h>
+ #include <linux/interrupt.h>
+diff -Nur linux.org/drivers/ide/gayle.c linux/drivers/ide/gayle.c
+--- linux.org/drivers/ide/gayle.c      Tue Nov 28 02:57:34 2000
++++ linux/drivers/ide/gayle.c  Thu Jul 18 14:23:00 2002
+@@ -16,6 +16,7 @@
+ #include <linux/hdreg.h>
+ #include <linux/ide.h>
+ #include <linux/init.h>
++#include <linux/zorro.h>
+ #include <asm/setup.h>
+ #include <asm/amigahw.h>
+@@ -88,7 +89,7 @@
+ {
+     unsigned char ch;
+-    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
++    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+     if (!(ch & GAYLE_IRQ_IDE))
+       return 0;
+     return 1;
+@@ -98,11 +99,11 @@
+ {
+     unsigned char ch;
+-    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
++    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+     if (!(ch & GAYLE_IRQ_IDE))
+       return 0;
+-    (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]);
+-    outb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
++    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
++    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+     return 1;
+ }
+diff -Nur linux.org/drivers/ide/hd.c linux/drivers/ide/hd.c
+--- linux.org/drivers/ide/hd.c Mon Oct 15 22:27:42 2001
++++ linux/drivers/ide/hd.c     Thu Jul 18 14:24:33 2002
+@@ -135,13 +135,12 @@
+       unsigned long t, flags;
+       int i;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       t = jiffies * 11932;
+       outb_p(0, 0x43);
+       i = inb_p(0x40);
+-      i |= inb(0x40) << 8;
+-      restore_flags(flags);
++      i |= IN_BYTE(0x40) << 8;
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return(t - i);
+ }
+ #endif
+@@ -185,7 +184,7 @@
+       if ((stat & ERR_STAT) == 0) {
+               hd_error = 0;
+       } else {
+-              hd_error = inb(HD_ERROR);
++              hd_error = IN_BYTE(HD_ERROR);
+               printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+               if (hd_error & BBD_ERR)         printk("BadSector ");
+               if (hd_error & ECC_ERR)         printk("UncorrectableError ");
+@@ -195,8 +194,9 @@
+               if (hd_error & MARK_ERR)        printk("AddrMarkNotFound ");
+               printk("}");
+               if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+-                      printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
+-                              inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
++                      printk(", CHS=%d/%d/%d",
++                              (IN_BYTE(HD_HCYL)<<8) + IN_BYTE(HD_LCYL),
++                              IN_BYTE(HD_CURRENT) & 0xf, IN_BYTE(HD_SECTOR));
+                       if (!QUEUE_EMPTY)
+                               printk(", sector=%ld", CURRENT->sector);
+               }
+@@ -207,7 +207,7 @@
+       if ((stat & ERR_STAT) == 0) {
+               hd_error = 0;
+       } else {
+-              hd_error = inb(HD_ERROR);
++              hd_error = IN_BYTE(HD_ERROR);
+               printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+       }
+ #endif        /* verbose errors */
+@@ -318,7 +318,7 @@
+       for(i = 0; i < 1000; i++) barrier();
+       if (drive_busy())
+               printk("hd: controller still busy\n");
+-      else if ((hd_error = inb(HD_ERROR)) != 1)
++      else if ((hd_error = IN_BYTE(HD_ERROR)) != 1)
+               printk("hd: controller reset failed: %02x\n",hd_error);
+ }
+@@ -346,6 +346,13 @@
+               hd_request();
+ }
++void do_reset_hd(void)
++{
++      DEVICE_INTR = NULL;
++      reset = 1;
++      reset_hd();
++}
++
+ /*
+  * Ok, don't know what to do with the unexpected interrupts: on some machines
+  * doing a reset and a retry seems to result in an eternal loop. Right now I
+@@ -876,14 +883,13 @@
+       target = DEVICE_NR(dev);
+       gdev = &GENDISK_STRUCT;
+-      save_flags(flags);
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       if (DEVICE_BUSY || USAGE > maxusage) {
+-              restore_flags(flags);
++              spin_unlock_irqrestore(&io_request_lock, flags);
+               return -EBUSY;
+       }
+       DEVICE_BUSY = 1;
+-      restore_flags(flags);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       max_p = gdev->max_p;
+       start = target << gdev->minor_shift;
+diff -Nur linux.org/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c
+--- linux.org/drivers/ide/hpt34x.c     Sun May 20 02:43:06 2001
++++ linux/drivers/ide/hpt34x.c Thu Jul 18 14:24:33 2002
+@@ -50,41 +50,57 @@
+ #undef DISPLAY_HPT34X_TIMINGS
++#define HPT34X_MAX_DEVS                       8
++static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
++static int n_hpt34x_devs;
++
+ #if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+ #include <linux/stat.h>
+ #include <linux/proc_fs.h>
+ static int hpt34x_get_info(char *, char **, off_t, int);
+ extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+-static struct pci_dev *bmide_dev;
+ static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+       char *p = buffer;
+-      u32 bibma = pci_resource_start(bmide_dev, 4);
+-      u8  c0 = 0, c1 = 0;
++      int i;
+-        /*
+-         * 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");
++      p += sprintf(p, "\n                             "
++                      "HPT34X Chipset.\n");
++      for (i = 0; i < n_hpt34x_devs; i++) {
++              struct pci_dev *dev = hpt34x_devs[i];
++              u32 bibma = pci_resource_start(dev, 4);
++              u8  c0 = 0, c1 = 0;
++
++              /*
++               * at that point bibma+0x2 et bibma+0xa are byte registers
++               * to investigate:
++               */
++              c0 = inb_p((unsigned short)bibma + 0x02);
++              c1 = inb_p((unsigned short)bibma + 0x0a);
++              p += sprintf(p, "\nController: %d\n", i);
++              p += sprintf(p, "--------------- Primary Channel "
++                              "---------------- Secondary Channel "
++                              "-------------\n");
++              p += sprintf(p, "                %sabled "
++                              "                        %sabled\n",
++                              (c0&0x80) ? "dis" : " en",
++                              (c1&0x80) ? "dis" : " en");
++              p += sprintf(p, "--------------- drive0 --------- drive1 "
++                              "-------- drive0 ---------- drive1 ------\n");
++              p += sprintf(p, "DMA enabled:    %s              %s"
++                              "             %s               %s\n",
++                              (c0&0x20) ? "yes" : "no ",
++                              (c0&0x40) ? "yes" : "no ",
++                              (c1&0x20) ? "yes" : "no ",
++                              (c1&0x40) ? "yes" : "no " );
++
++              p += sprintf(p, "UDMA\n");
++              p += sprintf(p, "DMA\n");
++              p += sprintf(p, "PIO\n");
++      }
++      p += sprintf(p, "\n");
+       return p-buffer;        /* => must be less than 4k! */
+ }
+@@ -92,27 +108,65 @@
+ byte hpt34x_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
++static byte hpt34x_ratemask (ide_drive_t *drive)
++{
++      byte mode = 0x00;
++
++      mode |= 0x01;
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte hpt34x_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++# ifdef CONFIG_HPT34X_AUTODMA
++byte mode = hpt34x_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      // while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      // while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      // while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++# else /* !CONFIG_HPT34X_AUTODMA */
++      while (speed > XFER_PIO_4) speed--;
++# endif /* CONFIG_HPT34X_AUTODMA */
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
+ static void hpt34x_clear_chipset (ide_drive_t *drive)
+ {
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       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);
++      pci_read_config_dword(dev, 0x44, &reg1);
++      pci_read_config_dword(dev, 0x48, &reg2);
+       tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+       tmp2 = (reg2 & ~(0x11 << drive->dn));
+-      pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+-      pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
++      pci_write_config_dword(dev, 0x44, tmp1);
++      pci_write_config_dword(dev, 0x48, tmp2);
+ }
+-static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
++static int hpt34x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+-      int                     err;
+-      byte                    hi_speed, lo_speed;
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte speed              = hpt34x_ratefilter(drive, xferspeed);
+       unsigned int reg1       = 0, tmp1 = 0;
+       unsigned int reg2       = 0, tmp2 = 0;
++      byte                    hi_speed, lo_speed;
+       SPLIT_BYTE(speed, hi_speed, lo_speed);
+@@ -123,76 +177,35 @@
+               lo_speed >>= 5;
+       }
+-      pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+-      pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
++      pci_read_config_dword(dev, 0x44, &reg1);
++      pci_read_config_dword(dev, 0x48, &reg2);
+       tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+       tmp2 = ((hi_speed << drive->dn) | reg2);
+-      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;
++      pci_write_config_dword(dev, 0x44, tmp1);
++      pci_write_config_dword(dev, 0x48, tmp2);
+ #if HPT343_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+-              " (0x%02x 0x%02x) 0x%04x\n",
++              " (0x%02x 0x%02x)\n",
+               drive->name, ide_xfer_verbose(speed),
+               drive->dn, reg1, tmp1, reg2, tmp2,
+-              hi_speed, lo_speed, err);
++              hi_speed, lo_speed);
+ #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);
++      return(ide_config_drive_speed(drive, speed));
+ }
+ static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
+ {
+       byte speed;
++      pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       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;
++              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);
+@@ -205,42 +218,41 @@
+  * 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)
++static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
++      byte mode               = hpt34x_ratemask(drive);
+       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);
++      switch(mode) {
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
++      hpt34x_clear_chipset(drive);
+       (void) hpt34x_tune_chipset(drive, speed);
+       return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+@@ -255,6 +267,8 @@
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
++      drive->init_speed = 0;
++
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -265,7 +279,7 @@
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x0007) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, 1);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -275,7 +289,7 @@
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+-                              dma_func = config_chipset_for_dma(drive, 0);
++                              dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+@@ -284,7 +298,7 @@
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, 0);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -294,7 +308,7 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              config_chipset_for_pio(drive);
++              hpt34x_tune_drive(drive, 255);
+       }
+ #ifndef CONFIG_HPT34X_AUTODMA
+@@ -316,6 +330,7 @@
+ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
+       ide_hwif_t *hwif = HWIF(drive);
++//    ide_task_t *args = HWGROUP(drive)->rq->special;
+       unsigned long dma_base = hwif->dma_base;
+       unsigned int count, reading = 0;
+       byte dma_stat;
+@@ -327,24 +342,52 @@
+                       reading = 1 << 3;
+               case ide_dma_write:
+                       if (!(count = ide_build_dmatable(drive, func)))
+-                              return 1;       /* try PIO instead of DMA */
+-                      outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
++                              return 1;
++                              /* try PIO instead of DMA */
++                      outl(hwif->dmatable_dma, dma_base + 4);
++                      /* PRD table */
+                       reading |= 0x01;
+-                      outb(reading, dma_base);                /* specify r/w */
+-                      outb(inb(dma_base+2)|6, dma_base+2);    /* clear INTR & ERROR flags */
++                      OUT_BYTE(reading, dma_base);
++                      /* specify r/w */
++                      OUT_BYTE(IN_BYTE(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;
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
++                      ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
++                      /* issue cmd to drive */
++                      /*
++                       * FIX ME to use only ACB ide_task_t args Struct
++                       */
++#if 0
++              {
++                      ide_task_t *args = HWGROUP(drive)->rq->special;
++                      OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++              {
++#else
++                      if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
++                              ide_task_t *args = HWGROUP(drive)->rq->special;
++                              OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++                      } else if (drive->addressing == 1)
++                              OUT_BYTE((reading == 9) ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
++                      else
++                              OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++#endif
++                      return HWIF(drive)->dmaproc(ide_dma_begin, 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 */
+-                      ide_destroy_dmatable(drive);            /* purge DMA mappings */
+-                      return (dma_stat & 7) != 4;             /* verify good DMA status */
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
++                      /* get DMA status */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* clear the INTR & ERROR bits */
++                      OUT_BYTE(dma_stat|6, dma_base+2);
++                      /* purge DMA mappings */
++                      ide_destroy_dmatable(drive);
++                      /* verify good DMA status */
++                      return (dma_stat & 7) != 4;
+               default:
+                       break;
+       }
+@@ -361,11 +404,11 @@
+ {
+       int i = 0;
+       unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
++      unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+       unsigned short cmd;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+@@ -373,35 +416,34 @@
+       if (cmd & PCI_COMMAND_MEMORY) {
+               if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+                       pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+-                      printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start);
++                      printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
++                              dev->resource[PCI_ROM_RESOURCE].start);
+               }
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+       } else {
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+       }
+-      pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+-      dev->resource[0].start = (hpt34xIoBase + 0x20);
+-      dev->resource[1].start = (hpt34xIoBase + 0x34);
+-      dev->resource[2].start = (hpt34xIoBase + 0x28);
+-      dev->resource[3].start = (hpt34xIoBase + 0x3c);
+-      for(i=0; i<4; i++)
+-              dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+       /*
+        * Since 20-23 can be assigned and are R/W, we correct them.
+        */
+-      pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
+-      pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
+-      pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
+-      pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
++      pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
++      for(i=0; i<4; i++) {
++              dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
++              dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
++              pci_write_config_dword(dev,
++                              (PCI_BASE_ADDRESS_0 + (i * 4)),
++                              dev->resource[i].start);
++      }
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
++
++      hpt34x_devs[n_hpt34x_devs++] = dev;
+ #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 */
+@@ -411,27 +453,39 @@
+ void __init ide_init_hpt34x (ide_hwif_t *hwif)
+ {
++      unsigned short pcicmd = 0;
+       hwif->tuneproc = &hpt34x_tune_drive;
+       hwif->speedproc = &hpt34x_tune_chipset;
+-
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (hwif->dma_base) {
+-              unsigned short pcicmd = 0;
+-
+-              pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+-              if (!noautodma)
+-                      hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+-              else
+-                      hwif->autodma = 0;
+-
+-              hwif->dmaproc = &hpt34x_dmaproc;
+-      } else {
+-              hwif->drives[0].autotune = 1;
+-              hwif->drives[1].autotune = 1;
+-      }
+-#else /* !CONFIG_BLK_DEV_IDEDMA */
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+       hwif->autodma = 0;
++
++      pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
++
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &hpt34x_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_hpt343 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      char *chipset_names[] = {"HPT343", "HPT345"};
++      unsigned short pcicmd = 0;
++
++      pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
++
++      strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
++      d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
++      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 -Nur linux.org/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
+--- linux.org/drivers/ide/hpt366.c     Wed Aug 15 05:01:07 2001
++++ linux/drivers/ide/hpt366.c Thu Jul 18 14:24:33 2002
+@@ -1,8 +1,8 @@
+ /*
+- * linux/drivers/ide/hpt366.c         Version 0.18    June. 9, 2000
++ * linux/drivers/ide/hpt366.c         Version 0.33    April 17, 2002
+  *
+- * Copyright (C) 1999-2000            Andre Hedrick <andre@linux-ide.org>
+- * May be copied or modified under the terms of the GNU General Public License
++ * Copyright (C) 1999-2002            Andre Hedrick <andre@linux-ide.org>
++ * Portions Copyright (C) 2001                Sun Microsystems, Inc.
+  *
+  * Thanks to HighPoint Technologies for their assistance, and hardware.
+  * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+@@ -11,8 +11,37 @@
+  *
+  * 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>
+@@ -28,6 +57,7 @@
+ #include <linux/init.h>
+ #include <linux/ide.h>
++#include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -35,13 +65,16 @@
+ #define DISPLAY_HPT366_TIMINGS
++/* various tuning parameters */
++#define HPT_RESET_STATE_ENGINE
++#undef HPT_DELAY_INTERRUPT
++#undef 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",
+@@ -106,160 +139,554 @@
+ struct chipset_bus_clock_list_entry {
+       byte            xfer_speed;
+-      unsigned int    chipset_settings_write;
+-      unsigned int    chipset_settings_read;
++      unsigned int    chipset_settings;
+ };
+-struct chipset_bus_clock_list_entry forty_base [] = {
++/* key for bus clock timings
++ * bit
++ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
++ *        DMA. cycles = value + 1
++ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
++ *        DMA. cycles = value + 1
++ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
++ *        register access.
++ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
++ *        register access.
++ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
++ *        during task file register access.
++ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
++ *        xfer.
++ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
++ *        register access.
++ * 28     UDMA enable
++ * 29     DMA enable
++ * 30     PIO_MST enable. if set, the chip is in bus master mode during
++ *        PIO.
++ * 31     FIFO enable.
++ */
++struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
++      {       XFER_UDMA_4,    0x900fd943      },
++      {       XFER_UDMA_3,    0x900ad943      },
++      {       XFER_UDMA_2,    0x900bd943      },
++      {       XFER_UDMA_1,    0x9008d943      },
++      {       XFER_UDMA_0,    0x9008d943      },
++
++      {       XFER_MW_DMA_2,  0xa008d943      },
++      {       XFER_MW_DMA_1,  0xa010d955      },
++      {       XFER_MW_DMA_0,  0xa010d9fc      },
++
++      {       XFER_PIO_4,     0xc008d963      },
++      {       XFER_PIO_3,     0xc010d974      },
++      {       XFER_PIO_2,     0xc010d997      },
++      {       XFER_PIO_1,     0xc010d9c7      },
++      {       XFER_PIO_0,     0xc018d9d9      },
++      {       0,              0x0120d9d9      }
++};
+-      {       XFER_UDMA_4,    0x900fd943,     0x900fd943      },
+-      {       XFER_UDMA_3,    0x900ad943,     0x900ad943      },
+-      {       XFER_UDMA_2,    0x900bd943,     0x900bd943      },
+-      {       XFER_UDMA_1,    0x9008d943,     0x9008d943      },
+-      {       XFER_UDMA_0,    0x9008d943,     0x9008d943      },
+-
+-      {       XFER_MW_DMA_2,  0xa008d943,     0xa008d943      },
+-      {       XFER_MW_DMA_1,  0xa010d955,     0xa010d955      },
+-      {       XFER_MW_DMA_0,  0xa010d9fc,     0xa010d9fc      },
+-
+-      {       XFER_PIO_4,     0xc008d963,     0xc008d963      },
+-      {       XFER_PIO_3,     0xc010d974,     0xc010d974      },
+-      {       XFER_PIO_2,     0xc010d997,     0xc010d997      },
+-      {       XFER_PIO_1,     0xc010d9c7,     0xc010d9c7      },
+-      {       XFER_PIO_0,     0xc018d9d9,     0xc018d9d9      },
+-      {       0,              0x0120d9d9,     0x0120d9d9      }
+-};
+-
+-struct chipset_bus_clock_list_entry thirty_three_base [] = {
+-
+-      {       XFER_UDMA_4,    0x90c9a731,     0x90c9a731      },
+-      {       XFER_UDMA_3,    0x90cfa731,     0x90cfa731      },
+-      {       XFER_UDMA_2,    0x90caa731,     0x90caa731      },
+-      {       XFER_UDMA_1,    0x90cba731,     0x90cba731      },
+-      {       XFER_UDMA_0,    0x90c8a731,     0x90c8a731      },
+-
+-      {       XFER_MW_DMA_2,  0xa0c8a731,     0xa0c8a731      },
+-      {       XFER_MW_DMA_1,  0xa0c8a732,     0xa0c8a732      },      /* 0xa0c8a733 */
+-      {       XFER_MW_DMA_0,  0xa0c8a797,     0xa0c8a797      },
+-
+-      {       XFER_PIO_4,     0xc0c8a731,     0xc0c8a731      },
+-      {       XFER_PIO_3,     0xc0c8a742,     0xc0c8a742      },
+-      {       XFER_PIO_2,     0xc0d0a753,     0xc0d0a753      },
+-      {       XFER_PIO_1,     0xc0d0a7a3,     0xc0d0a7a3      },      /* 0xc0d0a793 */
+-      {       XFER_PIO_0,     0xc0d0a7aa,     0xc0d0a7aa      },      /* 0xc0d0a7a7 */
+-      {       0,              0x0120a7a7,     0x0120a7a7      }
+-};
+-
+-struct chipset_bus_clock_list_entry twenty_five_base [] = {
+-
+-      {       XFER_UDMA_4,    0x90c98521,     0x90c98521      },
+-      {       XFER_UDMA_3,    0x90cf8521,     0x90cf8521      },
+-      {       XFER_UDMA_2,    0x90cf8521,     0x90cf8521      },
+-      {       XFER_UDMA_1,    0x90cb8521,     0x90cb8521      },
+-      {       XFER_UDMA_0,    0x90cb8521,     0x90cb8521      },
+-
+-      {       XFER_MW_DMA_2,  0xa0ca8521,     0xa0ca8521      },
+-      {       XFER_MW_DMA_1,  0xa0ca8532,     0xa0ca8532      },
+-      {       XFER_MW_DMA_0,  0xa0ca8575,     0xa0ca8575      },
+-
+-      {       XFER_PIO_4,     0xc0ca8521,     0xc0ca8521      },
+-      {       XFER_PIO_3,     0xc0ca8532,     0xc0ca8532      },
+-      {       XFER_PIO_2,     0xc0ca8542,     0xc0ca8542      },
+-      {       XFER_PIO_1,     0xc0d08572,     0xc0d08572      },
+-      {       XFER_PIO_0,     0xc0d08585,     0xc0d08585      },
+-      {       0,              0x01208585,     0x01208585      }
++struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
++      {       XFER_UDMA_4,    0x90c9a731      },
++      {       XFER_UDMA_3,    0x90cfa731      },
++      {       XFER_UDMA_2,    0x90caa731      },
++      {       XFER_UDMA_1,    0x90cba731      },
++      {       XFER_UDMA_0,    0x90c8a731      },
++
++      {       XFER_MW_DMA_2,  0xa0c8a731      },
++      {       XFER_MW_DMA_1,  0xa0c8a732      },      /* 0xa0c8a733 */
++      {       XFER_MW_DMA_0,  0xa0c8a797      },
++
++      {       XFER_PIO_4,     0xc0c8a731      },
++      {       XFER_PIO_3,     0xc0c8a742      },
++      {       XFER_PIO_2,     0xc0d0a753      },
++      {       XFER_PIO_1,     0xc0d0a7a3      },      /* 0xc0d0a793 */
++      {       XFER_PIO_0,     0xc0d0a7aa      },      /* 0xc0d0a7a7 */
++      {       0,              0x0120a7a7      }
+ };
++struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
++
++      {       XFER_UDMA_4,    0x90c98521      },
++      {       XFER_UDMA_3,    0x90cf8521      },
++      {       XFER_UDMA_2,    0x90cf8521      },
++      {       XFER_UDMA_1,    0x90cb8521      },
++      {       XFER_UDMA_0,    0x90cb8521      },
++
++      {       XFER_MW_DMA_2,  0xa0ca8521      },
++      {       XFER_MW_DMA_1,  0xa0ca8532      },
++      {       XFER_MW_DMA_0,  0xa0ca8575      },
++
++      {       XFER_PIO_4,     0xc0ca8521      },
++      {       XFER_PIO_3,     0xc0ca8532      },
++      {       XFER_PIO_2,     0xc0ca8542      },
++      {       XFER_PIO_1,     0xc0d08572      },
++      {       XFER_PIO_0,     0xc0d08585      },
++      {       0,              0x01208585      }
++};
++
++/* from highpoint documentation. these are old values */
+ struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+-      {       XFER_UDMA_5,    0x1A85F442,     0x16454e31      },
+-      {       XFER_UDMA_4,    0x16454e31,     0x16454e31      },
+-      {       XFER_UDMA_3,    0x166d4e31,     0x166d4e31      },
+-      {       XFER_UDMA_2,    0x16494e31,     0x16494e31      },
+-      {       XFER_UDMA_1,    0x164d4e31,     0x164d4e31      },
+-      {       XFER_UDMA_0,    0x16514e31,     0x16514e31      },
+-
+-      {       XFER_MW_DMA_2,  0x26514e21,     0x26514e21      },
+-      {       XFER_MW_DMA_1,  0x26514e33,     0x26514e33      },
+-      {       XFER_MW_DMA_0,  0x26514e97,     0x26514e97      },
+-
+-      {       XFER_PIO_4,     0x06514e21,     0x06514e21      },
+-      {       XFER_PIO_3,     0x06514e22,     0x06514e22      },
+-      {       XFER_PIO_2,     0x06514e33,     0x06514e33      },
+-      {       XFER_PIO_1,     0x06914e43,     0x06914e43      },
+-      {       XFER_PIO_0,     0x06914e57,     0x06914e57      },
+-      {       0,              0x06514e57,     0x06514e57      }
++/*    {       XFER_UDMA_5,    0x1A85F442,     0x16454e31      }, */
++      {       XFER_UDMA_5,    0x16454e31      },
++      {       XFER_UDMA_4,    0x16454e31      },
++      {       XFER_UDMA_3,    0x166d4e31      },
++      {       XFER_UDMA_2,    0x16494e31      },
++      {       XFER_UDMA_1,    0x164d4e31      },
++      {       XFER_UDMA_0,    0x16514e31      },
++
++      {       XFER_MW_DMA_2,  0x26514e21      },
++      {       XFER_MW_DMA_1,  0x26514e33      },
++      {       XFER_MW_DMA_0,  0x26514e97      },
++
++      {       XFER_PIO_4,     0x06514e21      },
++      {       XFER_PIO_3,     0x06514e22      },
++      {       XFER_PIO_2,     0x06514e33      },
++      {       XFER_PIO_1,     0x06914e43      },
++      {       XFER_PIO_0,     0x06914e57      },
++      {       0,              0x06514e57      }
++};
++
++struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
++      {       XFER_UDMA_5,    0x14846231      },
++      {       XFER_UDMA_4,    0x14886231      },
++      {       XFER_UDMA_3,    0x148c6231      },
++      {       XFER_UDMA_2,    0x148c6231      },
++      {       XFER_UDMA_1,    0x14906231      },
++      {       XFER_UDMA_0,    0x14986231      },
++      
++      {       XFER_MW_DMA_2,  0x26514e21      },
++      {       XFER_MW_DMA_1,  0x26514e33      },
++      {       XFER_MW_DMA_0,  0x26514e97      },
++      
++      {       XFER_PIO_4,     0x06514e21      },
++      {       XFER_PIO_3,     0x06514e22      },
++      {       XFER_PIO_2,     0x06514e33      },
++      {       XFER_PIO_1,     0x06914e43      },
++      {       XFER_PIO_0,     0x06914e57      },
++      {       0,              0x06514e57      }
++};
++
++/* these are the current (4 sep 2001) timings from highpoint */
++struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
++        {       XFER_UDMA_5,    0x12446231      },
++        {       XFER_UDMA_4,    0x12446231      },
++        {       XFER_UDMA_3,    0x126c6231      },
++        {       XFER_UDMA_2,    0x12486231      },
++        {       XFER_UDMA_1,    0x124c6233      },
++        {       XFER_UDMA_0,    0x12506297      },
++
++        {       XFER_MW_DMA_2,  0x22406c31      },
++        {       XFER_MW_DMA_1,  0x22406c33      },
++        {       XFER_MW_DMA_0,  0x22406c97      },
++
++        {       XFER_PIO_4,     0x06414e31      },
++        {       XFER_PIO_3,     0x06414e42      },
++        {       XFER_PIO_2,     0x06414e53      },
++        {       XFER_PIO_1,     0x06814e93      },
++        {       XFER_PIO_0,     0x06814ea7      },
++        {       0,              0x06814ea7      }
++};
++
++/* 2x 33MHz timings */
++struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
++      {       XFER_UDMA_5,    0x1488e673       },
++      {       XFER_UDMA_4,    0x1488e673       },
++      {       XFER_UDMA_3,    0x1498e673       },
++      {       XFER_UDMA_2,    0x1490e673       },
++      {       XFER_UDMA_1,    0x1498e677       },
++      {       XFER_UDMA_0,    0x14a0e73f       },
++
++      {       XFER_MW_DMA_2,  0x2480fa73       },
++      {       XFER_MW_DMA_1,  0x2480fa77       }, 
++      {       XFER_MW_DMA_0,  0x2480fb3f       },
++
++      {       XFER_PIO_4,     0x0c82be73       },
++      {       XFER_PIO_3,     0x0c82be95       },
++      {       XFER_PIO_2,     0x0c82beb7       },
++      {       XFER_PIO_1,     0x0d02bf37       },
++      {       XFER_PIO_0,     0x0d02bf5f       },
++      {       0,              0x0d02bf5f       }
++};
++
++struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
++      {       XFER_UDMA_5,    0x12848242      },
++      {       XFER_UDMA_4,    0x12ac8242      },
++      {       XFER_UDMA_3,    0x128c8242      },
++      {       XFER_UDMA_2,    0x120c8242      },
++      {       XFER_UDMA_1,    0x12148254      },
++      {       XFER_UDMA_0,    0x121882ea      },
++
++      {       XFER_MW_DMA_2,  0x22808242      },
++      {       XFER_MW_DMA_1,  0x22808254      },
++      {       XFER_MW_DMA_0,  0x228082ea      },
++
++      {       XFER_PIO_4,     0x0a81f442      },
++      {       XFER_PIO_3,     0x0a81f443      },
++      {       XFER_PIO_2,     0x0a81f454      },
++      {       XFER_PIO_1,     0x0ac1f465      },
++      {       XFER_PIO_0,     0x0ac1f48a      },
++      {       0,              0x0ac1f48a      }
+ };
++struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
++      {       XFER_UDMA_6,    0x1c81dc62      },
++      {       XFER_UDMA_5,    0x1c6ddc62      },
++      {       XFER_UDMA_4,    0x1c8ddc62      },
++      {       XFER_UDMA_3,    0x1c8edc62      },      /* checkme */
++      {       XFER_UDMA_2,    0x1c91dc62      },
++      {       XFER_UDMA_1,    0x1c9adc62      },      /* checkme */
++      {       XFER_UDMA_0,    0x1c82dc62      },      /* checkme */
++
++      {       XFER_MW_DMA_2,  0x2c829262      },
++      {       XFER_MW_DMA_1,  0x2c829266      },      /* checkme */
++      {       XFER_MW_DMA_0,  0x2c82922e      },      /* checkme */
++
++      {       XFER_PIO_4,     0x0c829c62      },
++      {       XFER_PIO_3,     0x0c829c84      },
++      {       XFER_PIO_2,     0x0c829ca6      },
++      {       XFER_PIO_1,     0x0d029d26      },
++      {       XFER_PIO_0,     0x0d029d5e      },
++      {       0,              0x0d029d5e      }
++};
++
++struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
++      {       XFER_UDMA_5,    0x12848242      },
++      {       XFER_UDMA_4,    0x12ac8242      },
++      {       XFER_UDMA_3,    0x128c8242      },
++      {       XFER_UDMA_2,    0x120c8242      },
++      {       XFER_UDMA_1,    0x12148254      },
++      {       XFER_UDMA_0,    0x121882ea      },
++
++      {       XFER_MW_DMA_2,  0x22808242      },
++      {       XFER_MW_DMA_1,  0x22808254      },
++      {       XFER_MW_DMA_0,  0x228082ea      },
++
++      {       XFER_PIO_4,     0x0a81f442      },
++      {       XFER_PIO_3,     0x0a81f443      },
++      {       XFER_PIO_2,     0x0a81f454      },
++      {       XFER_PIO_1,     0x0ac1f465      },
++      {       XFER_PIO_0,     0x0ac1f48a      },
++      {       0,              0x0a81f443      }
++};
++
++struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
++      {       XFER_UDMA_6,    0x1c869c62      },
++      {       XFER_UDMA_5,    0x1cae9c62      },
++      {       XFER_UDMA_4,    0x1c8a9c62      },
++      {       XFER_UDMA_3,    0x1c8e9c62      },
++      {       XFER_UDMA_2,    0x1c929c62      },
++      {       XFER_UDMA_1,    0x1c9a9c62      },
++      {       XFER_UDMA_0,    0x1c829c62      },
++
++      {       XFER_MW_DMA_2,  0x2c829c62      },
++      {       XFER_MW_DMA_1,  0x2c829c66      },
++      {       XFER_MW_DMA_0,  0x2c829d2e      },
++
++      {       XFER_PIO_4,     0x0c829c62      },
++      {       XFER_PIO_3,     0x0c829c84      },
++      {       XFER_PIO_2,     0x0c829ca6      },
++      {       XFER_PIO_1,     0x0d029d26      },
++      {       XFER_PIO_0,     0x0d029d5e      },
++      {       0,              0x0d029d26      }
++};
++
++struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
++      {       XFER_UDMA_6,    0x12808242      },
++      {       XFER_UDMA_5,    0x12848242      },
++      {       XFER_UDMA_4,    0x12ac8242      },
++      {       XFER_UDMA_3,    0x128c8242      },
++      {       XFER_UDMA_2,    0x120c8242      },
++      {       XFER_UDMA_1,    0x12148254      },
++      {       XFER_UDMA_0,    0x121882ea      },
++
++      {       XFER_MW_DMA_2,  0x22808242      },
++      {       XFER_MW_DMA_1,  0x22808254      },
++      {       XFER_MW_DMA_0,  0x228082ea      },
++
++      {       XFER_PIO_4,     0x0a81f442      },
++      {       XFER_PIO_3,     0x0a81f443      },
++      {       XFER_PIO_2,     0x0a81f454      },
++      {       XFER_PIO_1,     0x0ac1f465      },
++      {       XFER_PIO_0,     0x0ac1f48a      },
++      {       0,              0x06814e93      }
++};
++
++#if 0
++struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
++      {       XFER_UDMA_6,    },
++      {       XFER_UDMA_5,    },
++      {       XFER_UDMA_4,    },
++      {       XFER_UDMA_3,    },
++      {       XFER_UDMA_2,    },
++      {       XFER_UDMA_1,    },
++      {       XFER_UDMA_0,    },
++      {       XFER_MW_DMA_2,  },
++      {       XFER_MW_DMA_1,  },
++      {       XFER_MW_DMA_0,  },
++      {       XFER_PIO_4,     },
++      {       XFER_PIO_3,     },
++      {       XFER_PIO_2,     },
++      {       XFER_PIO_1,     },
++      {       XFER_PIO_0,     },
++      {       0,      }
++};
++#endif
++#if 0
++struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
++      {       XFER_UDMA_6,    0x12406231      },      /* checkme */
++      {       XFER_UDMA_5,    0x12446231      },
++                              0x14846231
++      {       XFER_UDMA_4,            0x16814ea7      },
++                              0x14886231
++      {       XFER_UDMA_3,            0x16814ea7      },
++                              0x148c6231
++      {       XFER_UDMA_2,            0x16814ea7      },
++                              0x148c6231
++      {       XFER_UDMA_1,            0x16814ea7      },
++                              0x14906231
++      {       XFER_UDMA_0,            0x16814ea7      },
++                              0x14986231
++      {       XFER_MW_DMA_2,          0x16814ea7      },
++                              0x26514e21
++      {       XFER_MW_DMA_1,          0x16814ea7      },
++                              0x26514e97
++      {       XFER_MW_DMA_0,          0x16814ea7      },
++                              0x26514e97
++      {       XFER_PIO_4,             0x06814ea7      },
++                              0x06514e21
++      {       XFER_PIO_3,             0x06814ea7      },
++                              0x06514e22
++      {       XFER_PIO_2,             0x06814ea7      },
++                              0x06514e33
++      {       XFER_PIO_1,             0x06814ea7      },
++                              0x06914e43
++      {       XFER_PIO_0,             0x06814ea7      },
++                              0x06914e57
++      {       0,              0x06814ea7      }
++};
++#endif
++
+ #define HPT366_DEBUG_DRIVE_INFO               0
++#define HPT374_ALLOW_ATA133_6         0
++#define HPT371_ALLOW_ATA133_6         0
++#define HPT302_ALLOW_ATA133_6         0
++#define HPT372_ALLOW_ATA133_6         1
+ #define HPT370_ALLOW_ATA100_5         1
+ #define HPT366_ALLOW_ATA66_4          1
+ #define HPT366_ALLOW_ATA66_3          1
++#define HPT366_MAX_DEVS                       8
++
++#define F_LOW_PCI_33      0x23
++#define F_LOW_PCI_40      0x29
++#define F_LOW_PCI_50      0x2d
++#define F_LOW_PCI_66      0x42
++
++static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
++static int n_hpt_devs;
++
++static unsigned int hpt_revision(struct pci_dev *dev);
++static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
++
++byte hpt366_proc = 0;
++byte hpt363_shared_irq;
++byte hpt363_shared_pin;
+ #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+ static int hpt366_get_info(char *, char **, off_t, int);
+ extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+-static struct pci_dev *bmide_dev;
+-static struct pci_dev *bmide2_dev;
+ static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+-      char *p         = buffer;
+-      u32 bibma       = bmide_dev->resource[4].start;
+-      u32 bibma2      = bmide2_dev->resource[4].start;
+-      char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
+-      u8  c0 = 0, c1 = 0;
+-      u32 class_rev;
+-
+-      pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
+-      class_rev &= 0xff;
+-
+-        /*
+-         * at that point bibma+0x2 et bibma+0xa are byte registers
+-         * to investigate:
+-         */
+-      c0 = inb_p((unsigned short)bibma + 0x02);
+-      if (bmide2_dev)
+-              c1 = inb_p((unsigned short)bibma2 + 0x02);
+-
+-      p += sprintf(p, "\n                                %s Chipset.\n", chipset_names[class_rev]);
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+-      p += sprintf(p, "                %sabled                         %sabled\n",
+-                      (c0&0x80) ? "dis" : " en",
+-                      (c1&0x80) ? "dis" : " en");
+-      p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+-      p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
+-                      (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+-                      (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+-
+-      p += sprintf(p, "UDMA\n");
+-      p += sprintf(p, "DMA\n");
+-      p += sprintf(p, "PIO\n");
++      char *p = buffer;
++      char *chipset_nums[] = {"366", "366",  "368",
++                              "370", "370A", "372",
++                              "302", "371",  "374" };
++      int i;
++
++      p += sprintf(p, "\n                             "
++              "HighPoint HPT366/368/370/372/374\n");
++      for (i = 0; i < n_hpt_devs; i++) {
++              struct pci_dev *dev = hpt_devs[i];
++              unsigned long iobase = dev->resource[4].start;
++              u32 class_rev = hpt_revision(dev);
++              u8 c0, c1;
++
++              p += sprintf(p, "\nController: %d\n", i);
++              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 (hpt_minimum_revision(dev, 3)) {
++                      u8 cbl;
++                      cbl = inb_p(iobase + 0x7b);
++                      outb_p(cbl | 1, iobase + 0x7b);
++                      outb_p(cbl & ~1, iobase + 0x7b);
++                      cbl = inb_p(iobase + 0x7a);
++                      p += sprintf(p, "Cable:          ATA-%d"
++                                      "                          ATA-%d\n",
++                              (cbl & 0x02) ? 33 : 66,
++                              (cbl & 0x01) ? 33 : 66);
++                      p += sprintf(p, "\n");
++              }
++              p += sprintf(p, "--------------- drive0 --------- drive1 "
++                              "------- drive0 ---------- drive1 -------\n");
++              p += sprintf(p, "DMA capable:    %s              %s" 
++                              "            %s               %s\n",
++                      (c0 & 0x20) ? "yes" : "no ", 
++                      (c0 & 0x40) ? "yes" : "no ",
++                      (c1 & 0x20) ? "yes" : "no ", 
++                      (c1 & 0x40) ? "yes" : "no ");
++
++              {
++                      u8 c2, c3;
++                      /* older revs don't have these registers mapped 
++                       * into io space */
++                      pci_read_config_byte(dev, 0x43, &c0);
++                      pci_read_config_byte(dev, 0x47, &c1);
++                      pci_read_config_byte(dev, 0x4b, &c2);
++                      pci_read_config_byte(dev, 0x4f, &c3);
++
++                      p += sprintf(p, "Mode:           %s             %s"
++                                      "           %s              %s\n",
++                              (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
++                                      (c0 & 0x80) ? "PIO " : "off ",
++                              (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
++                                      (c1 & 0x80) ? "PIO " : "off ",
++                              (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
++                                      (c2 & 0x80) ? "PIO " : "off ",
++                              (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
++                                      (c3 & 0x80) ? "PIO " : "off ");
++              }
++      }
++      p += sprintf(p, "\n");
++      
+       return p-buffer;/* => must be less than 4k! */
+ }
+ #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+-byte hpt366_proc = 0;
+-
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-byte hpt363_shared_irq;
+-byte hpt363_shared_pin;
+-
+-static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
++static unsigned int hpt_revision (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);
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_TTI_HPT374:
++                      class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
++              case PCI_DEVICE_ID_TTI_HPT371:
++                      class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
++              case PCI_DEVICE_ID_TTI_HPT302:
++                      class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
++              case PCI_DEVICE_ID_TTI_HPT372:
++                      class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
++              default:
++                      break;
++      }
++      return class_rev;
+ }
+-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
++static unsigned int hpt_minimum_revision (struct pci_dev *dev, int revision)
+ {
+-      unsigned int class_rev;
+-      pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+-      class_rev &= 0xff;
+-      return ((int) (class_rev > 0x01) ? 1 : 0);
++      unsigned int class_rev = hpt_revision(dev);
++      revision--;
++      return ((int) (class_rev > revision) ? 1 : 0);
++}
++
++static int check_in_drive_lists(ide_drive_t *drive, const char **list);
++
++static byte hpt3xx_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
++      byte mode = 0x00;
++
++      if (hpt_minimum_revision(dev, 8)) {             /* HPT374 */
++              mode |= (HPT374_ALLOW_ATA133_6) ? 0x04 : 0x03;
++      } else if (hpt_minimum_revision(dev, 7)) {      /* HPT371 */
++              mode |= (HPT371_ALLOW_ATA133_6) ? 0x04 : 0x03;
++      } else if (hpt_minimum_revision(dev, 6)) {      /* HPT302 */
++              mode |= (HPT302_ALLOW_ATA133_6) ? 0x04 : 0x03;
++      } else if (hpt_minimum_revision(dev, 5)) {      /* HPT372 */
++              mode |= (HPT372_ALLOW_ATA133_6) ? 0x04 : 0x03;
++      } else if (hpt_minimum_revision(dev, 4)) {      /* HPT370A */
++              mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
++      } else if (hpt_minimum_revision(dev, 3)) {      /* HPT370 */
++              mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
++              if (check_in_drive_lists(drive, bad_ata33))
++                      return (mode &= ~0xFF);
++      } else {                                        /* HPT366 and HPT368 */
++              mode |= 0x02;
++              if (check_in_drive_lists(drive, bad_ata33))
++                      return (mode &= ~0xFF);
++      }
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte hpt3xx_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = hpt3xx_ratemask(drive);
++
++      if (drive->media != ide_disk)
++              while (speed > XFER_PIO_4) speed--;
++
++      switch(mode) {
++              case 0x04:
++                      while (speed > XFER_UDMA_6) speed--;
++                      break;
++              case 0x03:
++                      while (speed > XFER_UDMA_5) speed--;
++                      if (hpt_minimum_revision(dev, 5))
++                              break;
++                      if (check_in_drive_lists(drive, bad_ata100_5))
++                              while (speed > XFER_UDMA_4) speed--;
++                      break;
++              case 0x02:
++                      while (speed > XFER_UDMA_4) speed--;
++      /*
++       * CHECK ME, Does this need to be set to 5 ??
++       */
++                      if (hpt_minimum_revision(dev, 3))
++                              break;
++                      if ((check_in_drive_lists(drive, bad_ata66_4)) ||
++                          (!(HPT366_ALLOW_ATA66_4)))
++                              while (speed > XFER_UDMA_3) speed--;
++                      if ((check_in_drive_lists(drive, bad_ata66_3)) ||
++                          (!(HPT366_ALLOW_ATA66_3)))
++                              while (speed > XFER_UDMA_2) speed--;
++                      break;
++              case 0x01:
++                      while (speed > XFER_UDMA_2) speed--;
++      /*
++       * CHECK ME, Does this need to be set to 5 ??
++       */
++                      if (hpt_minimum_revision(dev, 3))
++                              break;
++                      if (check_in_drive_lists(drive, bad_ata33))
++                              while (speed > XFER_MW_DMA_2) speed--;
++                      break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
+ }
+ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+@@ -282,51 +709,44 @@
+       return 0;
+ }
+-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
++static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+ {
+       for ( ; chipset_table->xfer_speed ; chipset_table++)
+               if (chipset_table->xfer_speed == speed) {
+-                      return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
++                      return chipset_table->chipset_settings;
+               }
+-      return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
++      return chipset_table->chipset_settings;
+ }
+-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
++static void hpt366_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte speed              = hpt3xx_ratefilter(drive, xferspeed);
+       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.
+-                       */
+-
++      byte drive_fast         = 0;
+       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);
++      pci_read_config_byte(dev, regfast, &drive_fast);
++#if 0
+       if (drive_fast & 0x02)
+-              pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
++              pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
++#else
++      if (drive_fast & 0x80)
++              pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
++#endif
+-      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, direction, forty_base);
+-                      break;
+-              case 9:
+-                      reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+-                      break;
+-              default:
+-              case 7:
+-                      reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+-                      break;
+-      }
++      reg2 = pci_bus_clock_list(speed,
++              (struct chipset_bus_clock_list_entry *) dev->driver_data);
+       /*
+-       * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
++       * Disable on-chip PIO FIFO/buffer
++       *  (to avoid problems handling I/O errors later)
+        */
++      pci_read_config_dword(dev, regtime, &reg1);
+       if (speed >= XFER_MW_DMA_0) {
+               reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+       } else {
+@@ -334,109 +754,127 @@
+       }       
+       reg2 &= ~0x80000000;
+-      pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
++      pci_write_config_dword(dev, regtime, reg2);
+ }
+-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
++static void hpt368_tune_chipset (ide_drive_t *drive, byte speed)
+ {
++      hpt366_tune_chipset(drive, speed);
++}
++
++static void hpt370_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++      byte speed              = hpt3xx_ratefilter(drive, xferspeed);
+       byte regfast            = (HWIF(drive)->channel) ? 0x55 : 0x51;
+-      byte reg5bh             = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
+-      unsigned int list_conf  = pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
++      unsigned int list_conf  = 0;
+       unsigned int drive_conf = 0;
+       unsigned int conf_mask  = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+-      byte drive_pci          = 0;
+-      byte drive_fast         = 0;
++      byte drive_pci          = 0x40 + (drive->dn * 4);
++      byte new_fast, drive_fast               = 0;
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
+-      switch (drive->dn) {
+-              case 0: drive_pci = 0x40; break;
+-              case 1: drive_pci = 0x44; break;
+-              case 2: drive_pci = 0x48; break;
+-              case 3: drive_pci = 0x4c; break;
+-              default: return;
+-      }
+       /*
+        * Disable the "fast interrupt" prediction.
++       * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+        */
+-      pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
+-      if (drive_fast & 0x80)
+-              pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
++      pci_read_config_byte(dev, regfast, &drive_fast);
++      new_fast = drive_fast;
++      if (new_fast & 0x02)
++              new_fast &= ~0x02;
++
++#ifdef HPT_DELAY_INTERRUPT
++      if (new_fast & 0x01)
++              new_fast &= ~0x01;
++#else
++      if ((new_fast & 0x01) == 0)
++              new_fast |= 0x01;
++#endif
++      if (new_fast != drive_fast)
++              pci_write_config_byte(dev, regfast, new_fast);
+-      pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
+-      pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
++      list_conf = pci_bus_clock_list(speed, 
++                                     (struct chipset_bus_clock_list_entry *)
++                                     dev->driver_data);
++      pci_read_config_dword(dev, drive_pci, &drive_conf);
+       list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+-      /*
+-       * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
+-       */
+-      list_conf &= ~0x80000000;
++      
++      if (speed < XFER_MW_DMA_0) {
++              list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
++      }
+-      pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
++      pci_write_config_dword(dev, drive_pci, list_conf);
+ }
+-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
++static void hpt372_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+-      if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+-              return -1;
++      byte speed              = hpt3xx_ratefilter(drive, xferspeed);
++      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 drive_fast         = 0;
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
++      /*
++       * Disable the "fast interrupt" prediction.
++       * don't holdoff on interrupts. (== 0x01 despite what the docs say)
++       */
++      pci_read_config_byte(dev, regfast, &drive_fast);
++      drive_fast &= ~0x07;
++      pci_write_config_byte(dev, regfast, drive_fast);
++                                      
++      list_conf = pci_bus_clock_list(speed,
++                      (struct chipset_bus_clock_list_entry *)
++                                      dev->driver_data);
++      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);
++}
+-      if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+-              hpt370_tune_chipset(drive, speed, 0);
+-        } else {
+-                hpt366_tune_chipset(drive, speed, 0);
+-        }
+-      drive->current_speed = speed;
+-      return ((int) ide_config_drive_speed(drive, speed));
++static void hpt374_tune_chipset (ide_drive_t *drive, byte speed)
++{
++      hpt372_tune_chipset(drive, speed);
+ }
+-static void config_chipset_for_pio (ide_drive_t *drive)
++static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
+ {
+-      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;
+-      }
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
+-      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);
++      if (hpt_minimum_revision(dev, 8))
++              hpt374_tune_chipset(drive, speed);
++#if 0
++      else if (hpt_minimum_revision(dev, 7))
++              hpt371_tune_chipset(drive, speed);
++      else if (hpt_minimum_revision(dev, 6))
++              hpt302_tune_chipset(drive, speed);
++#endif
++      else if (hpt_minimum_revision(dev, 5))
++              hpt372_tune_chipset(drive, speed);
++      else if (hpt_minimum_revision(dev, 3))
++              hpt370_tune_chipset(drive, speed);
++      else if (hpt_minimum_revision(dev, 2))
++              hpt368_tune_chipset(drive, speed);
++      else
++                hpt366_tune_chipset(drive, speed);
++
++      return ((int) ide_config_drive_speed(drive, speed));
+ }
+ static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
+ {
+       byte speed;
++
++      pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       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;
++              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);
+ }
+@@ -456,54 +894,49 @@
+ static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
++      byte mode               = hpt3xx_ratemask(drive);
+       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 (drive->media != ide_disk)
++              mode |= 0x08;
+-      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);
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
+       (void) hpt3xx_tune_chipset(drive, speed);
+-      rval = (int)(   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
++      return ((int)   ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
++                      ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+-      return rval;
+ }
+ int hpt3xx_quirkproc (ide_drive_t *drive)
+@@ -513,21 +946,22 @@
+ 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]);
+-      }
++      if (drive->quirk_list)
++              return;
++      /* drives in the quirk_list may not like intr setups/cleanups */
++      OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+ }
+ void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+ {
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
++
+       if (drive->quirk_list) {
+-              if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
++              if (hpt_minimum_revision(dev,3)) {
+                       byte reg5a = 0;
+-                      pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
++                      pci_read_config_byte(dev, 0x5a, &reg5a);
+                       if (((reg5a & 0x10) >> 4) != mask)
+-                              pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
++                              pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+               } else {
+                       if (mask) {
+                               disable_irq(HWIF(drive)->irq);
+@@ -541,18 +975,13 @@
+       }
+ }
+-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
+-{
+-      if ((func != ide_dma_write) || (func != ide_dma_read))
+-              return;
+-      hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
+-}
+-
+ static int config_drive_xfer_rate (ide_drive_t *drive)
+ {
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
++      drive->init_speed = 0;
++
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -561,7 +990,7 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x007F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+@@ -592,7 +1021,7 @@
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              config_chipset_for_pio(drive);
++              hpt3xx_tune_drive(drive, 5);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
+@@ -605,45 +1034,418 @@
+  */
+ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      unsigned long dma_base  = HWIF(drive)->dma_base;
+       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_test_irq:
++                              /* returns 1 if dma irq issued, 0 otherwise */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* return 1 if INTR asserted */
++                      return (dma_stat & 4) == 4;
+               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",
++                      pci_read_config_byte(dev, 0x50, &reg50h);
++                      pci_read_config_byte(dev, 0x52, &reg52h);
++                      pci_read_config_byte(dev, 0x5a, &reg5ah);
++                      printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x,"
++                              " reg5ah=0x%02x\n",
+                               drive->name,
+                               ide_dmafunc_verbose(func),
+                               reg50h, reg52h, reg5ah);
+                       if (reg5ah & 0x10)
+-                              pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
++                              pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
++#if 0
++                      /* how about we flush and reset, mmmkay? */
++                      pci_write_config_byte(dev, 0x51, 0x1F);
++                      /* fall through to a reset */
++              case ide_dma_begin:
++              case ide_dma_end:
++                      /* reset the chips state over and over.. */
++                      pci_write_config_byte(dev, 0x51, 0x13);
++#endif
+                       break;
+               case ide_dma_timeout:
+               default:
+                       break;
+       }
+-      return ide_dmaproc(func, drive);        /* use standard DMA stuff */
++      /* use standard DMA stuff */
++      return ide_dmaproc(func, drive);
+ }
+ int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      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 = IN_BYTE(dma_base+2);
++                      /* return 1 if INTR asserted */
++                      return (dma_stat & 4) == 4;
++
++              case ide_dma_end:
++                      dma_stat = IN_BYTE(dma_base + 2);
++                      if (dma_stat & 0x01) {
++                              /* wait a little */
++                              udelay(20);
++                              dma_stat = IN_BYTE(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(dev, reginfo, &dma_stat);
++                      printk("%s: %d bytes in FIFO\n", drive->name, 
++                             dma_stat);
++                      pci_write_config_byte(dev, regstate, 0x37);
++                      udelay(10);
++                      dma_stat = IN_BYTE(dma_base);
++                      /* stop dma */
++                      OUT_BYTE(dma_stat & ~0x1, dma_base);
++                      dma_stat = IN_BYTE(dma_base + 2);
++                      /* clear errors */
++                      OUT_BYTE(dma_stat | 0x6, dma_base+2);
++                      /* fallthrough */
++
++#ifdef HPT_RESET_STATE_ENGINE
++              case ide_dma_begin:
++#endif
++                      pci_write_config_byte(dev, regstate, 0x37);
++                      udelay(10);
++                      break;
++
++              default:
++                      break;
++      }
++      /* use standard DMA stuff */
++      return ide_dmaproc(func, drive);
++}
++
++int hpt374_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
++{
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      ide_hwif_t *hwif        = HWIF(drive);
++      unsigned long dma_base  = hwif->dma_base;
++      byte mscreg             = 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 = IN_BYTE(dma_base+2);
++#if 0  /* do not set unless you know what you are doing */
++                      if (dma_stat & 4) {
++                              byte stat = GET_STAT();
++                              OUT_BYTE(dma_base+2, dma_stat & 0xE4);
++                      }
++#endif
++                      /* return 1 if INTR asserted */
++                      return (dma_stat & 4) == 4;
++              case ide_dma_end:
++              {
++                      byte bwsr_mask = hwif->channel ? 0x02 : 0x01;
++                      byte bwsr_stat, msc_stat;
++                      pci_read_config_byte(dev, 0x6a, &bwsr_stat);
++                      pci_read_config_byte(dev, mscreg, &msc_stat);
++                      if ((bwsr_stat & bwsr_mask) == bwsr_mask)
++                              pci_write_config_byte(dev, mscreg, msc_stat|0x30);
++              }
+               default:
+                       break;
+       }
+-      return ide_dmaproc(func, drive);        /* use standard DMA stuff */
++      /* use standard DMA stuff */
++      return ide_dmaproc(func, drive);
+ }
+ #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);
++      struct pci_dev *dev     = hwif->pci_dev;
++      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(dev, tristate, &tri_reg);
++      pci_read_config_byte(dev, 0x59, &bus_reg);
++
++      /* set the state. we don't set it if we don't need to do so.
++       * make sure that the drive knows that it has failed if it's off */
++      switch (state) {
++      case BUSSTATE_ON:
++              hwif->drives[0].failures = 0;
++              hwif->drives[1].failures = 0;
++              if ((bus_reg & resetmask) == 0)
++                      return 0;
++              tri_reg &= ~TRISTATE_BIT;
++              bus_reg &= ~resetmask;
++              break;
++      case BUSSTATE_OFF:
++              hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
++              hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
++              if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
++                      return 0;
++              tri_reg &= ~TRISTATE_BIT;
++              bus_reg |= resetmask;
++              break;
++      case BUSSTATE_TRISTATE:
++              hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
++              hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
++              if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
++                      return 0;
++              tri_reg |= TRISTATE_BIT;
++              bus_reg |= resetmask;
++              break;
++      }
++      pci_write_config_byte(dev, 0x59, bus_reg);
++      pci_write_config_word(dev, tristate, tri_reg);
++
++      return 0;
++}
++
++static void __init init_hpt37x(struct pci_dev *dev)
++{
++      int adjust, i;
++      u16 freq;
++      u32 pll;
++      byte reg5bh;
++
++#if 1
++      byte reg5ah = 0;
++      pci_read_config_byte(dev, 0x5a, &reg5ah);
++      /* interrupt force enable */
++      pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
++#endif
++
++      /*
++       * 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;
++              if (hpt_minimum_revision(dev,8))
++                      dev->driver_data = (void *) thirty_three_base_hpt374;
++              else if (hpt_minimum_revision(dev,5))
++                      dev->driver_data = (void *) thirty_three_base_hpt372;
++              else if (hpt_minimum_revision(dev,4))
++                      dev->driver_data = (void *) thirty_three_base_hpt370a;
++              else
++                      dev->driver_data = (void *) thirty_three_base_hpt370;
++              printk("HPT37X: using 33MHz PCI clock\n");
++      } else if (freq < 0xb0) {
++              pll = F_LOW_PCI_40;
++      } else if (freq < 0xc8) {
++              pll = F_LOW_PCI_50;
++              if (hpt_minimum_revision(dev,8))
++                      BUG();
++              else if (hpt_minimum_revision(dev,5))
++                      dev->driver_data = (void *) fifty_base_hpt372;
++              else if (hpt_minimum_revision(dev,4))
++                      dev->driver_data = (void *) fifty_base_hpt370a;
++              else
++                      dev->driver_data = (void *) fifty_base_hpt370a;
++              printk("HPT37X: using 50MHz PCI clock\n");
++      } else {
++              pll = F_LOW_PCI_66;
++              if (hpt_minimum_revision(dev,8))
++                      BUG();
++              else if (hpt_minimum_revision(dev,5))
++                      dev->driver_data = (void *) sixty_six_base_hpt372;
++              else if (hpt_minimum_revision(dev,4))
++                      dev->driver_data = (void *) sixty_six_base_hpt370a;
++              else
++                      dev->driver_data = (void *) sixty_six_base_hpt370;
++              printk("HPT37X: using 66MHz PCI clock\n");
++      }
++      
++      /*
++       * only try the pll if we don't have a table for the clock
++       * speed that we're running at. NOTE: the internal PLL will
++       * result in slow reads when using a 33MHz PCI clock. we also
++       * don't like to use the PLL because it will cause glitches
++       * on PRST/SRST when the HPT state engine gets reset.
++       */
++      if (dev->driver_data) 
++              goto init_hpt37X_done;
++      
++      /*
++       * adjust PLL based upon PCI clock, enable it, and wait for
++       * stabilization.
++       */
++      adjust = 0;
++      freq = (pll < F_LOW_PCI_50) ? 2 : 4;
++      while (adjust++ < 6) {
++              pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
++                                     pll | 0x100);
++
++              /* wait for clock stabilization */
++              for (i = 0; i < 0x50000; i++) {
++                      pci_read_config_byte(dev, 0x5b, &reg5bh);
++                      if (reg5bh & 0x80) {
++                              /* spin looking for the clock to destabilize */
++                              for (i = 0; i < 0x1000; ++i) {
++                                      pci_read_config_byte(dev, 0x5b, 
++                                                           &reg5bh);
++                                      if ((reg5bh & 0x80) == 0)
++                                              goto pll_recal;
++                              }
++                              pci_read_config_dword(dev, 0x5c, &pll);
++                              pci_write_config_dword(dev, 0x5c, 
++                                                     pll & ~0x100);
++                              pci_write_config_byte(dev, 0x5b, 0x21);
++                              if (hpt_minimum_revision(dev,8))
++                                      BUG();
++                              else if (hpt_minimum_revision(dev,5))
++                                      dev->driver_data = (void *) fifty_base_hpt372;
++                              else if (hpt_minimum_revision(dev,4))
++                                      dev->driver_data = (void *) fifty_base_hpt370a;
++                              else
++                                      dev->driver_data = (void *) fifty_base_hpt370a;
++                              printk("HPT37X: using 50MHz internal PLL\n");
++                              goto init_hpt37X_done;
++                      }
++              }
++pll_recal:
++              if (adjust & 1)
++                      pll -= (adjust >> 1);
++              else
++                      pll += (adjust >> 1);
++      } 
++
++init_hpt37X_done:
++      /* reset state engine */
++      pci_write_config_byte(dev, 0x50, 0x37); 
++      pci_write_config_byte(dev, 0x54, 0x37); 
++      udelay(100);
++}
++
++static void __init init_hpt366 (struct pci_dev *dev)
++{
++      unsigned int reg1       = 0;
++      byte drive_fast         = 0;
++
++      /*
++       * Disable the "fast interrupt" prediction.
++       */
++      pci_read_config_byte(dev, 0x51, &drive_fast);
++      if (drive_fast & 0x80)
++              pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
++      pci_read_config_dword(dev, 0x40, &reg1);
++                                                                      
++      /* detect bus speed by looking at control reg timing: */
++      switch((reg1 >> 8) & 7) {
++              case 5:
++                      dev->driver_data = (void *) forty_base_hpt366;
++                      break;
++              case 9:
++                      dev->driver_data = (void *) twenty_five_base_hpt366;
++                      break;
++              case 7:
++              default:
++                      dev->driver_data = (void *) thirty_three_base_hpt366;
++                      break;
++      }
++
++      if (!dev->driver_data)
++              BUG();
++}
++
+ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
+ {
+       byte test = 0;
+@@ -652,14 +1454,8 @@
+               pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+       pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+-
+-#if 0
+-      if (test != 0x08)
+-              pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
+-#else
+       if (test != (L1_CACHE_BYTES / 4))
+               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+-#endif
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+       if (test != 0x78)
+@@ -673,17 +1469,19 @@
+       if (test != 0x08)
+               pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
++      if (hpt_minimum_revision(dev, 3)) {
++              init_hpt37x(dev);
++              hpt_devs[n_hpt_devs++] = dev;
++      } else {
++              init_hpt366(dev);
++              hpt_devs[n_hpt_devs++] = dev;
++      }
++      
+ #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+       if (!hpt366_proc) {
+               hpt366_proc = 1;
+-              bmide_dev = dev;
+-              if (pci_rev_check_hpt3xx(dev))
+-                      bmide2_dev = dev;
+               hpt366_display_info = &hpt366_get_info;
+       }
+-      if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
+-              bmide2_dev = dev;
+-      }
+ #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+       return dev->irq;
+@@ -692,66 +1490,84 @@
+ 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 & 0x02) ? "33" : "66",
++              ata66, (ata66 & regmask) ? "33" : "66",
+               PCI_FUNC(hwif->pci_dev->devfn));
+ #endif /* DEBUG */
+-      return ((ata66 & 0x02) ? 0 : 1);
++      return ((ata66 & regmask) ? 0 : 1);
+ }
+ void __init ide_init_hpt366 (ide_hwif_t *hwif)
+ {
+-      hwif->tuneproc  = &hpt3xx_tune_drive;
+-      hwif->speedproc = &hpt3xx_tune_chipset;
+-      hwif->quirkproc = &hpt3xx_quirkproc;
+-      hwif->intrproc  = &hpt3xx_intrproc;
+-      hwif->maskproc  = &hpt3xx_maskproc;
+-
+-      if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
+-              /* do nothing now but will split device types */
+-      }
++      struct pci_dev *dev             = hwif->pci_dev;
++      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
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (hwif->dma_base) {
+-              if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+-                      byte reg5ah = 0;
+-                      pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
+-                      if (reg5ah & 0x10)      /* interrupt force enable */
+-                              pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
+-                      hwif->dmaproc = &hpt370_dmaproc;
+-                      hwif->rwproc = &hpt370_rw_proc;
+-              } else {
+-                      hwif->dmaproc = &hpt366_dmaproc;
+-              }
+-              if (!noautodma)
+-                      hwif->autodma = 1;
+-              else
+-                      hwif->autodma = 0;
+-      } else {
+-              hwif->autodma = 0;
++      if (hpt_minimum_revision(dev,3)) {
++              byte reg5ah = 0;
++                      pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
++              /*
++               * set up ioctl for power status.
++               * note: power affects both
++               * drives on each channel
++               */
++              hwif->resetproc = &hpt3xx_reset;
++              hwif->busproc   = &hpt370_busproc;
+               hwif->drives[0].autotune = 1;
+               hwif->drives[1].autotune = 1;
++      } else if (hpt_minimum_revision(dev,2)) {
++              hwif->resetproc = &hpt3xx_reset;
++              hwif->busproc   = &hpt3xx_tristate;
++      } else {
++              hwif->resetproc = &hpt3xx_reset;
++              hwif->busproc   = &hpt3xx_tristate;
+       }
+-#else /* !CONFIG_BLK_DEV_IDEDMA */
+-      hwif->drives[0].autotune = 1;
+-      hwif->drives[1].autotune = 1;
+-      hwif->autodma = 0;
++
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (hpt_minimum_revision(dev,8))
++              hwif->dmaproc   = &hpt374_dmaproc;
++      else if (hpt_minimum_revision(dev,5))
++              hwif->dmaproc   = &hpt374_dmaproc;
++      else if (hpt_minimum_revision(dev,3))
++              hwif->dmaproc   = &hpt370_dmaproc;
++      else if (hpt_minimum_revision(dev,2))
++              hwif->dmaproc   = &hpt366_dmaproc;
++      else
++              hwif->dmaproc   = &hpt366_dmaproc;
++
++
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #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 dma_new = 0, dma_old = IN_BYTE(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 */
++      local_irq_save(flags);
+       dma_new = dma_old;
+       pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+@@ -759,9 +1575,121 @@
+       if (masterdma & 0x30)   dma_new |= 0x20;
+       if (slavedma & 0x30)    dma_new |= 0x40;
+-      if (dma_new != dma_old) outb(dma_new, dmabase+2);
++      if (dma_new != dma_old) OUT_BYTE(dma_new, dmabase+2);
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       ide_setup_dma(hwif, dmabase, 8);
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      struct pci_dev *dev2 = NULL, *findev;
++      ide_pci_device_t *d2;
++
++      if (PCI_FUNC(dev->devfn) & 1)
++              return;
++
++      pci_for_each_dev(findev) {
++              if ((findev->vendor == dev->vendor) &&
++                  (findev->device == dev->device) &&
++                  ((findev->devfn - dev->devfn) == 1) &&
++                  (PCI_FUNC(findev->devfn) & 1)) {
++                      dev2 = findev;
++                      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;
++      } else {
++              byte irq = 0, irq2 = 0;
++              pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
++              pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
++              if (irq != irq2) {
++                      pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
++                      dev2->irq = dev->irq;
++                      printk("%s: pci-config space interrupt fixed.\n",
++                              d->name);
++              }
++      }
++      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);
++
++}
++
++void __init fixup_device_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      struct pci_dev *dev2 = NULL, *findev;
++      ide_pci_device_t *d2;
++      unsigned char pin1 = 0, pin2 = 0;
++      unsigned int class_rev;
++      char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
++                               "HPT370", "HPT370A", "HPT372"};
++
++      if (PCI_FUNC(dev->devfn) & 1)
++              return;
++
++      pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
++      class_rev &= 0xff;
++
++      strcpy(d->name, chipset_names[class_rev]);
++
++      switch(class_rev) {
++              case 5:
++              case 4:
++              case 3: printk("%s: IDE controller on PCI bus %02x dev %02x\n",
++                              d->name, dev->bus->number, dev->devfn);
++                      ide_setup_pci_device(dev, d);
++                      return;
++              default:        break;
++      }
++
++      pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
++      pci_for_each_dev(findev) {
++              if ((findev->vendor == dev->vendor) &&
++                  (findev->device == dev->device) &&
++                  ((findev->devfn - dev->devfn) == 1) &&
++                  (PCI_FUNC(findev->devfn) & 1)) {
++                      dev2 = findev;
++                      pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
++                      hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
++                      hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
++                      if (hpt363_shared_pin && hpt363_shared_irq) {
++                              d->bootable = ON_BOARD;
++                              printk("%s: onboard version of chipset, "
++                                      "pin1=%d pin2=%d\n", d->name,
++                                      pin1, pin2);
++#if 0
++                              /*
++                               * This is the third undocumented detection
++                               * method and is generally required for the
++                               * ABIT-BP6 boards.
++                               */
++                              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);
++}
++
+diff -Nur linux.org/drivers/ide/hptraid.c linux/drivers/ide/hptraid.c
+--- linux.org/drivers/ide/hptraid.c    Mon Oct 15 22:27:42 2001
++++ linux/drivers/ide/hptraid.c        Thu Jul 18 14:23:00 2002
+@@ -123,13 +123,8 @@
+                       return 0;
+               }
+                       
+-              case BLKROSET:
+-              case BLKROGET:
+-              case BLKSSZGET:
+-                      return blk_ioctl(inode->i_rdev, cmd, arg);
+-
+               default:
+-                      return -EINVAL;
++                      return blk_ioctl(inode->i_rdev, cmd, arg);
+       };
+       return 0;
+@@ -366,7 +361,11 @@
+       probedisk(IDE2_MAJOR, 64, device);
+       probedisk(IDE3_MAJOR,  0, device);
+       probedisk(IDE3_MAJOR, 64, device);
+-                                                                      
++      probedisk(IDE4_MAJOR,  0, device);
++      probedisk(IDE4_MAJOR, 64, device);
++      probedisk(IDE5_MAJOR,  0, device);
++      probedisk(IDE5_MAJOR, 64, device);
++
+       fill_cutoff(device);
+       
+       /* Initialize the gendisk structure */
+diff -Nur linux.org/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c
+--- linux.org/drivers/ide/ht6560b.c    Fri Apr 14 07:54:26 2000
++++ linux/drivers/ide/ht6560b.c        Thu Jul 18 14:24:33 2002
+@@ -134,8 +134,7 @@
+       static byte current_timing = 0;
+       byte select, timing;
+       
+-      __save_flags (flags);   /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       
+       select = HT_CONFIG(drive);
+       timing = HT_TIMING(drive);
+@@ -145,21 +144,22 @@
+               current_timing = timing;
+               if (drive->media != ide_disk || !drive->present)
+                       select |= HT_PREFETCH_MODE;
+-              (void) inb(HT_CONFIG_PORT);
+-              (void) inb(HT_CONFIG_PORT);
+-              (void) inb(HT_CONFIG_PORT);
+-              (void) inb(HT_CONFIG_PORT);
+-              outb(select, HT_CONFIG_PORT);
++              (void) IN_BYTE(HT_CONFIG_PORT);
++              (void) IN_BYTE(HT_CONFIG_PORT);
++              (void) IN_BYTE(HT_CONFIG_PORT);
++              (void) IN_BYTE(HT_CONFIG_PORT);
++              OUT_BYTE(select, HT_CONFIG_PORT);
+               /*
+                * Set timing for this drive:
+                */
+-              outb(timing, IDE_SELECT_REG);
+-              (void) inb(IDE_STATUS_REG);
++              OUT_BYTE(timing, IDE_SELECT_REG);
++              (void) IN_BYTE(IDE_STATUS_REG);
+ #ifdef DEBUG
+-              printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
++              printk("ht6560b: %s: select=%#x timing=%#x\n",
++                      drive->name, select, timing);
+ #endif
+       }
+-      __restore_flags (flags);        /* local CPU only */
++      local_irq_restore(flags);
+ }
+ /*
+@@ -171,27 +171,27 @@
+       int i;
+       
+       /* Autodetect ht6560b */
+-      if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
++      if ((orig_value = IN_BYTE(HT_CONFIG_PORT)) == 0xff)
+               return 0;
+       
+       for (i=3;i>0;i--) {
+-              outb(0x00, HT_CONFIG_PORT);
+-              if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+-                      outb(orig_value, HT_CONFIG_PORT);
++              OUT_BYTE(0x00, HT_CONFIG_PORT);
++              if (!( (~IN_BYTE(HT_CONFIG_PORT)) & 0x3f )) {
++                      OUT_BYTE(orig_value, HT_CONFIG_PORT);
+                       return 0;
+               }
+       }
+-      outb(0x00, HT_CONFIG_PORT);
+-      if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+-              outb(orig_value, HT_CONFIG_PORT);
++      OUT_BYTE(0x00, HT_CONFIG_PORT);
++      if ((~IN_BYTE(HT_CONFIG_PORT))& 0x3f) {
++              OUT_BYTE(orig_value, HT_CONFIG_PORT);
+               return 0;
+       }
+       /*
+        * Ht6560b autodetected
+        */
+-      outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+-      outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+-      (void) inb(0x1f7);               /* IDE_STATUS_REG */
++      OUT_BYTE(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
++      OUT_BYTE(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
++      (void) IN_BYTE(0x1f7);               /* IDE_STATUS_REG */
+       
+       printk("\nht6560b " HT6560B_VERSION
+              ": chipset detected and initialized"
+@@ -257,8 +257,7 @@
+       unsigned long flags;
+       int t = HT_PREFETCH_MODE << 8;
+       
+-      save_flags (flags);     /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       
+       /*
+        *  Prefetch mode and unmask irq seems to conflict
+@@ -272,7 +271,7 @@
+               drive->no_unmask = 0;
+       }
+       
+-      restore_flags (flags);  /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       
+ #ifdef DEBUG
+       printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+@@ -293,13 +292,12 @@
+       
+       timing = ht_pio2timings(drive, pio);
+       
+-      save_flags (flags);     /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       
+       drive->drive_data &= 0xff00;
+       drive->drive_data |= timing;
+       
+-      restore_flags (flags);  /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       
+ #ifdef DEBUG
+       printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+diff -Nur linux.org/drivers/ide/icside.c linux/drivers/ide/icside.c
+--- linux.org/drivers/ide/icside.c     Thu Oct 25 22:53:47 2001
++++ linux/drivers/ide/icside.c Thu Jul 18 14:24:33 2002
+@@ -26,8 +26,6 @@
+ #include <asm/ecard.h>
+ #include <asm/io.h>
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-
+ /*
+  * Maximum number of interfaces per card
+  */
+@@ -94,7 +92,7 @@
+ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ {
+       unsigned int memc_port = (unsigned int)ec->irq_data;
+-      outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
++      OUT_BYTE(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+ }
+ /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+@@ -103,7 +101,7 @@
+ static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ {
+       unsigned int memc_port = (unsigned int)ec->irq_data;
+-      inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
++      IN_BYTE(memc_port + ICS_ARCIN_V5_INTROFFSET);
+ }
+ static const expansioncard_ops_t icside_ops_arcin_v5 = {
+@@ -124,8 +122,8 @@
+ {
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+-      outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+-      outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
++      OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
++      OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+ }
+ /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+@@ -135,8 +133,8 @@
+ {
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+-      inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+-      inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
++      IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
++      IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+ }
+ /* Prototype: icside_irqprobe(struct expansion_card *ec)
+@@ -146,8 +144,8 @@
+ {
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+-      return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+-             inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
++      return IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
++             IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+ }
+ static const expansioncard_ops_t icside_ops_arcin_v6 = {
+@@ -173,10 +171,10 @@
+       addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+-      id = inb (addr) & 1;
+-      id |= (inb (addr + 1) & 1) << 1;
+-      id |= (inb (addr + 2) & 1) << 2;
+-      id |= (inb (addr + 3) & 1) << 3;
++      id = IN_BYTE(addr) & 1;
++      id |= (IN_BYTE(addr + 1) & 1) << 1;
++      id |= (IN_BYTE(addr + 2) & 1) << 2;
++      id |= (IN_BYTE(addr + 3) & 1) << 3;
+       switch (id) {
+       case 0: /* A3IN */
+@@ -334,14 +332,14 @@
+                       rq = HWGROUP(drive)->rq;
+                       for (i = rq->nr_sectors; i > 0;) {
+                               i -= rq->current_nr_sectors;
+-                              ide_end_request(1, HWGROUP(drive));
++                              DRIVER(drive)->end_request(drive, 1);
+                       }
+                       return ide_stopped;
+               }
+               printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+                      drive->name, dma_stat);
+       }
+-      return ide_error(drive, "dma_intr", stat);
++      return DRIVER(drive)->error(drive, "dma_intr", stat);
+ }
+ /*
+@@ -493,6 +491,7 @@
+ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+ {
+       ide_hwif_t *hwif = HWIF(drive);
++//    ide_task_t *args = HWGROUP(drive)->rq->special;
+       int count, reading = 0;
+       switch (func) {
+@@ -519,7 +518,7 @@
+               /* Route the DMA signals to
+                * to the correct interface.
+                */
+-              outb(hwif->select_data, hwif->config_data);
++              OUT_BYTE(hwif->select_data, hwif->config_data);
+               /* Select the correct timing
+                * for this drive
+@@ -534,10 +533,27 @@
+               if (drive->media != ide_disk)
+                       return 0;
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+-              OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
+-                       IDE_COMMAND_REG);
+-
++              /*
++               * FIX ME to use only ACB ide_task_t args Struct
++               */
++#if 0
++      {
++              ide_task_t *args = HWGROUP(drive)->rq->special;
++              OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++      }
++#else
++              if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
++                      ide_task_t *args = HWGROUP(drive)->rq->special;
++                      OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++              } else if (drive->addressing == 1)
++                      OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
++              else
++                      OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++#endif
++              return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+       case ide_dma_begin:
+               enable_dma(hwif->hw.dma);
+               return 0;
+@@ -549,7 +565,7 @@
+               return get_dma_residue(hwif->hw.dma) != 0;
+       case ide_dma_test_irq:
+-              return inb((unsigned long)hwif->hw.priv) & 1;
++              return IN_BYTE((unsigned long)hwif->hw.priv) & 1;
+       case ide_dma_bad_drive:
+       case ide_dma_good_drive:
+@@ -660,7 +676,7 @@
+       /*
+        * Be on the safe side - disable interrupts
+        */
+-      inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
++      IN_BYTE(slot_port + ICS_ARCIN_V5_INTROFFSET);
+       hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+@@ -681,7 +697,7 @@
+       else
+               sel = 1 << 5;
+-      outb(sel, slot_port);
++      OUT_BYTE(sel, slot_port);
+       ec->irq_data = (void *)port;
+       ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+@@ -689,8 +705,8 @@
+       /*
+        * Be on the safe side - disable interrupts
+        */
+-      inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+-      inb(port + ICS_ARCIN_V6_INTROFFSET_2);
++      IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_1);
++      IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_2);
+       hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+       mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+diff -Nur linux.org/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
+--- linux.org/drivers/ide/ide-cd.c     Mon Feb 25 20:37:57 2002
++++ linux/drivers/ide/ide-cd.c Thu Jul 18 14:24:33 2002
+@@ -540,7 +540,113 @@
+ }
+-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
++/*
++ * This is our end_request replacement function.
++ */
++static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
++{
++      struct request *rq;
++      unsigned long flags;
++      int ret = 1;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      rq = HWGROUP(drive)->rq;
++
++      /*
++       * decide whether to reenable DMA -- 3 is a random magic for now,
++       * if we DMA timeout more than 3 times, just stay in PIO
++       */
++      if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
++              drive->state = 0;
++              HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
++      }
++
++      if (!end_that_request_first(rq, uptodate, drive->name)) {
++              add_blkdev_randomness(MAJOR(rq->rq_dev));
++              blkdev_dequeue_request(rq);
++              HWGROUP(drive)->rq = NULL;
++              end_that_request_last(rq);
++              ret = 0;
++      }
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return ret;
++}
++
++/*
++ * Error reporting, in human readable form (luxurious, but a memory hog).
++ */
++byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
++{
++      unsigned long flags;
++      byte err = 0;
++
++      local_irq_set(flags);
++      printk("%s: %s: status=0x%02x", drive->name, msg, stat);
++#if FANCY_STATUS_DUMPS
++      printk(" { ");
++      if (stat & BUSY_STAT)
++              printk("Busy ");
++      else {
++              if (stat & READY_STAT)  printk("DriveReady ");
++              if (stat & WRERR_STAT)  printk("DeviceFault ");
++              if (stat & SEEK_STAT)   printk("SeekComplete ");
++              if (stat & DRQ_STAT)    printk("DataRequest ");
++              if (stat & ECC_STAT)    printk("CorrectedError ");
++              if (stat & INDEX_STAT)  printk("Index ");
++              if (stat & ERR_STAT)    printk("Error ");
++      }
++      printk("}");
++#endif        /* FANCY_STATUS_DUMPS */
++      printk("\n");
++      if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
++              err = GET_ERR();
++              printk("%s: %s: error=0x%02x", drive->name, msg, err);
++#if FANCY_STATUS_DUMPS
++#endif        /* FANCY_STATUS_DUMPS */
++              printk("\n");
++      }
++      local_irq_restore(flags);
++      return err;
++}
++
++/*
++ * ide_error() takes action based on the error returned by the drive.
++ */
++ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
++{
++      struct request *rq;
++      byte err;
++
++      err = ide_cdrom_dump_status(drive, msg, stat);
++      if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
++              return ide_stopped;
++      /* retry only "normal" I/O: */
++      if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
++              rq->errors = 1;
++              ide_end_drive_cmd(drive, stat, err);
++              return ide_stopped;
++      }
++
++      if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
++              /* other bits are useless when BUSY */
++              rq->errors |= ERROR_RESET;
++      }
++      if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
++              /* force an abort */
++              OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
++      if (rq->errors >= ERROR_MAX) {
++              DRIVER(drive)->end_request(drive, 0);
++      } else {
++              if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++                      ++rq->errors;
++                      return ide_do_reset(drive);
++              }
++              ++rq->errors;
++      }
++      return ide_stopped;
++}
++
++static void cdrom_end_request (ide_drive_t *drive, int uptodate)
+ {
+       struct request *rq = HWGROUP(drive)->rq;
+@@ -554,7 +660,7 @@
+               if (!rq->current_nr_sectors)
+                       uptodate = 1;
+-      ide_end_request (uptodate, HWGROUP(drive));
++      ide_cdrom_end_request(drive, uptodate);
+ }
+@@ -591,8 +697,8 @@
+               pc = (struct packet_command *) rq->buffer;
+               pc->stat = 1;
+-              cdrom_end_request (1, drive);
+-              *startstop = ide_error (drive, "request sense failure", stat);
++              cdrom_end_request(drive, 1);
++              *startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
+               return 1;
+       } else if (rq->cmd == PACKET_COMMAND) {
+@@ -628,7 +734,7 @@
+               }
+               pc->stat = 1;
+-              cdrom_end_request (1, drive);
++              cdrom_end_request(drive, 1);
+               if ((stat & ERR_STAT) != 0)
+                       cdrom_queue_request_sense(drive, wait, pc->sense, pc);
+@@ -641,7 +747,7 @@
+                       /* Fail the request. */
+                       printk ("%s: tray open\n", drive->name);
+-                      cdrom_end_request (0, drive);
++                      cdrom_end_request(drive, 0);
+               } else if (sense_key == UNIT_ATTENTION) {
+                       /* Media change. */
+                       cdrom_saw_media_change (drive);
+@@ -650,21 +756,21 @@
+                          But be sure to give up if we've retried
+                          too many times. */
+                       if (++rq->errors > ERROR_MAX)
+-                              cdrom_end_request (0, drive);
++                              cdrom_end_request(drive, 0);
+               } else if (sense_key == ILLEGAL_REQUEST ||
+                          sense_key == DATA_PROTECT) {
+                       /* No point in retrying after an illegal
+                          request or data protect error.*/
+                       ide_dump_status (drive, "command error", stat);
+-                      cdrom_end_request (0, drive);
++                      cdrom_end_request(drive, 0);
+               } else if ((err & ~ABRT_ERR) != 0) {
+                       /* Go to the default handler
+                          for other errors. */
+-                      *startstop = ide_error (drive, "cdrom_decode_status", stat);
++                      *startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
+                       return 1;
+               } else if ((++rq->errors > ERROR_MAX)) {
+                       /* We've racked up too many retries.  Abort. */
+-                      cdrom_end_request (0, drive);
++                      cdrom_end_request(drive, 0);
+               }
+               /* If we got a CHECK_CONDITION status,
+@@ -732,24 +838,26 @@
+       }
+       /* Set up the controller registers. */
+-      OUT_BYTE (info->dma, IDE_FEATURE_REG);
+-      OUT_BYTE (0, IDE_NSECTOR_REG);
+-      OUT_BYTE (0, IDE_SECTOR_REG);
++      OUT_BYTE(info->dma, IDE_FEATURE_REG);
++      OUT_BYTE(0, IDE_NSECTOR_REG);
++      OUT_BYTE(0, IDE_SECTOR_REG);
+-      OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+-      OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
++      OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG);
++      OUT_BYTE(xferlen >> 8  , IDE_HCYL_REG);
+       if (IDE_CONTROL_REG)
+-              OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
++              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+  
+       if (info->dma)
+               (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+       if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+-              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+               return ide_started;
+       } else {
+-              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+               return (*handler) (drive);
+       }
+ }
+@@ -786,6 +894,9 @@
+                       return startstop;
+       }
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
++
+       /* Arm the interrupt handler. */
+       ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
+@@ -879,7 +990,7 @@
+                       drive->name, ireason);
+       }
+-      cdrom_end_request (0, drive);
++      cdrom_end_request(drive, 0);
+       return -1;
+ }
+@@ -910,16 +1021,16 @@
+               if (!dma_error) {
+                       for (i = rq->nr_sectors; i > 0;) {
+                               i -= rq->current_nr_sectors;
+-                              ide_end_request(1, HWGROUP(drive));
++                              ide_cdrom_end_request(drive, 1);
+                       }
+                       return ide_stopped;
+               } else
+-                      return ide_error (drive, "dma error", stat);
++                      return DRIVER(drive)->error(drive, "dma error", stat);
+       }
+       /* Read the interrupt reason and the transfer length. */
+-      ireason = IN_BYTE (IDE_NSECTOR_REG);
+-      len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
++      ireason = IN_BYTE(IDE_NSECTOR_REG);
++      len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+       /* If DRQ is clear, the command has completed. */
+       if ((stat & DRQ_STAT) == 0) {
+@@ -928,9 +1039,9 @@
+               if (rq->current_nr_sectors > 0) {
+                       printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
+                               drive->name, rq->current_nr_sectors);
+-                      cdrom_end_request (0, drive);
++                      cdrom_end_request(drive, 0);
+               } else
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+               return ide_stopped;
+       }
+@@ -950,7 +1061,7 @@
+                       printk ("  Trying to limit transfer sizes\n");
+                       CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+               }
+-              cdrom_end_request (0, drive);
++              cdrom_end_request(drive, 0);
+               return ide_stopped;
+       }
+@@ -979,7 +1090,7 @@
+               /* If we've filled the present buffer but there's another
+                  chained buffer after it, move on. */
+               if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+               /* If the buffers are full, cache the rest of the data in our
+                  internal buffer. */
+@@ -1007,8 +1118,10 @@
+               }
+       }
+-      /* Done moving data!
+-         Wait for another interrupt. */
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
++
++      /* Done moving data!  Wait for another interrupt. */
+       ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+       return ide_started;
+ }
+@@ -1031,7 +1144,7 @@
+              rq->sector >= info->sector_buffered &&
+              rq->sector < info->sector_buffered + info->nsectors_buffered) {
+               if (rq->current_nr_sectors == 0)
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+               memcpy (rq->buffer,
+                       info->buffer +
+@@ -1046,13 +1159,13 @@
+       /* If we've satisfied the current request,
+          terminate it successfully. */
+       if (rq->nr_sectors == 0) {
+-              cdrom_end_request (1, drive);
++              cdrom_end_request(drive, 1);
+               return -1;
+       }
+       /* Move on to the next buffer if needed. */
+       if (rq->current_nr_sectors == 0)
+-              cdrom_end_request (1, drive);
++              cdrom_end_request(drive, 1);
+       /* If this condition does not hold, then the kluge i use to
+          represent the number of sectors to skip at the start of a transfer
+@@ -1062,7 +1175,7 @@
+           (rq->sector % SECTORS_PER_FRAME) != 0) {
+               printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+                       drive->name, rq->sector);
+-              cdrom_end_request (0, drive);
++              cdrom_end_request(drive, 0);
+               return -1;
+       }
+@@ -1101,7 +1214,7 @@
+                       (rq->sector % CD_FRAMESIZE != 0)) {
+                       printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
+                               drive->name, rq->current_nr_sectors);
+-                      cdrom_end_request (0, drive);
++                      cdrom_end_request(drive, 0);
+                       return ide_stopped;
+               }
+               sector -= nskip;
+@@ -1147,7 +1260,7 @@
+               return startstop;
+       CDROM_CONFIG_FLAGS(drive)->seeking = 1;
+-      if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
++      if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
+               if (--retry == 0) {
+                       /*
+                        * this condition is far too common, to bother
+@@ -1337,7 +1450,7 @@
+               }
+               if (pc->buflen == 0)
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+               else {
+                       /* Comment this out, because this always happens 
+                          right after a reset occurs, and it is annoying to 
+@@ -1347,7 +1460,7 @@
+                               drive->name, pc->buflen);
+                       */
+                       pc->stat = 1;
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+               }
+               return ide_stopped;
+       }
+@@ -1398,6 +1511,9 @@
+               pc->stat = 1;
+       }
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
++
+       /* Now we wait for another interrupt. */
+       ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+       return ide_started;
+@@ -1522,7 +1638,7 @@
+                       drive->name, ireason);
+       }
+-      cdrom_end_request(0, drive);
++      cdrom_end_request(drive, 0);
+       return 1;
+ }
+@@ -1554,12 +1670,12 @@
+        */
+       if (dma) {
+               if (dma_error)
+-                      return ide_error(drive, "dma error", stat);
++                      return DRIVER(drive)->error(drive, "dma error", stat);
+               rq = HWGROUP(drive)->rq;
+               for (i = rq->nr_sectors; i > 0;) {
+                       i -= rq->current_nr_sectors;
+-                      ide_end_request(1, HWGROUP(drive));
++                      ide_cdrom_end_request(drive, 1);
+               }
+               return ide_stopped;
+       }
+@@ -1579,7 +1695,7 @@
+                       drive->name, rq->current_nr_sectors);
+                       uptodate = 0;
+               }
+-              cdrom_end_request(uptodate, drive);
++              cdrom_end_request(drive, uptodate);
+               return ide_stopped;
+       }
+@@ -1620,9 +1736,12 @@
+                * current buffer complete, move on
+                */
+               if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+-                      cdrom_end_request (1, drive);
++                      cdrom_end_request(drive, 1);
+       }
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
++
+       /* re-arm handler */
+       ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
+       return ide_started;
+@@ -1662,7 +1781,7 @@
+        * writes *must* be 2kB frame aligned
+        */
+       if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
+-              cdrom_end_request(0, drive);
++              cdrom_end_request(drive, 0);
+               return ide_stopped;
+       }
+@@ -1698,11 +1817,10 @@
+               case WRITE:
+               case READ: {
+                       if (CDROM_CONFIG_FLAGS(drive)->seeking) {
+-                              unsigned long elpased = jiffies - info->start_seek;
+                               int stat = GET_STAT();
+                               if ((stat & SEEK_STAT) != SEEK_STAT) {
+-                                      if (elpased < IDECD_SEEK_TIMEOUT) {
++                                      if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) {
+                                               ide_stall_queue(drive, IDECD_SEEK_TIMER);
+                                               return ide_stopped;
+                                       }
+@@ -1728,13 +1846,13 @@
+               }
+               case RESET_DRIVE_COMMAND: {
+-                      cdrom_end_request(1, drive);
++                      cdrom_end_request(drive, 1);
+                       return ide_do_reset(drive);
+               }
+               default: {
+                       printk("ide-cd: bad cmd %d\n", rq->cmd);
+-                      cdrom_end_request(0, drive);
++                      cdrom_end_request(drive, 0);
+                       return ide_stopped;
+               }
+       }
+@@ -2536,8 +2654,8 @@
+       devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+       devinfo->ops = &ide_cdrom_dops;
+       devinfo->mask = 0;
+-      *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+-      *(int *)&devinfo->capacity = nslots;
++      devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
++      devinfo->capacity = nslots;
+       devinfo->handle = (void *) drive;
+       strcpy(devinfo->name, drive->name);
+       
+@@ -2644,7 +2762,9 @@
+        * but they do support reading TOC & audio datas
+        */
+       if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+-          strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0)
++          strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
++          strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
++          strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+               CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+ #if ! STANDARD_ATAPI
+@@ -2961,22 +3081,29 @@
+       return 0;
+ }
+-static
+-int ide_cdrom_reinit (ide_drive_t *drive)
+-{
+-      return 0;
+-}
++int ide_cdrom_init(void);
++int ide_cdrom_reinit (ide_drive_t *drive);
+ static ide_driver_t ide_cdrom_driver = {
+       name:                   "ide-cdrom",
+       version:                IDECD_VERSION,
+       media:                  ide_cdrom,
+       busy:                   0,
++#ifdef CONFIG_IDEDMA_ONLYDISK
++      supports_dma:           0,
++#else
+       supports_dma:           1,
++#endif
+       supports_dsc_overlap:   1,
+       cleanup:                ide_cdrom_cleanup,
++      standby:                NULL,
++      suspend:                NULL,
++      resume:                 NULL,
++      flushcache:             NULL,
+       do_request:             ide_do_rw_cdrom,
+-      end_request:            NULL,
++      end_request:            ide_cdrom_end_request,
++      sense:                  ide_cdrom_dump_status,
++      error:                  ide_cdrom_error,
+       ioctl:                  ide_cdrom_ioctl,
+       open:                   ide_cdrom_open,
+       release:                ide_cdrom_release,
+@@ -2986,10 +3113,12 @@
+       capacity:               ide_cdrom_capacity,
+       special:                NULL,
+       proc:                   NULL,
+-      driver_reinit:          ide_cdrom_reinit,
++      init:                   ide_cdrom_init,
++      reinit:                 ide_cdrom_reinit,
++      ata_prebuilder:         NULL,
++      atapi_prebuilder:       NULL,
+ };
+-int ide_cdrom_init(void);
+ static ide_module_t ide_cdrom_module = {
+       IDE_DRIVER_MODULE,
+       ide_cdrom_init,
+@@ -3003,6 +3132,39 @@
+ MODULE_PARM(ignore, "s");
+ MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
++int ide_cdrom_reinit (ide_drive_t *drive)
++{
++      struct cdrom_info *info;
++      int failed = 0;
++
++      MOD_INC_USE_COUNT;
++      info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
++      if (info == NULL) {
++              printk ("%s: Can't allocate a cdrom structure\n", drive->name);
++              return 1;
++      }
++      if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
++              printk ("%s: Failed to register the driver with ide.c\n", drive->name);
++              kfree (info);
++              return 1;
++      }
++      memset (info, 0, sizeof (struct cdrom_info));
++      drive->driver_data = info;
++      DRIVER(drive)->busy++;
++      if (ide_cdrom_setup (drive)) {
++              DRIVER(drive)->busy--;
++              if (ide_cdrom_cleanup (drive))
++                      printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
++              return 1;
++      }
++      DRIVER(drive)->busy--;
++      failed--;
++
++      ide_register_module(&ide_cdrom_module);
++      MOD_DEC_USE_COUNT;
++      return 0;
++}
++
+ static void __exit ide_cdrom_exit(void)
+ {
+       ide_drive_t *drive;
+diff -Nur linux.org/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
+--- linux.org/drivers/ide/ide-cd.h     Thu Nov 22 20:46:58 2001
++++ linux/drivers/ide/ide-cd.h Thu Jul 18 14:23:00 2002
+@@ -38,7 +38,9 @@
+ /************************************************************************/
+ #define SECTOR_BITS           9
++#ifndef SECTOR_SIZE
+ #define SECTOR_SIZE           (1 << SECTOR_BITS)
++#endif
+ #define SECTORS_PER_FRAME     (CD_FRAMESIZE >> SECTOR_BITS)
+ #define SECTOR_BUFFER_SIZE    (CD_FRAMESIZE * 32)
+ #define SECTORS_BUFFER                (SECTOR_BUFFER_SIZE >> SECTOR_BITS)
+diff -Nur linux.org/drivers/ide/ide-cs.c linux/drivers/ide/ide-cs.c
+--- linux.org/drivers/ide/ide-cs.c     Sun Sep 30 21:26:05 2001
++++ linux/drivers/ide/ide-cs.c Thu Jul 18 14:24:33 2002
+@@ -42,6 +42,7 @@
+ #include <linux/ioport.h>
+ #include <linux/hdreg.h>
+ #include <linux/major.h>
++#include <linux/ide.h>
+ #include <asm/io.h>
+ #include <asm/system.h>
+@@ -226,6 +227,15 @@
+ #define CFG_CHECK(fn, args...) \
+ if (CardServices(fn, args) != 0) goto next_entry
++int idecs_register (int arg1, int arg2, int irq)
++{
++        hw_regs_t hw;
++        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
++        hw.irq = irq;
++        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
++        return ide_register_hw(&hw, NULL);
++}
++
+ void ide_config(dev_link_t *link)
+ {
+     client_handle_t handle = link->handle;
+@@ -329,10 +339,14 @@
+     /* retry registration in case device is still spinning up */
+     for (i = 0; i < 10; i++) {
+-      hd = ide_register(io_base, ctl_base, link->irq.AssignedIRQ);
++      if (ctl_base)
++          OUT_BYTE(0x02, ctl_base); /* Set nIEN = disable device interrupts */
++      hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+       if (hd >= 0) break;
+       if (link->io.NumPorts1 == 0x20) {
+-          hd = ide_register(io_base+0x10, ctl_base+0x10,
++          if (ctl_base)
++              OUT_BYTE(0x02, ctl_base+0x10);
++          hd = idecs_register(io_base+0x10, ctl_base+0x10,
+                             link->irq.AssignedIRQ);
+           if (hd >= 0) {
+               io_base += 0x10; ctl_base += 0x10;
+diff -Nur linux.org/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
+--- linux.org/drivers/ide/ide-disk.c   Fri Dec 21 18:41:54 2001
++++ linux/drivers/ide/ide-disk.c       Thu Jul 18 14:24:33 2002
+@@ -1,5 +1,9 @@
+ /*
+- *  linux/drivers/ide/ide-disk.c      Version 1.10    June 9, 2000
++ *  linux/drivers/ide/ide-disk.c      Version 1.16    April 7, 2002
++ *
++ *  Copyright (C) 1998-2002  Linux ATA Developemt
++ *                            Andre Hedrick <andre@linux-ide.org>
++ *
+  *
+  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+  */
+@@ -27,9 +31,16 @@
+  * Version 1.09               added increment of rq->sector in ide_multwrite
+  *                    added UDMA 3/4 reporting
+  * Version 1.10               request queue changes, Ultra DMA 100
++ * Version 1.11               added 48-bit lba
++ * Version 1.12               adding taskfile io access method
++ * Version 1.13               added standby and flush-cache for notifier
++ * Version 1.14               added acoustic-wcache
++ * Version 1.15               convert all calls to ide_raw_taskfile
++ *                            since args will return register content.
++ * Version 1.16               added suspend-resume-checkpower
+  */
+-#define IDEDISK_VERSION       "1.10"
++#define IDEDISK_VERSION       "1.16"
+ #undef REALLY_SLOW_IO         /* most systems can safely undef this */
+@@ -59,32 +70,16 @@
+ #define IS_PDC4030_DRIVE (0)  /* auto-NULLs out pdc4030 code */
+ #endif
+-static void idedisk_bswap_data (void *buffer, int wcount)
+-{
+-      u16 *p = buffer;
++static int driver_blocked;
+-      while (wcount--) {
+-              *p = *p << 8 | *p >> 8; p++;
+-              *p = *p << 8 | *p >> 8; p++;
+-      }
+-}
+-
+-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
++static inline u32 idedisk_read_24 (ide_drive_t *drive)
+ {
+-      ide_input_data(drive, buffer, wcount);
+-      if (drive->bswap)
+-              idedisk_bswap_data(buffer, wcount);
++      return  (IN_BYTE(IDE_HCYL_REG)<<16) |
++              (IN_BYTE(IDE_LCYL_REG)<<8) |
++               IN_BYTE(IDE_SECTOR_REG);
+ }
+-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+-{
+-      if (drive->bswap) {
+-              idedisk_bswap_data(buffer, wcount);
+-              ide_output_data(drive, buffer, wcount);
+-              idedisk_bswap_data(buffer, wcount);
+-      } else
+-              ide_output_data(drive, buffer, wcount);
+-}
++static int idedisk_end_request(ide_drive_t *drive, int uptodate);
+ /*
+  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
+@@ -99,6 +94,11 @@
+ {
+       unsigned long lba_sects, chs_sects, head, tail;
++      if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
++              printk("48-bit Drive: %llu \n", id->lba_capacity_2);
++              return 1;
++      }
++
+       /*
+        * The ATA spec tells large drives to return
+        * C/H/S = 16383/16/63 independent of their size.
+@@ -131,6 +131,8 @@
+       return 0;       /* lba_capacity value may be bad */
+ }
++#ifndef CONFIG_IDE_TASKFILE_IO
++
+ /*
+  * read_intr() is the handler for disk read/multread interrupts
+  */
+@@ -144,9 +146,11 @@
+       /* 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);
++                      return DRIVER(drive)->error(drive, "read_intr", stat);
+               }
+               /* no data yet, so wait for another interrupt */
++              if (HWGROUP(drive)->handler != NULL)
++                      BUG();
+               ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+               return ide_started;
+       }
+@@ -160,7 +164,7 @@
+               msect -= nsect;
+       } else
+               nsect = 1;
+-      idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
++      taskfile_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+ #ifdef DEBUG
+       printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
+               drive->name, rq->sector, rq->sector+nsect-1,
+@@ -171,11 +175,18 @@
+       rq->errors = 0;
+       i = (rq->nr_sectors -= nsect);
+       if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
+-              ide_end_request(1, HWGROUP(drive));
++              idedisk_end_request(drive, 1);
++      /*
++       * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
++       * If passed back up on multimode read, BAD DATA could be ACKED
++       * to FILE SYSTEMS above ...
++       */
+       if (i > 0) {
+               if (msect)
+                       goto read_next;
+-              ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
++              ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+                 return ide_started;
+       }
+         return ide_stopped;
+@@ -206,17 +217,19 @@
+                       i = --rq->nr_sectors;
+                       --rq->current_nr_sectors;
+                       if (((long)rq->current_nr_sectors) <= 0)
+-                              ide_end_request(1, hwgroup);
++                              idedisk_end_request(drive, 1);
+                       if (i > 0) {
+-                              idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
+-                              ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
++                              taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
++                              if (HWGROUP(drive)->handler != NULL)
++                                      BUG();
++                              ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+                                 return ide_started;
+                       }
+                         return ide_stopped;
+               }
+               return ide_stopped;     /* the original code did this here (?) */
+       }
+-      return ide_error(drive, "write_intr", stat);
++      return DRIVER(drive)->error(drive, "write_intr", stat);
+ }
+ /*
+@@ -229,6 +242,11 @@
+  * and IRQ context. The IRQ can happen any time after we've output the
+  * full "mcount" number of sectors, so we must make sure we update the
+  * state _before_ we output the final part of the data!
++ *
++ * The update and return to BH is a BLOCK Layer Fakey to get more data
++ * to satisfy the hardware atomic segment.  If the hardware atomic segment
++ * is shorter or smaller than the BH segment then we should be OKAY.
++ * This is only valid if we can rewind the rq->current_nr_sectors counter.
+  */
+ int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
+ {
+@@ -267,7 +285,7 @@
+                * Ok, we're all setup for the interrupt
+                * re-entering us on the last transfer.
+                */
+-              idedisk_output_data(drive, buffer, nsect<<7);
++              taskfile_output_data(drive, buffer, nsect<<7);
+       } while (mcount);
+         return 0;
+@@ -292,7 +310,9 @@
+                       if (rq->nr_sectors) {
+                               if (ide_multwrite(drive, drive->mult_count))
+                                       return ide_stopped;
+-                              ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
++                              if (HWGROUP(drive)->handler != NULL)
++                                      BUG();
++                              ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
+                               return ide_started;
+                       }
+               } else {
+@@ -304,62 +324,186 @@
+                               rq = hwgroup->rq;
+                               for (i = rq->nr_sectors; i > 0;){
+                                       i -= rq->current_nr_sectors;
+-                                      ide_end_request(1, hwgroup);
++                                      idedisk_end_request(drive, 1);
+                               }
+                               return ide_stopped;
+                       }
+               }
+               return ide_stopped;     /* the original code did this here (?) */
+       }
+-      return ide_error(drive, "multwrite_intr", stat);
++      return DRIVER(drive)->error(drive, "multwrite_intr", stat);
+ }
++#endif /* CONFIG_IDE_TASKFILE_IO */
++
++#ifdef CONFIG_IDE_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;
++      if (rq->cmd == READ)
++              goto good_command;
++      if (rq->cmd == WRITE)
++              goto good_command;
+-      if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+-              drive->mult_count = drive->mult_req;
+-      } else {
+-              drive->mult_req = drive->mult_count = 0;
+-              drive->special.b.recalibrate = 1;
+-              (void) ide_dump_status(drive, "set_multmode", stat);
+-      }
++      printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
++      idedisk_end_request(drive, 0);
+       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 == 1))           /* 48-bit LBA */
++              return lba_48_rw_disk(drive, rq, (unsigned long long) block);
++      if (drive->select.b.lba)                /* 28-bit LBA */
++              return lba_28_rw_disk(drive, rq, (unsigned long) block);
++
++      /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
++      return chs_rw_disk(drive, rq, (unsigned long) block);
+ }
+-/*
+- * 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;
++      int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+-      if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+-              return ide_stopped;
++#if 1
++      lba48bit = (drive->addressing == 1) ? 1 : 0;
++#endif
+-      if (stat & (ERR_STAT|DRQ_STAT))
+-              return ide_error(drive, "set_geometry_intr", stat);
++      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;
++}
+-      ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+-      return ide_started;     
++static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
++{
++      ide_task_t              args;
++      int                     sectors;
++      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);
++
++#ifdef DEBUG
++      printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
++      printk("CHS=%d/%d/%d, ", cyl, head, sect);
++      printk("sectors=%ld, ", rq->nr_sectors);
++      printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
++#endif
++
++      memset(&args, 0, sizeof(ide_task_t));
++
++      sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = sectors;
++      args.tfRegister[IDE_SECTOR_OFFSET]      = sect;
++      args.tfRegister[IDE_LCYL_OFFSET]        = cyl;
++      args.tfRegister[IDE_HCYL_OFFSET]        = (cyl>>8);
++      args.tfRegister[IDE_SELECT_OFFSET]      = head;
++      args.tfRegister[IDE_SELECT_OFFSET]      |= drive->select.all;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = command;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      args.rq                                 = (struct request *) rq;
++      rq->special                             = (ide_task_t *)&args;
++      return do_rw_taskfile(drive, &args);
++}
++
++static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
++{
++      ide_task_t              args;
++      int                     sectors;
++      task_ioreg_t command    = get_command(drive, rq->cmd);
++
++#ifdef DEBUG
++      printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
++      printk("LBAsect=%lld, ", block);
++      printk("sectors=%ld, ", rq->nr_sectors);
++      printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
++#endif
++
++      memset(&args, 0, sizeof(ide_task_t));
++
++      sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = sectors;
++      args.tfRegister[IDE_SECTOR_OFFSET]      = block;
++      args.tfRegister[IDE_LCYL_OFFSET]        = (block>>=8);
++      args.tfRegister[IDE_HCYL_OFFSET]        = (block>>=8);
++      args.tfRegister[IDE_SELECT_OFFSET]      = ((block>>8)&0x0f);
++      args.tfRegister[IDE_SELECT_OFFSET]      |= drive->select.all;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = command;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      args.rq                                 = (struct request *) rq;
++      rq->special                             = (ide_task_t *)&args;
++      return do_rw_taskfile(drive, &args);
+ }
+ /*
+- * 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();
++      ide_task_t              args;
++      int                     sectors;
++      task_ioreg_t command    = get_command(drive, rq->cmd);
+-      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");
++      printk("LBAsect=%lld, ", block);
++      printk("sectors=%ld, ", rq->nr_sectors);
++      printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
++#endif
++
++      memset(&args, 0, sizeof(ide_task_t));
++
++      sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = sectors;
++      args.tfRegister[IDE_SECTOR_OFFSET]      = block;        /* low lba */
++      args.tfRegister[IDE_LCYL_OFFSET]        = (block>>=8);  /* mid lba */
++      args.tfRegister[IDE_HCYL_OFFSET]        = (block>>=8);  /* hi  lba */
++      args.tfRegister[IDE_SELECT_OFFSET]      = drive->select.all;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = command;
++      args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
++      args.hobRegister[IDE_SECTOR_OFFSET_HOB] = (block>>=8);  /* low lba */
++      args.hobRegister[IDE_LCYL_OFFSET_HOB]   = (block>>=8);  /* mid lba */
++      args.hobRegister[IDE_HCYL_OFFSET_HOB]   = (block>>=8);  /* hi  lba */
++      args.hobRegister[IDE_SELECT_OFFSET_HOB] = drive->select.all;
++      args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
++      args.command_type                       = ide_cmd_type_parser(&args);
++      args.rq                                 = (struct request *) rq;
++      rq->special                             = (ide_task_t *)&args;
++      return do_rw_taskfile(drive, &args);
+ }
++#else /* !CONFIG_IDE_TASKFILE_IO */
++
+ /*
+  * do_rw_disk() issues READ and WRITE commands to a disk,
+  * using LBA if supported, or CHS otherwise, to address sectors.
+@@ -367,24 +511,75 @@
+  */
+ static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+ {
++      if (driver_blocked)
++              panic("Request while ide driver is blocked?");
+       if (IDE_CONTROL_REG)
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+-      OUT_BYTE(0x00, IDE_FEATURE_REG);
+-      OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
++
+ #ifdef CONFIG_BLK_DEV_PDC4030
+       if (drive->select.b.lba || IS_PDC4030_DRIVE) {
+ #else /* !CONFIG_BLK_DEV_PDC4030 */
+       if (drive->select.b.lba) {
+ #endif /* CONFIG_BLK_DEV_PDC4030 */
++
++              if ((drive->id->cfs_enable_2 & 0x0400) &&
++                  (drive->addressing == 1)) {
++                      task_ioreg_t tasklets[10];
++
++                      tasklets[0] = 0;
++                      tasklets[1] = 0;
++                      tasklets[2] = rq->nr_sectors;
++                      tasklets[3] = (rq->nr_sectors>>8);
++                      if (rq->nr_sectors == 65536) {
++                              tasklets[2] = 0x00;
++                              tasklets[3] = 0x00;
++                      }
++                      tasklets[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;
+@@ -392,6 +587,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);
+@@ -412,8 +610,15 @@
+               if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+                       return ide_started;
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
++              if (HWGROUP(drive)->handler != NULL)
++                      BUG();
+               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 == 1)) {
++                      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) {
+@@ -422,27 +627,36 @@
+               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 == 1)) {
++                      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");
+                       return startstop;
+               }
+               if (!drive->unmask)
+-                      __cli();        /* local CPU only */
++                      local_irq_disable();
+               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...
++       *
++       * MAJOR DATA INTEGRITY BUG !!! only if we error 
++       */
+                       hwgroup->wrq = *rq; /* scratchpad */
+-                      ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
++                      if (HWGROUP(drive)->handler != NULL)
++                              BUG();
++                      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);
+@@ -452,39 +666,57 @@
+                               return ide_stopped;
+                       }
+               } else {
+-                      ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+-                      idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
++                      if (HWGROUP(drive)->handler != NULL)
++                              BUG();
++                      ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
++                      taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+               }
+               return ide_started;
+       }
+       printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+-      ide_end_request(0, HWGROUP(drive));
++      idedisk_end_request(drive, 0);
+       return ide_stopped;
+ }
++#endif /* CONFIG_IDE_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) {
++              ide_task_t args;
++              memset(&args, 0, sizeof(ide_task_t));
++              args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
++              args.command_type = ide_cmd_type_parser(&args);
+               check_disk_change(inode->i_rdev);
+               /*
+                * Ignore the return code from door_lock,
+                * since the open() has already succeeded,
+                * and the door_lock is irrelevant at this point.
+                */
+-              if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
++              if (drive->doorlocking && ide_raw_taskfile(drive, &args, 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) {
++              ide_task_t args;
++              memset(&args, 0, sizeof(ide_task_t));
++              args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
++              args.command_type = ide_cmd_type_parser(&args);
+               invalidate_bdev(inode->i_bdev, 0);
+-              if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
++              if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+                       drive->doorlocking = 0;
+       }
++      if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
++              if (do_idedisk_flushcache(drive))
++                      printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
++                              drive->name);
+       MOD_DEC_USE_COUNT;
+ }
+@@ -500,28 +732,423 @@
+                       current_capacity(drive));
+ }
++static int idedisk_end_request (ide_drive_t *drive, int uptodate)
++{
++      struct request *rq;
++      unsigned long flags;
++      int ret = 1;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      rq = HWGROUP(drive)->rq;
++
++      /*
++       * decide whether to reenable DMA -- 3 is a random magic for now,
++       * if we DMA timeout more than 3 times, just stay in PIO
++       */
++      if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
++              drive->state = 0;
++              HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
++      }
++
++      if (!end_that_request_first(rq, uptodate, drive->name)) {
++              add_blkdev_randomness(MAJOR(rq->rq_dev));
++              blkdev_dequeue_request(rq);
++              HWGROUP(drive)->rq = NULL;
++              end_that_request_last(rq);
++              ret = 0;
++      }
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return ret;
++}
++
++static byte idedisk_dump_status (ide_drive_t *drive, const char *msg, byte stat)
++{
++      unsigned long flags;
++      byte err = 0;
++
++      local_irq_set(flags);
++      printk("%s: %s: status=0x%02x", drive->name, msg, stat);
++#if FANCY_STATUS_DUMPS
++      printk(" { ");
++      if (stat & BUSY_STAT)
++              printk("Busy ");
++      else {
++              if (stat & READY_STAT)  printk("DriveReady ");
++              if (stat & WRERR_STAT)  printk("DeviceFault ");
++              if (stat & SEEK_STAT)   printk("SeekComplete ");
++              if (stat & DRQ_STAT)    printk("DataRequest ");
++              if (stat & ECC_STAT)    printk("CorrectedError ");
++              if (stat & INDEX_STAT)  printk("Index ");
++              if (stat & ERR_STAT)    printk("Error ");
++      }
++      printk("}");
++#endif        /* FANCY_STATUS_DUMPS */
++      printk("\n");
++      if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
++              err = GET_ERR();
++              printk("%s: %s: error=0x%02x", drive->name, msg, err);
++#if FANCY_STATUS_DUMPS
++              printk(" { ");
++              if (err & ABRT_ERR)     printk("DriveStatusError ");
++              if (err & ICRC_ERR)     printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
++              if (err & ECC_ERR)      printk("UncorrectableError ");
++              if (err & ID_ERR)       printk("SectorIdNotFound ");
++              if (err & TRK0_ERR)     printk("TrackZeroNotFound ");
++              if (err & MARK_ERR)     printk("AddrMarkNotFound ");
++              printk("}");
++              if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
++                      if ((drive->id->command_set_2 & 0x0400) &&
++                          (drive->id->cfs_enable_2 & 0x0400) &&
++                          (drive->addressing == 1)) {
++                              __u64 sectors = 0;
++                              u32 low = 0, high = 0;
++                              low = idedisk_read_24(drive);
++                              OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
++                              high = idedisk_read_24(drive);
++                              sectors = ((__u64)high << 24) | low;
++                              printk(", LBAsect=%llu, high=%d, low=%d",
++                                     (unsigned long long) sectors,
++                                     high, low);
++                      } else {
++                              byte cur = IN_BYTE(IDE_SELECT_REG);
++                              if (cur & 0x40) {       /* using LBA? */
++                                      printk(", LBAsect=%ld", (unsigned long)
++                                       ((cur&0xf)<<24)
++                                       |(IN_BYTE(IDE_HCYL_REG)<<16)
++                                       |(IN_BYTE(IDE_LCYL_REG)<<8)
++                                       | IN_BYTE(IDE_SECTOR_REG));
++                              } else {
++                                      printk(", CHS=%d/%d/%d",
++                                       (IN_BYTE(IDE_HCYL_REG)<<8) +
++                                        IN_BYTE(IDE_LCYL_REG),
++                                        cur & 0xf,
++                                        IN_BYTE(IDE_SECTOR_REG));
++                              }
++                      }
++                      if (HWGROUP(drive) && HWGROUP(drive)->rq)
++                              printk(", sector=%ld", HWGROUP(drive)->rq->sector);
++              }
++      }
++#endif        /* FANCY_STATUS_DUMPS */
++      printk("\n");
++      local_irq_restore(flags);
++      return err;
++}
++
++ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, byte stat)
++{
++      struct request *rq;
++      byte err;
++      int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
++
++      err = idedisk_dump_status(drive, msg, stat);
++
++      if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
++              return ide_stopped;
++      /* retry only "normal" I/O: */
++      switch (rq->cmd) {
++              case IDE_DRIVE_CMD:
++              case IDE_DRIVE_TASK:
++              case IDE_DRIVE_TASKFILE:
++                      rq->errors = 1;
++                      ide_end_drive_cmd(drive, stat, err);
++                      return ide_stopped;
++#if 0
++              case IDE_DRIVE_TASKFILE:
++                      rq->errors = 1;
++                      ide_end_taskfile(drive, stat, err);
++                      return ide_stopped;
++#endif
++              default:
++                      break;
++      }
++
++      if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
++              /* other bits are useless when BUSY */
++              rq->errors |= ERROR_RESET;
++      } else if (stat & ERR_STAT) {
++              /* err has different meaning on cdrom and tape */
++              if (err == ABRT_ERR) {
++                      if (drive->select.b.lba &&
++                          /* some newer drives don't support WIN_SPECIFY */
++                          IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
++                              return ide_stopped;
++              } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
++                      /* UDMA crc error, just retry the operation */
++                      drive->crc_count++;
++              } else if (err & (BBD_ERR | ECC_ERR))
++                      /* retries won't help these */
++                      rq->errors = ERROR_MAX;
++              else if (err & TRK0_ERR)
++                      /* help it find track zero */
++                      rq->errors |= ERROR_RECAL;
++      }
++      if ((stat & DRQ_STAT) && rq->cmd != WRITE) {
++              /*
++               * try_to_flush_leftover_data() is invoked in response to
++               * a drive unexpectedly having its DRQ_STAT bit set.  As
++               * an alternative to resetting the drive, this routine
++               * tries to clear the condition by read a sector's worth
++               * of data from the drive.  Of course, this may not help
++               * if the drive is *waiting* for data from *us*.
++               */
++              while (i > 0) {
++                      u32 buffer[16];
++                      unsigned int wcount = (i > 16) ? 16 : i;
++                      i -= wcount;
++                      ata_input_data(drive, buffer, wcount);
++              }
++      }
++      if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
++              /* force an abort */
++              OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
++      if (rq->errors >= ERROR_MAX)
++              DRIVER(drive)->end_request(drive, 0);
++      else {
++              if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++                      ++rq->errors;
++                      return ide_do_reset(drive);
++              }
++              if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
++                      drive->special.b.recalibrate = 1;
++              ++rq->errors;
++      }
++      return ide_stopped;
++}
++
++/*
++ * Queries for true maximum capacity of the drive.
++ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
++ */
++static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
++{
++      ide_task_t args;
++      unsigned long addr = 0;
++
++#if 0
++      if (!(drive->id->command_set_1 & 0x0400) &&
++          !(drive->id->cfs_enable_2 & 0x0100))
++              return addr;
++#endif
++
++      /* 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.command_type                       = ide_cmd_type_parser(&args);
++      /* 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.command_type                       = ide_cmd_type_parser(&args);
++        /* 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.command_type                       = ide_cmd_type_parser(&args);
++      /* submit command request */
++      ide_raw_taskfile(drive, &args, NULL);
++      /* if OK, read new maximum address value */
++      if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
++              addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
++                       | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
++                       | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
++                       | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
++      }
++      addr_set++;
++      return addr_set;
++}
++
++static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
++{
++      ide_task_t args;
++      unsigned long long addr_set = 0;
++
++      addr_req--;
++      /* Create IDE/ATA command request structure */
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_SECTOR_OFFSET]      = ((addr_req >>  0) & 0xff);
++      args.tfRegister[IDE_LCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
++      args.tfRegister[IDE_HCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
++      args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SET_MAX_EXT;
++      args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
++      args.hobRegister[IDE_LCYL_OFFSET_HOB]   = ((addr_req >>= 8) & 0xff);
++      args.hobRegister[IDE_HCYL_OFFSET_HOB]   = ((addr_req >>= 8) & 0xff);
++      args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40;
++      args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
++      args.command_type                       = ide_cmd_type_parser(&args);
++      /* 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;
++}
++
++#endif /* CONFIG_IDEDISK_STROKE */
++
++/*
++ * 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;
++      if (flag)
++              printk("%s: host protected area => %d\n", drive->name, flag);
++      return flag;
++}
++
+ /*
+  * 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;
++      (void) idedisk_supports_host_protected_area(drive);
++
++      if (id->cfs_enable_2 & 0x0400) {
++              capacity_2 = id->lba_capacity_2;
++              drive->head             = drive->bios_head = 255;
++              drive->sect             = drive->bios_sect = 63;
++              drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
++              drive->select.b.lba     = 1;
++              set_max_ext = idedisk_read_native_max_address_ext(drive);
++              if (set_max_ext > capacity_2) {
++#ifdef CONFIG_IDEDISK_STROKE
++                      set_max_ext = idedisk_read_native_max_address_ext(drive);
++                      set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
++                      if (set_max_ext) {
++                              drive->capacity48 = capacity_2 = set_max_ext;
++                              drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
++                              drive->select.b.lba = 1;
++                              drive->id->lba_capacity_2 = capacity_2;
++                        }
++#else /* !CONFIG_IDEDISK_STROKE */
++                      printk("%s: setmax_ext LBA %llu, native  %llu\n",
++                              drive->name, set_max_ext, capacity_2);
++#endif /* CONFIG_IDEDISK_STROKE */
++              }
++              drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
++              drive->bios_cyl         = drive->cyl;
++              drive->capacity48       = capacity_2;
++              drive->capacity         = (unsigned long) capacity_2;
++              return;
+       /* Determine capacity, and use LBA if the drive properly supports it */
+-      if ((id->capability & 2) && lba_capacity_is_ok(id)) {
++      } else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+               capacity = id->lba_capacity;
+               drive->cyl = capacity / (drive->head * drive->sect);
+               drive->select.b.lba = 1;
+       }
++
++      if (set_max > capacity) {
++#ifdef CONFIG_IDEDISK_STROKE
++              set_max = idedisk_read_native_max_address(drive);
++              set_max = idedisk_set_max_address(drive, set_max);
++              if (set_max) {
++                      drive->capacity = capacity = set_max;
++                      drive->cyl = set_max / (drive->head * drive->sect);
++                      drive->select.b.lba = 1;
++                      drive->id->lba_capacity = capacity;
++              }
++#else /* !CONFIG_IDEDISK_STROKE */
++              printk("%s: setmax LBA %lu, native  %lu\n",
++                      drive->name, set_max, capacity);
++#endif /* CONFIG_IDEDISK_STROKE */
++      }
++
+       drive->capacity = capacity;
++
++      if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
++              drive->capacity48 = id->lba_capacity_2;
++              drive->head = 255;
++              drive->sect = 63;
++              drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
++      }
+ }
+-static unsigned long idedisk_capacity (ide_drive_t  *drive)
++static unsigned long idedisk_capacity (ide_drive_t *drive)
+ {
++      if (drive->id->cfs_enable_2 & 0x0400)
++              return (drive->capacity48 - drive->sect0);
+       return (drive->capacity - drive->sect0);
+ }
+@@ -530,23 +1157,41 @@
+       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);
++              s->b.set_geometry       = 0;
++              if (!IS_PDC4030_DRIVE) {
++                      ide_task_t args;
++                      memset(&args, 0, sizeof(ide_task_t));
++                      args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
++                      args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
++                      args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
++                      args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
++                      args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
++                      args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
++                      args.command_type = ide_cmd_type_parser(&args);
++                      do_rw_taskfile(drive, &args);
++              }
+       } 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) {
++                      ide_task_t args;
++                      memset(&args, 0, sizeof(ide_task_t));
++                      args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
++                      args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
++                      args.command_type = ide_cmd_type_parser(&args);
++                      do_rw_taskfile(drive, &args);
++              }
+       } else if (s->b.set_multmode) {
+               s->b.set_multmode = 0;
+               if (drive->id && drive->mult_req > drive->id->max_multsect)
+                       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) {
++                      ide_task_t args;
++                      memset(&args, 0, sizeof(ide_task_t));
++                      args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
++                      args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
++                      args.command_type = ide_cmd_type_parser(&args);
++                      do_rw_taskfile(drive, &args);
++              }
+       } else if (s->all) {
+               int special = s->all;
+               s->all = 0;
+@@ -558,9 +1203,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)
+@@ -573,19 +1220,44 @@
+ static int smart_enable(ide_drive_t *drive)
+ {
+-      return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
++      ide_task_t args;
++
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_FEATURE_OFFSET]     = SMART_ENABLE;
++      args.tfRegister[IDE_LCYL_OFFSET]        = SMART_LCYL_PASS;
++      args.tfRegister[IDE_HCYL_OFFSET]        = SMART_HCYL_PASS;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SMART;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      return ide_raw_taskfile(drive, &args, NULL);
+ }
+ static int get_smart_values(ide_drive_t *drive, byte *buf)
+ {
++      ide_task_t args;
++
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_FEATURE_OFFSET]     = SMART_READ_VALUES;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
++      args.tfRegister[IDE_LCYL_OFFSET]        = SMART_LCYL_PASS;
++      args.tfRegister[IDE_HCYL_OFFSET]        = SMART_HCYL_PASS;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SMART;
++      args.command_type                       = ide_cmd_type_parser(&args);
+       (void) smart_enable(drive);
+-      return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
++      return ide_raw_taskfile(drive, &args, buf);
+ }
+ static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+ {
++      ide_task_t args;
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_FEATURE_OFFSET]     = SMART_READ_THRESHOLDS;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
++      args.tfRegister[IDE_LCYL_OFFSET]        = SMART_LCYL_PASS;
++      args.tfRegister[IDE_HCYL_OFFSET]        = SMART_HCYL_PASS;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SMART;
++      args.command_type                       = ide_cmd_type_parser(&args);
+       (void) smart_enable(drive);
+-      return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
++      return ide_raw_taskfile(drive, &args, buf);
+ }
+ static int proc_idedisk_read_cache
+@@ -609,7 +1281,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 {
+@@ -628,7 +1300,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 {
+@@ -654,6 +1326,10 @@
+ #endif        /* CONFIG_PROC_FS */
++/*
++ * This is tightly woven into the driver->do_special can not touch.
++ * DON'T do it again until a total personality rewrite is committed.
++ */
+ static int set_multcount(ide_drive_t *drive, int arg)
+ {
+       struct request rq;
+@@ -661,6 +1337,7 @@
+       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);
+@@ -677,6 +1354,136 @@
+       return 0;
+ }
++static int write_cache (ide_drive_t *drive, int arg)
++{
++      ide_task_t args;
++
++      if (!(drive->id->cfs_enable_2 & 0x3000))
++              return 1;
++
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ?
++                      SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SETFEATURES;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      (void) ide_raw_taskfile(drive, &args, NULL);
++
++      drive->wcache = arg;
++      return 0;
++}
++
++static int call_idedisk_standby (ide_drive_t *drive, int arg)
++{
++      ide_task_t args;
++      byte standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_COMMAND_OFFSET]     = standby;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      return ide_raw_taskfile(drive, &args, NULL);
++}
++
++static int do_idedisk_standby (ide_drive_t *drive)
++{
++      return call_idedisk_standby(drive, 0);
++}
++
++static int call_idedisk_suspend (ide_drive_t *drive, int arg)
++{
++      ide_task_t args;
++      byte suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_COMMAND_OFFSET]     = suspend;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      return ide_raw_taskfile(drive, &args, NULL);
++}
++
++static int do_idedisk_suspend (ide_drive_t *drive)
++{
++      if (drive->suspend_reset)
++              return 1;
++
++      return call_idedisk_suspend(drive, 0);
++}
++
++#if 0
++static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
++{
++      ide_task_t args;
++      byte ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_COMMAND_OFFSET]     = ckpw;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      ide_raw_taskfile(drive, &args, NULL);
++#if 0
++if (errno != EIO || args[0] != 0 || args[1] != 0)
++   state = "unknown";
++else
++   state = "sleeping";
++} else {
++   state = (args[2] == 255) ? "active/idle" : "standby";
++#endif
++      return 0;
++}
++
++static int do_idedisk_checkpower (ide_drive_t *drive)
++{
++      return call_idedisk_checkpower(drive, 0);
++}
++#endif
++
++static int do_idedisk_resume (ide_drive_t *drive)
++{
++      if (!drive->suspend_reset)
++              return 1;
++      return 0;
++}
++
++static int do_idedisk_flushcache (ide_drive_t *drive)
++{
++      ide_task_t args;
++
++      memset(&args, 0, sizeof(ide_task_t));
++      if (drive->id->cfs_enable_2 & 0x2400)
++              args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_FLUSH_CACHE_EXT;
++      else
++              args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_FLUSH_CACHE;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      return ide_raw_taskfile(drive, &args, NULL);
++}
++
++static int set_acoustic (ide_drive_t *drive, int arg)
++{
++      ide_task_t args;
++
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ? SETFEATURES_EN_AAM :
++                                                        SETFEATURES_DIS_AAM;
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = arg;
++      args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SETFEATURES;
++      args.command_type = ide_cmd_type_parser(&args);
++      ide_raw_taskfile(drive, &args, NULL);
++      drive->acoustic = arg;
++      return 0;
++}
++
++static int probe_lba_addressing (ide_drive_t *drive, int arg)
++{
++      drive->addressing =  0;
++
++      if (HWIF(drive)->addressing)
++              return 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;
+@@ -686,15 +1493,18 @@
+       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->bios_cyl,               NULL);
+       ide_add_setting(drive,  "bios_head",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &drive->bios_head,              NULL);
+       ide_add_setting(drive,  "bios_sect",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      63,                             1,      1,      &drive->bios_sect,              NULL);
++      ide_add_setting(drive,  "address",              SETTING_RW,                                     HDIO_GET_ADDRESS,       HDIO_SET_ADDRESS,       TYPE_INTA,      0,      2,                              1,      1,      &drive->addressing,     set_lba_addressing);
+       ide_add_setting(drive,  "bswap",                SETTING_READ,                                   -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,      1,      &drive->bswap,                  NULL);
+-      ide_add_setting(drive,  "multcount",            id ? SETTING_RW : SETTING_READ,                 HDIO_GET_MULTCOUNT,     HDIO_SET_MULTCOUNT,     TYPE_BYTE,      0,      id ? id->max_multsect : 0,      1,      2,      &drive->mult_count,             set_multcount);
++      ide_add_setting(drive,  "multcount",            id ? SETTING_RW : SETTING_READ,                 HDIO_GET_MULTCOUNT,     HDIO_SET_MULTCOUNT,     TYPE_BYTE,      0,      id ? id->max_multsect : 0,      1,      1,      &drive->mult_count,             set_multcount);
+       ide_add_setting(drive,  "nowerr",               SETTING_RW,                                     HDIO_GET_NOWERR,        HDIO_SET_NOWERR,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->nowerr,                 set_nowerr);
+-      ide_add_setting(drive,  "breada_readahead",     SETTING_RW,                                     BLKRAGET,               BLKRASET,               TYPE_INT,       0,      255,                            1,      2,      &read_ahead[major],             NULL);
++      ide_add_setting(drive,  "breada_readahead",     SETTING_RW,                                     BLKRAGET,               BLKRASET,               TYPE_INT,       0,      255,                            1,      1,      &read_ahead[major],             NULL);
+       ide_add_setting(drive,  "file_readahead",       SETTING_RW,                                     BLKFRAGET,              BLKFRASET,              TYPE_INTA,      0,      4096,                   PAGE_SIZE,      1024,   &max_readahead[major][minor],   NULL);
+-      ide_add_setting(drive,  "max_kb_per_request",   SETTING_RW,                                     BLKSECTGET,             BLKSECTSET,             TYPE_INTA,      1,      255,                            1,      2,      &max_sectors[major][minor],     NULL);
++      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,  "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);
++      ide_add_setting(drive,  "wcache",               SETTING_RW,                                     HDIO_GET_WCACHE,        HDIO_SET_WCACHE,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->wcache,                 write_cache);
++      ide_add_setting(drive,  "acoustic",             SETTING_RW,                                     HDIO_GET_ACOUSTIC,      HDIO_SET_ACOUSTIC,      TYPE_BYTE,      0,      254,                            1,      1,      &drive->acoustic,               set_acoustic);
++      ide_add_setting(drive,  "failures",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->failures,               NULL);
++      ide_add_setting(drive,  "max_failures",         SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->max_failures,           NULL);
+ }
+ static void idedisk_setup (ide_drive_t *drive)
+@@ -731,6 +1541,14 @@
+               break;
+       }
++#if 1
++      (void) probe_lba_addressing(drive, 1);
++#else
++      /* if using 48-bit addressing bump the request size up */
++      if (probe_lba_addressing(drive, 1))
++              blk_queue_max_sectors(&drive->queue, 2048);
++#endif
++
+       /* Extract geometry if we did not already have one for the drive */
+       if (!drive->cyl || !drive->head || !drive->sect) {
+               drive->cyl     = drive->bios_cyl  = id->cyls;
+@@ -764,7 +1582,6 @@
+       if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
+           (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
+               drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+-
+       printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
+       /* Give size in megabytes (MB), not mebibytes (MiB). */
+@@ -796,21 +1613,25 @@
+                       drive->mult_req = id->max_multsect;
+               if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+                       drive->special.b.set_multmode = 1;
+-#endif
++#endif        /* CONFIG_IDEDISK_MULTI_MODE */
+       }
+       drive->no_io_32bit = id->dword_io ? 1 : 0;
+-}
+-
+-static int idedisk_reinit (ide_drive_t *drive)
+-{
+-      return 0;
++      if (drive->id->cfs_enable_2 & 0x3000)
++              write_cache(drive, (id->cfs_enable_2 & 0x3000));
+ }
+ 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_init (void);
++int idedisk_reinit(ide_drive_t *drive);
++
+ /*
+  *      IDE subdriver functions, registered with ide.c
+  */
+@@ -822,8 +1643,14 @@
+       supports_dma:           1,
+       supports_dsc_overlap:   0,
+       cleanup:                idedisk_cleanup,
++      standby:                do_idedisk_standby,
++      suspend:                do_idedisk_suspend,
++      resume:                 do_idedisk_resume,
++      flushcache:             do_idedisk_flushcache,
+       do_request:             do_rw_disk,
+-      end_request:            NULL,
++      end_request:            idedisk_end_request,
++      sense:                  idedisk_dump_status,
++      error:                  idedisk_error,
+       ioctl:                  NULL,
+       open:                   idedisk_open,
+       release:                idedisk_release,
+@@ -833,10 +1660,12 @@
+       capacity:               idedisk_capacity,
+       special:                idedisk_special,
+       proc:                   idedisk_proc,
+-      driver_reinit:          idedisk_reinit,
++      init:                   idedisk_init,
++      reinit:                 idedisk_reinit,
++      ata_prebuilder:         NULL,
++      atapi_prebuilder:       NULL,
+ };
+-int idedisk_init (void);
+ static ide_module_t idedisk_module = {
+       IDE_DRIVER_MODULE,
+       idedisk_init,
+@@ -846,6 +1675,33 @@
+ MODULE_DESCRIPTION("ATA DISK Driver");
++int idedisk_reinit (ide_drive_t *drive)
++{
++      int failed = 0;
++
++      MOD_INC_USE_COUNT;
++
++      if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
++              printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
++              return 1;
++      }
++      DRIVER(drive)->busy++;
++      idedisk_setup(drive);
++      if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
++              printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
++                      drive->name, drive->head);
++              (void) idedisk_cleanup(drive);
++              DRIVER(drive)->busy--;
++              return 1;
++      }
++      DRIVER(drive)->busy--;
++      failed--;
++
++      ide_register_module(&idedisk_module);
++      MOD_DEC_USE_COUNT;
++      return 0;
++}
++
+ static void __exit idedisk_exit (void)
+ {
+       ide_drive_t *drive;
+@@ -877,12 +1733,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);
+@@ -890,6 +1749,78 @@
+       return 0;
+ }
++ide_startstop_t panic_box(ide_drive_t *drive)
++{
++#if 0
++      panic("%s: Attempted to corrupt something: ide operation "
++#else
++      printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
++#endif
++              "was pending accross suspend/resume.\n", drive->name);
++      return ide_stopped;
++}
++
++int ide_disks_busy(void)
++{
++      int i;
++      for (i=0; i<MAX_HWIFS; i++) {
++              struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
++              if (!hwgroup) continue;
++              if ((hwgroup->handler) && (hwgroup->handler != panic_box))
++                      return 1;
++      }
++      return 0;
++}
++
++void ide_disk_suspend(void)
++{
++      int i;
++      while (ide_disks_busy()) {
++              printk("*");
++              schedule();
++      }
++      for (i=0; i<MAX_HWIFS; i++) {
++              struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
++
++              if (!hwgroup) continue;
++              hwgroup->handler_save = hwgroup->handler;
++              hwgroup->handler = panic_box;
++      }
++      driver_blocked = 1;
++      if (ide_disks_busy())
++              panic("How did you get that request through?!");
++}
++
++/* unsuspend and resume should be equal in the ideal world */
++
++void ide_disk_unsuspend(void)
++{
++      int i;
++      for (i=0; i<MAX_HWIFS; i++) {
++              struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
++
++              if (!hwgroup) continue;
++              hwgroup->handler = NULL; /* hwgroup->handler_save; */
++              hwgroup->handler_save = NULL;
++      }
++      driver_blocked = 0;
++}
++
++void ide_disk_resume(void)
++{
++      int i;
++      for (i=0; i<MAX_HWIFS; i++) {
++              struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
++
++              if (!hwgroup) continue;
++              if (hwgroup->handler != panic_box)
++                      panic("Handler was not set to panic?");
++              hwgroup->handler_save = NULL;
++              hwgroup->handler = NULL;
++      }
++      driver_blocked = 0;
++}
++
+ module_init(idedisk_init);
+ module_exit(idedisk_exit);
+ MODULE_LICENSE("GPL");
+diff -Nur linux.org/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
+--- linux.org/drivers/ide/ide-dma.c    Sun Sep  9 19:43:02 2001
++++ linux/drivers/ide/ide-dma.c        Thu Jul 18 14:24:33 2002
+@@ -101,8 +101,6 @@
+ #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 {
+@@ -237,14 +235,14 @@
+                       rq = HWGROUP(drive)->rq;
+                       for (i = rq->nr_sectors; i > 0;) {
+                               i -= rq->current_nr_sectors;
+-                              ide_end_request(1, HWGROUP(drive));
++                              DRIVER(drive)->end_request(drive, 1);
+                       }
+                       return ide_stopped;
+               }
+               printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+                      drive->name, dma_stat);
+       }
+-      return ide_error(drive, "dma_intr", stat);
++      return DRIVER(drive)->error(drive, "dma_intr", stat);
+ }
+ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+@@ -282,6 +280,48 @@
+       return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+ }
++static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
++{
++      struct scatterlist *sg = hwif->sg_table;
++      int nents = 0;
++      ide_task_t *args = rq->special;
++      unsigned char *virt_addr = rq->buffer;
++      int sector_count = rq->nr_sectors;
++
++      if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
++              hwif->sg_dma_direction = PCI_DMA_TODEVICE;
++      else
++              hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++#if 1
++      if (sector_count > 128) {
++              memset(&sg[nents], 0, sizeof(*sg));
++              sg[nents].address = virt_addr;
++              sg[nents].length = 128  * SECTOR_SIZE;
++              nents++;
++              virt_addr = virt_addr + (128 * SECTOR_SIZE);
++              sector_count -= 128;
++      }
++      memset(&sg[nents], 0, sizeof(*sg));
++      sg[nents].address = virt_addr;
++      sg[nents].length =  sector_count  * SECTOR_SIZE;
++      nents++;
++#else
++        while (sector_count > 128) {
++              memset(&sg[nents], 0, sizeof(*sg));
++              sg[nents].address       = virt_addr;
++              sg[nents].length        = 128 * SECTOR_SIZE;
++              nents++;
++              virt_addr               = virt_addr + (128 * SECTOR_SIZE);
++              sector_count            -= 128;
++      };
++      memset(&sg[nents], 0, sizeof(*sg));
++      sg[nents].address       = virt_addr;
++      sg[nents].length        = sector_count * SECTOR_SIZE;
++      nents++;
++#endif
++      return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
++}
++
+ /*
+  * ide_build_dmatable() prepares a dma request.
+  * Returns 0 if all went okay, returns 1 otherwise.
+@@ -299,7 +339,10 @@
+       int i;
+       struct scatterlist *sg;
+-      HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
++      if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
++              HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
++      else
++              HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+       if (!i)
+               return 0;
+@@ -429,7 +472,14 @@
+       struct hd_driveid *id = drive->id;
+       if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+-          (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
++          (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
++              if ((id->dma_ultra >> 15) & 1) {
++                      printk(", UDMA(mode 7)");       /* UDMA BIOS-enabled! */
++              } else {
++                      printk(", UDMA(133)");  /* UDMA BIOS-enabled! */
++              }
++      } else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
++                (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+               if ((id->dma_ultra >> 13) & 1) {
+                       printk(", UDMA(100)");  /* UDMA BIOS-enabled! */
+               } else if ((id->dma_ultra >> 12) & 1) {
+@@ -464,6 +514,10 @@
+               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))
+@@ -483,54 +537,70 @@
+       return hwif->dmaproc(ide_dma_off_quietly, drive);
+ }
+-#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
++#ifndef __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);
++      byte dma_stat = IN_BYTE(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
++#if 0
+       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);
++              return DRIVER(drive)->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)
++#else /* __IDEDMA_TIMEOUT */
++static int ide_dma_timeout_recovery (ide_drive_t *drive)
+ {
+-      ide_hwgroup_t *hwgroup  = HWGROUP(drive);
+-      ide_hwif_t *hwif        = HWIF(drive);
++      struct request *rq      = HWGROUP(drive)->rq;
+       int enable_dma          = drive->using_dma;
++      int speed               = drive->current_speed;
+       unsigned long flags;
+-      ide_startstop_t startstop;
+       spin_lock_irqsave(&io_request_lock, flags);
+-      hwgroup->handler = NULL;
+-      del_timer(&hwgroup->timer);
++      HWGROUP(drive)->handler = NULL;
++      del_timer(&HWGROUP(drive)->timer);
++      HWGROUP(drive)->expiry  = NULL;
++      HWGROUP(drive)->rq      = NULL;
+       spin_unlock_irqrestore(&io_request_lock, flags);
++      (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+       drive->waiting_for_dma = 0;
+-      startstop = ide_do_reset(drive);
++      (void) ide_do_reset(drive);
++
++      if (!(drive_is_ready(drive))) {
++              /* FIXME: Replace hard-coded 100, error handling? */
++              int i;
++              for (i=0; i<100; i++) {
++                      if (drive_is_ready(drive))
++                              break;
++              }
++      }
++
++      if ((HWIF(drive)->speedproc) != NULL) {
++              HWIF(drive)->speedproc(drive, speed);
++              drive->current_speed = speed;
++      }
+       if ((enable_dma) && !(drive->using_dma))
+-              (void) hwif->dmaproc(ide_dma_on, drive);
++              (void) HWIF(drive)->dmaproc(ide_dma_on, drive);
+-      return startstop;
++      return restart_request(drive, rq);
+ }
+-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
++#endif /* __IDEDMA_TIMEOUT */
+ /*
+  * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
+@@ -550,8 +620,8 @@
+  */
+ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
+-//    ide_hwgroup_t *hwgroup          = HWGROUP(drive);
+       ide_hwif_t *hwif                = HWIF(drive);
++//    ide_task_t *args                = HWGROUP(drive)->rq->special;
+       unsigned long dma_base          = hwif->dma_base;
+       byte unit                       = (drive->select.b.unit & 0x01);
+       unsigned int count, reading     = 0;
+@@ -561,11 +631,17 @@
+               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_host_off:
++                      OUT_BYTE(IN_BYTE(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
++                      if (func == ide_dma_host_off)
++                              return 0;
+               case ide_dma_on:
+                       drive->using_dma = (func == ide_dma_on);
++                      if (!drive->using_dma)
++                              return 0;
++              case ide_dma_host_on:
+                       if (drive->using_dma)
+-                              outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
++                              OUT_BYTE(IN_BYTE(dma_base+2)|(1<<(5+unit)), dma_base+2);
+                       return 0;
+               case ide_dma_check:
+                       return config_drive_for_dma (drive);
+@@ -574,88 +650,127 @@
+               case ide_dma_write:
+                       SELECT_READ_WRITE(hwif,drive,func);
+                       if (!(count = ide_build_dmatable(drive, func)))
+-                              return 1;       /* try PIO instead of DMA */
+-                      outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
+-                      outb(reading, dma_base);                        /* specify r/w */
+-                      outb(inb(dma_base+2)|6, dma_base+2);            /* clear INTR & ERROR flags */
++                              /* try PIO instead of DMA */
++                              return 1;
++                      /* PRD table */
++                      outl(hwif->dmatable_dma, dma_base + 4);
++                      /* specify r/w */
++                      OUT_BYTE(reading, dma_base);
++                      /* clear INTR & ERROR flags */
++                      OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2);
+                       drive->waiting_for_dma = 1;
+                       if (drive->media != ide_disk)
+                               return 0;
+-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
+-                      ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);  /* issue cmd to drive */
+-#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+-                      ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);      /* issue cmd to drive */
+-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+-                      OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++                      /* paranoia check */
++                      if (HWGROUP(drive)->handler != NULL)
++                              BUG();
++#ifndef __IDEDMA_TIMEOUT
++                      ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
++#else /* __IDEDMA_TIMEOUT */
++                      ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);
++#endif /* __IDEDMA_TIMEOUT */
++                      /* issue cmd to drive */
++                      /*
++                       * FIX ME to use only ACB ide_task_t args Struct
++                       */
++#if 0
++              {
++                      ide_task_t *args = HWGROUP(drive)->rq->special;
++                      OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++              }
++#else
++                      if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
++                              ide_task_t *args = HWGROUP(drive)->rq->special;
++                              OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++                      } else if (drive->addressing == 1)
++                              OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
++                      else
++                              OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++#endif
++                      return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+               case ide_dma_begin:
+                       /* Note that this is done *after* the cmd has
+                        * been issued to the drive, as per the BM-IDE spec.
+                        * The Promise Ultra33 doesn't work correctly when
+                        * we do this part before issuing the drive cmd.
+                        */
+-                      outb(inb(dma_base)|1, dma_base);                /* start DMA */
++                      /* start DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)|1, dma_base);
+                       return 0;
+               case ide_dma_end: /* returns 1 on error, 0 otherwise */
+                       drive->waiting_for_dma = 0;
+-                      outb(inb(dma_base)&~1, dma_base);       /* stop DMA */
+-                      dma_stat = inb(dma_base+2);             /* get DMA status */
+-                      outb(dma_stat|6, dma_base+2);   /* clear the INTR & ERROR bits */
+-                      ide_destroy_dmatable(drive);    /* purge DMA mappings */
+-                      return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;     /* verify good DMA status */
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
++                      /* get DMA status */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* clear the INTR & ERROR bits */
++                      OUT_BYTE(dma_stat|6, dma_base+2);
++                      /* purge DMA mappings */
++                      ide_destroy_dmatable(drive);
++                      /* verify good DMA status */
++                      return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+               case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+-                      dma_stat = inb(dma_base+2);
+-#if 0 /* do not set unless you know what you are doing */
++                      dma_stat = IN_BYTE(dma_base+2);
++#if 0  /* do not set unless you know what you are doing */
+                       if (dma_stat & 4) {
+                               byte stat = GET_STAT();
+-                              outb(dma_base+2, dma_stat & 0xE4);
++                              OUT_BYTE(dma_base+2, dma_stat & 0xE4);
+                       }
+ #endif
+-                      return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
++                      /* return 1 if INTR asserted */
++                      return (dma_stat & 4) == 4;
+               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
++      // 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 __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 */
++#if 0
++                      dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
++#else
++                      drive->waiting_for_dma = 0;
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
++//                    OUT_BYTE(0x00, dma_base);
++                      /* get DMA status */
++                      dma_stat = IN_BYTE(dma_base+2);
++                      /* clear the INTR & ERROR bits */
++                      OUT_BYTE(dma_stat|6, dma_base+2);
++                      /* purge DMA mappings */
++                      ide_destroy_dmatable(drive);
++#endif
+                       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!!
+-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
++                              return ide_dma_timeout_recovery(drive);
++#endif /* __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);
++                      printk("ide_dmaproc: chipset supported %s "
++                              "func only: %d\n",
++                              ide_dmafunc_verbose(func),  func);
+                       return 1;
+               default:
+-                      printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
++                      printk("ide_dmaproc: unsupported %s func: %d\n",
++                              ide_dmafunc_verbose(func), func);
+                       return 1;
+       }
+ }
+@@ -683,7 +798,7 @@
+ }
+ /*
+- *    This can be called for a dynamically installed interface. Don't __init it
++ * This can be called for a dynamically installed interface. Don't __init it
+  */
+  
+ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+@@ -712,7 +827,7 @@
+       hwif->dmaproc = &ide_dmaproc;
+       if (hwif->chipset != ide_trm290) {
+-              byte dma_stat = inb(dma_base+2);
++              byte dma_stat = IN_BYTE(dma_base+2);
+               printk(", BIOS settings: %s:%s, %s:%s",
+                      hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+                      hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+@@ -777,8 +892,9 @@
+                       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) {
++                      case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
++                              OUT_BYTE(IN_BYTE(dma_base+2) & 0x60, dma_base+2);
++                              if (IN_BYTE(dma_base+2) & 0x80) {
+                                       printk("%s: simplex device: DMA forced\n", name);
+                               }
+                               break;
+@@ -790,7 +906,7 @@
+                                * So we should enable DMA only on one of the
+                                * two interfaces.
+                                */
+-                              if ((inb(dma_base+2) & 0x80)) { /* simplex device? */
++                              if ((IN_BYTE(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);
+diff -Nur linux.org/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
+--- linux.org/drivers/ide/ide-features.c       Fri Feb  9 20:40:02 2001
++++ linux/drivers/ide/ide-features.c   Thu Jan  1 01:00:00 1970
+@@ -1,391 +0,0 @@
+-/*
+- * linux/drivers/block/ide-features.c Version 0.04    June 9, 2000
+- *
+- *  Copyright (C) 1999-2000   Linus Torvalds & authors (see below)
+- *  
+- *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
+- *
+- *  Extracts if ide.c to address the evolving transfer rate code for
+- *  the SETFEATURES_XFER callouts.  Various parts of any given function
+- *  are credited to previous ATA-IDE maintainers.
+- *
+- *  Auto-CRC downgrade for Ultra DMA(ing)
+- *
+- *  May be copied or modified under the terms of the GNU General Public License
+- */
+-
+-#include <linux/config.h>
+-#define __NO_VERSION__
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/string.h>
+-#include <linux/kernel.h>
+-#include <linux/timer.h>
+-#include <linux/mm.h>
+-#include <linux/interrupt.h>
+-#include <linux/major.h>
+-#include <linux/errno.h>
+-#include <linux/genhd.h>
+-#include <linux/blkpg.h>
+-#include <linux/slab.h>
+-#include <linux/pci.h>
+-#include <linux/delay.h>
+-#include <linux/hdreg.h>
+-#include <linux/ide.h>
+-
+-#include <asm/byteorder.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/bitops.h>
+-
+-/*
+- * A Verbose noise maker for debugging on the attempted transfer rates.
+- */
+-char *ide_xfer_verbose (byte xfer_rate)
+-{
+-      switch(xfer_rate) {
+-              case XFER_UDMA_7:       return("UDMA 7");
+-              case XFER_UDMA_6:       return("UDMA 6");
+-              case XFER_UDMA_5:       return("UDMA 5");
+-              case XFER_UDMA_4:       return("UDMA 4");
+-              case XFER_UDMA_3:       return("UDMA 3");
+-              case XFER_UDMA_2:       return("UDMA 2");
+-              case XFER_UDMA_1:       return("UDMA 1");
+-              case XFER_UDMA_0:       return("UDMA 0");
+-              case XFER_MW_DMA_2:     return("MW DMA 2");
+-              case XFER_MW_DMA_1:     return("MW DMA 1");
+-              case XFER_MW_DMA_0:     return("MW DMA 0");
+-              case XFER_SW_DMA_2:     return("SW DMA 2");
+-              case XFER_SW_DMA_1:     return("SW DMA 1");
+-              case XFER_SW_DMA_0:     return("SW DMA 0");
+-              case XFER_PIO_4:        return("PIO 4");
+-              case XFER_PIO_3:        return("PIO 3");
+-              case XFER_PIO_2:        return("PIO 2");
+-              case XFER_PIO_1:        return("PIO 1");
+-              case XFER_PIO_0:        return("PIO 0");
+-              case XFER_PIO_SLOW:     return("PIO SLOW");
+-              default:                return("XFER ERROR");
+-      }
+-}
+-
+-/*
+- *
+- */
+-char *ide_media_verbose (ide_drive_t *drive)
+-{
+-      switch (drive->media) {
+-              case ide_scsi:          return("scsi   ");
+-              case ide_disk:          return("disk   ");
+-              case ide_optical:       return("optical");
+-              case ide_cdrom:         return("cdrom  ");
+-              case ide_tape:          return("tape   ");
+-              case ide_floppy:        return("floppy ");
+-              default:                return("???????");
+-      }
+-}
+-
+-/*
+- * A Verbose noise maker for debugging on the attempted dmaing calls.
+- */
+-char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
+-{
+-      switch (dmafunc) {
+-              case ide_dma_read:              return("ide_dma_read");
+-              case ide_dma_write:             return("ide_dma_write");
+-              case ide_dma_begin:             return("ide_dma_begin");
+-              case ide_dma_end:               return("ide_dma_end:");
+-              case ide_dma_check:             return("ide_dma_check");
+-              case ide_dma_on:                return("ide_dma_on");
+-              case ide_dma_off:               return("ide_dma_off");
+-              case ide_dma_off_quietly:       return("ide_dma_off_quietly");
+-              case ide_dma_test_irq:          return("ide_dma_test_irq");
+-              case ide_dma_bad_drive:         return("ide_dma_bad_drive");
+-              case ide_dma_good_drive:        return("ide_dma_good_drive");
+-              case ide_dma_verbose:           return("ide_dma_verbose");
+-              case ide_dma_retune:            return("ide_dma_retune");
+-              case ide_dma_lostirq:           return("ide_dma_lostirq");
+-              case ide_dma_timeout:           return("ide_dma_timeout");
+-              default:                        return("unknown");
+-      }
+-}
+-
+-/*
+- *
+- */
+-byte ide_auto_reduce_xfer (ide_drive_t *drive)
+-{
+-      if (!drive->crc_count)
+-              return drive->current_speed;
+-      drive->crc_count = 0;
+-
+-      switch(drive->current_speed) {
+-              case XFER_UDMA_7:       return XFER_UDMA_6;
+-              case XFER_UDMA_6:       return XFER_UDMA_5;
+-              case XFER_UDMA_5:       return XFER_UDMA_4;
+-              case XFER_UDMA_4:       return XFER_UDMA_3;
+-              case XFER_UDMA_3:       return XFER_UDMA_2;
+-              case XFER_UDMA_2:       return XFER_UDMA_1;
+-              case XFER_UDMA_1:       return XFER_UDMA_0;
+-              case XFER_UDMA_0:
+-                      if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
+-                      else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
+-                      else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
+-                      else return XFER_PIO_4;
+-              case XFER_MW_DMA_2:     return XFER_MW_DMA_1;
+-              case XFER_MW_DMA_1:     return XFER_MW_DMA_0;
+-              case XFER_MW_DMA_0:
+-                      if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
+-                      else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
+-                      else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
+-                      else return XFER_PIO_4;
+-              case XFER_SW_DMA_2:     return XFER_SW_DMA_1;
+-              case XFER_SW_DMA_1:     return XFER_SW_DMA_0;
+-              case XFER_SW_DMA_0:
+-                      {
+-                              return XFER_PIO_4;
+-                      }
+-              case XFER_PIO_4:        return XFER_PIO_3;
+-              case XFER_PIO_3:        return XFER_PIO_2;
+-              case XFER_PIO_2:        return XFER_PIO_1;
+-              case XFER_PIO_1:        return XFER_PIO_0;
+-              case XFER_PIO_0:
+-              default:                return XFER_PIO_SLOW;
+-      }
+-}
+-
+-/*
+- * Update the 
+- */
+-int ide_driveid_update (ide_drive_t *drive)
+-{
+-      /*
+-       * Re-read drive->id for possible DMA mode
+-       * change (copied from ide-probe.c)
+-       */
+-      struct hd_driveid *id;
+-      unsigned long timeout, flags;
+-
+-      SELECT_MASK(HWIF(drive), drive, 1);
+-      if (IDE_CONTROL_REG)
+-              OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+-      ide_delay_50ms();
+-      OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
+-      timeout = jiffies + WAIT_WORSTCASE;
+-      do {
+-              if (0 < (signed long)(jiffies - timeout)) {
+-                      SELECT_MASK(HWIF(drive), drive, 0);
+-                      return 0;       /* drive timed-out */
+-              }
+-              ide_delay_50ms();       /* give drive a breather */
+-      } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
+-      ide_delay_50ms();       /* wait for IRQ and DRQ_STAT */
+-      if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+-              SELECT_MASK(HWIF(drive), drive, 0);
+-              printk("%s: CHECK for good STATUS\n", drive->name);
+-              return 0;
+-      }
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only; some systems need this */
+-      SELECT_MASK(HWIF(drive), drive, 0);
+-      id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+-      if (!id) {
+-              __restore_flags(flags); /* local CPU only */
+-              return 0;
+-      }
+-      ide_input_data(drive, id, SECTOR_WORDS);
+-      (void) GET_STAT();      /* clear drive IRQ */
+-      ide__sti();             /* local CPU only */
+-      __restore_flags(flags); /* local CPU only */
+-      ide_fix_driveid(id);
+-      if (id) {
+-              drive->id->dma_ultra = id->dma_ultra;
+-              drive->id->dma_mword = id->dma_mword;
+-              drive->id->dma_1word = id->dma_1word;
+-              /* anything more ? */
+-              kfree(id);
+-      }
+-
+-      return 1;
+-}
+-
+-/*
+- * Verify that we are doing an approved SETFEATURES_XFER with respect
+- * to the hardware being able to support request.  Since some hardware
+- * can improperly report capabilties, we check to see if the host adapter
+- * in combination with the device (usually a disk) properly detect
+- * and acknowledge each end of the ribbon.
+- */
+-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+-{
+-      if ((cmd == WIN_SETFEATURES) &&
+-          (nsect > XFER_UDMA_2) &&
+-          (feature == 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, byte cmd, byte nsect, byte feature)
+-{
+-      if ((cmd == WIN_SETFEATURES) &&
+-          (nsect >= XFER_SW_DMA_0) &&
+-          (feature == 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;
+-
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+-      byte unit = (drive->select.b.unit & 0x01);
+-      outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+-
+-      /*
+-       * Don't use ide_wait_cmd here - it will
+-       * attempt to set_geometry and recalibrate,
+-       * but for some reason these don't work at
+-       * this point (lost interrupt).
+-       */
+-        /*
+-         * Select the drive, and issue the SETFEATURES command
+-         */
+-      disable_irq(hwif->irq); /* disable_irq_nosync ?? */
+-      udelay(1);
+-      SELECT_DRIVE(HWIF(drive), drive);
+-      SELECT_MASK(HWIF(drive), drive, 0);
+-      udelay(1);
+-      if (IDE_CONTROL_REG)
+-              OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+-      OUT_BYTE(speed, IDE_NSECTOR_REG);
+-      OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+-      OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+-      if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+-              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+-      udelay(1);
+-      /*
+-       * Wait for drive to become non-BUSY
+-       */
+-      if ((stat = GET_STAT()) & BUSY_STAT) {
+-              unsigned long flags, timeout;
+-              __save_flags(flags);    /* local CPU only */
+-              ide__sti();             /* local CPU only -- for jiffies */
+-              timeout = jiffies + WAIT_CMD;
+-              while ((stat = GET_STAT()) & BUSY_STAT) {
+-                      if (0 < (signed long)(jiffies - timeout))
+-                              break;
+-              }
+-              __restore_flags(flags); /* local CPU only */
+-      }
+-
+-      /*
+-       * Allow status to settle, then read it again.
+-       * A few rare drives vastly violate the 400ns spec here,
+-       * so we'll wait up to 10usec for a "good" status
+-       * rather than expensively fail things immediately.
+-       * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+-       */
+-      for (i = 0; i < 10; i++) {
+-              udelay(1);
+-              if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+-                      error = 0;
+-                      break;
+-              }
+-      }
+-
+-      SELECT_MASK(HWIF(drive), drive, 0);
+-
+-      enable_irq(hwif->irq);
+-
+-      if (error) {
+-              (void) ide_dump_status(drive, "set_drive_speed_status", stat);
+-              return error;
+-      }
+-
+-      drive->id->dma_ultra &= ~0xFF00;
+-      drive->id->dma_mword &= ~0x0F00;
+-      drive->id->dma_1word &= ~0x0F00;
+-
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+-      if (speed > XFER_PIO_4) {
+-              outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
+-      } else {
+-              outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+-      }
+-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+-
+-      switch(speed) {
+-              case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+-              case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+-              case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+-              case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+-              case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+-              case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+-              case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+-              case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+-              case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+-              case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+-              case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+-              case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+-              case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+-              case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+-              default: break;
+-      }
+-      return error;
+-}
+-
+-EXPORT_SYMBOL(ide_auto_reduce_xfer);
+-EXPORT_SYMBOL(ide_driveid_update);
+-EXPORT_SYMBOL(ide_ata66_check);
+-EXPORT_SYMBOL(set_transfer);
+-EXPORT_SYMBOL(eighty_ninty_three);
+-EXPORT_SYMBOL(ide_config_drive_speed);
+diff -Nur linux.org/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
+--- linux.org/drivers/ide/ide-floppy.c Fri Dec 21 18:41:54 2001
++++ linux/drivers/ide/ide-floppy.c     Thu Jul 18 14:24:33 2002
+@@ -1,8 +1,8 @@
+ /*
+- * linux/drivers/ide/ide-floppy.c     Version 0.97.sv Jan 14 2001
++ * linux/drivers/ide/ide-floppy.c     Version 0.99    Feb 24 2002
+  *
+  * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+- * Copyright (C) 2000 - 2001 Paul Bristow <paul@paulbristow.net>
++ * Copyright (C) 2000 - 2002 Paul Bristow <paul@paulbristow.net>
+  */
+ /*
+@@ -13,7 +13,7 @@
+  *
+  * This driver supports the following IDE floppy drives:
+  *
+- * LS-120 SuperDisk
++ * LS-120/240 SuperDisk
+  * Iomega Zip 100/250
+  * Iomega PC Card Clik!/PocketZip
+  *
+@@ -68,12 +68,19 @@
+  * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
+  * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
+  * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
+- *                       including set_bit patch from Rusty Russel
++ *                       including set_bit patch from Rusty Russell
+  * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
+  * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
++ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
++ *                        fix a lost interrupt problem. It appears the busy
++ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
++ *                        drive before the drive was actually ready.
++ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
++ * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code 
++ *                        to support new PocketZip drives 
+  */
+-#define IDEFLOPPY_VERSION "0.97.sv"
++#define IDEFLOPPY_VERSION "0.99.newide"
+ #include <linux/config.h>
+ #include <linux/module.h>
+@@ -276,6 +283,7 @@
+        *      Last error information
+        */
+       byte sense_key, asc, ascq;
++      byte ticks;             /* delay this long before sending packet command */
+       int progress_indication;
+       /*
+@@ -289,6 +297,8 @@
+       unsigned long flags;                    /* Status/Action flags */
+ } idefloppy_floppy_t;
++#define IDEFLOPPY_TICKS_DELAY 3       /* default delay for ZIP 100 */
++
+ /*
+  *    Floppy flag bits values.
+  */
+@@ -297,7 +307,7 @@
+ #define IDEFLOPPY_USE_READ12          2       /* Use READ12/WRITE12 or READ10/WRITE10 */
+ #define       IDEFLOPPY_FORMAT_IN_PROGRESS    3       /* Format in progress */
+ #define IDEFLOPPY_CLIK_DRIVE          4       /* Avoid commands not supported in Clik drive */
+-
++#define IDEFLOPPY_ZIP_DRIVE           5       /* Requires BH algorithm for packets */
+ /*
+  *    ATAPI floppy drive packet commands
+@@ -658,28 +668,57 @@
+ static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
+ {
+       while (bcount--)
+-              IN_BYTE (IDE_DATA_REG);
++              IN_BYTE(IDE_DATA_REG);
+ }
+ #if IDEFLOPPY_DEBUG_BUGS
+ static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
+ {
+       while (bcount--)
+-              OUT_BYTE (0, IDE_DATA_REG);
++              OUT_BYTE(0, IDE_DATA_REG);
+ }
+ #endif /* IDEFLOPPY_DEBUG_BUGS */
++
++static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
++{
++      struct request *rq;
++      unsigned long flags;
++      int ret = 1;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      rq = HWGROUP(drive)->rq;
++
++      /*
++       * decide whether to reenable DMA -- 3 is a random magic for now,
++       * if we DMA timeout more than 3 times, just stay in PIO
++       */
++      if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
++              drive->state = 0;
++              HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
++      }
++
++      if (!end_that_request_first(rq, uptodate, drive->name)) {
++              add_blkdev_randomness(MAJOR(rq->rq_dev));
++              blkdev_dequeue_request(rq);
++              HWGROUP(drive)->rq = NULL;
++              end_that_request_last(rq);
++              ret = 0;
++      }
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return ret;
++}
++
+ /*
+- *    idefloppy_end_request is used to finish servicing a request.
++ *    idefloppy_do_end_request is used to finish servicing a request.
+  *
+  *    For read/write requests, we will call ide_end_request to pass to the
+  *    next buffer.
+  */
+-static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
++static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
+ {
+-      ide_drive_t *drive = hwgroup->drive;
+       idefloppy_floppy_t *floppy = drive->driver_data;
+-      struct request *rq = hwgroup->rq;
++      struct request *rq = HWGROUP(drive)->rq;
+       int error;
+ #if IDEFLOPPY_DEBUG_LOG
+@@ -695,13 +734,16 @@
+               floppy->failed_pc = NULL;
+       /* Why does this happen? */
+       if (!rq)
+-              return;
++              return 0;
+       if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+-              ide_end_request (uptodate, hwgroup);
+-              return;
++              /* our real local end request function */
++              idefloppy_end_request(drive, uptodate);
++              return 0;
+       }
+       rq->errors = error;
++      /* fixme: need to move this local also */
+       ide_end_drive_cmd (drive, 0, 0);
++      return 0;
+ }
+ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+@@ -714,7 +756,7 @@
+               if (pc->b_count == bh->b_size) {
+                       rq->sector += rq->current_nr_sectors;
+                       rq->nr_sectors -= rq->current_nr_sectors;
+-                      idefloppy_end_request (1, HWGROUP(drive));
++                      idefloppy_do_end_request(drive, 1);
+                       if ((bh = rq->bh) != NULL)
+                               pc->b_count = 0;
+               }
+@@ -739,7 +781,7 @@
+               if (!pc->b_count) {
+                       rq->sector += rq->current_nr_sectors;
+                       rq->nr_sectors -= rq->current_nr_sectors;
+-                      idefloppy_end_request (1, HWGROUP(drive));
++                      idefloppy_do_end_request(drive, 1);
+                       if ((bh = rq->bh) != NULL) {
+                               pc->b_data = bh->b_data;
+                               pc->b_count = bh->b_size;
+@@ -763,7 +805,7 @@
+       struct buffer_head *bh = rq->bh;
+       while ((bh = rq->bh) != NULL)
+-              idefloppy_end_request (1, HWGROUP(drive));
++              idefloppy_do_end_request(drive, 1);
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+@@ -826,10 +868,10 @@
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+       if (!floppy->pc->error) {
+               idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+-              idefloppy_end_request (1,HWGROUP (drive));
++              idefloppy_do_end_request(drive, 1);
+       } else {
+               printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+-              idefloppy_end_request (0,HWGROUP (drive));
++              idefloppy_do_end_request(drive, 0);
+       }
+ }
+@@ -844,7 +886,7 @@
+       printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+-      idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive));
++      idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
+ }
+ /*
+@@ -929,7 +971,7 @@
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+               clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+-              ide__sti();     /* local CPU only */
++              local_irq_enable();
+               if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {    /* Error detected */
+ #if IDEFLOPPY_DEBUG_LOG
+@@ -975,7 +1017,9 @@
+                       if (temp > pc->buffer_size) {
+                               printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
+                               idefloppy_discard_data (drive,bcount.all);
+-                              ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
++                              if (HWGROUP(drive)->handler != NULL)
++                                      BUG();
++                              ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+                               return ide_started;
+                       }
+ #if IDEFLOPPY_DEBUG_LOG
+@@ -997,10 +1041,17 @@
+       pc->actually_transferred+=bcount.all;                           /* Update the current position */
+       pc->current_position+=bcount.all;
+-      ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);            /* And set the interrupt handler again */
++      if (HWGROUP(drive)->handler != NULL)
++              BUG();
++      ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);           /* And set the interrupt handler again */
+       return ide_started;
+ }
++/*
++ * This is the original routine that did the packet transfer.
++ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
++ * for that drive below. The algorithm is chosen based on drive type
++ */
+ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+ {
+       ide_startstop_t startstop;
+@@ -1008,19 +1059,77 @@
+       idefloppy_ireason_reg_t ireason;
+       if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+-              printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
++              printk(KERN_ERR "ide-floppy: Strange, packet command "
++                              "initiated yet DRQ isn't asserted\n");
+               return startstop;
+       }
+-      ireason.all=IN_BYTE (IDE_IREASON_REG);
++      ireason.all = IN_BYTE(IDE_IREASON_REG);
+       if (!ireason.b.cod || ireason.b.io) {
+-              printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
++              printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
++                              "issuing a packet command\n");
+               return ide_do_reset (drive);
+       }
+-      ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);  /* Set the interrupt routine */
++      if (HWGROUP(drive)->handler != NULL)
++              BUG();
++      ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);   /* Set the interrupt routine */
+       atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+       return ide_started;
+ }
++
++/*
++ * What we have here is a classic case of a top half / bottom half
++ * interrupt service routine. In interrupt mode, the device sends
++ * an interrupt to signal it's ready to receive a packet. However,
++ * we need to delay about 2-3 ticks before issuing the packet or we
++ * gets in trouble.
++ *
++ * So, follow carefully. transfer_pc1 is called as an interrupt (or
++ * directly). In either case, when the device says it's ready for a 
++ * packet, we schedule the packet transfer to occur about 2-3 ticks
++ * later in transfer_pc2.
++ */
++static int idefloppy_transfer_pc2 (ide_drive_t *drive)
++{
++      idefloppy_floppy_t *floppy = drive->driver_data;
++
++      atapi_output_bytes(drive, floppy->pc->c, 12); /* Send the actual packet */
++      return IDEFLOPPY_WAIT_CMD;      /* Timeout for the packet command */
++}
++
++static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
++{
++      idefloppy_floppy_t *floppy = drive->driver_data;
++      ide_startstop_t startstop;
++      idefloppy_ireason_reg_t ireason;
++
++      if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
++              printk(KERN_ERR "ide-floppy: Strange, packet command "
++                              "initiated yet DRQ isn't asserted\n");
++              return startstop;
++      }
++      ireason.all = IN_BYTE(IDE_IREASON_REG);
++      if (!ireason.b.cod || ireason.b.io) {
++              printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
++                              "while issuing a packet command\n");
++              return ide_do_reset (drive);
++      }
++      /* 
++       * The following delay solves a problem with ATAPI Zip 100 drives where the
++       * Busy flag was apparently being deasserted before the unit was ready to
++       * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
++       * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
++       * not be actually used until after the packet is moved in about 50 msec.
++       */
++      if (HWGROUP(drive)->handler != NULL)
++              BUG();
++      ide_set_handler(drive, 
++        &idefloppy_pc_intr,           /* service routine for packet command */
++        floppy->ticks,                /* wait this long before "failing" */
++        &idefloppy_transfer_pc2);     /* fail == transfer_pc2 */
++      return ide_started;
++}
++
+ /*
+  *    Issue a packet command
+  */
+@@ -1029,6 +1138,7 @@
+       idefloppy_floppy_t *floppy = drive->driver_data;
+       idefloppy_bcount_reg_t bcount;
+       int dma_ok = 0;
++      ide_handler_t *pkt_xfer_routine;
+ #if IDEFLOPPY_DEBUG_BUGS
+       if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+@@ -1048,10 +1158,15 @@
+               if (!test_bit (PC_ABORT, &pc->flags)) {
+                       if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
+                               ;
+-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+-                              drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
++                              printk(KERN_ERR "ide-floppy: %s: I/O error, "
++                                              "pc = %2x, key = %2x, "
++                                              "asc = %2x, ascq = %2x\n",
++                                              drive->name, pc->c[0],
++                                              floppy->sense_key,
++                                              floppy->asc, floppy->ascq);
+                       }
+-                      pc->error = IDEFLOPPY_ERROR_GENERAL;            /* Giving up */
++                      /* Giving up */
++                      pc->error = IDEFLOPPY_ERROR_GENERAL;
+               }
+               floppy->failed_pc=NULL;
+               pc->callback(drive);
+@@ -1062,7 +1177,7 @@
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+       pc->retries++;
+-      pc->actually_transferred=0;                                     /* We haven't transferred any data yet */
++      pc->actually_transferred=0;     /* We haven't transferred any data yet */
+       pc->current_position=pc->buffer;
+       bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+@@ -1075,26 +1190,35 @@
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+       if (IDE_CONTROL_REG)
+-              OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+-      OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);                        /* Use PIO/DMA */
+-      OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+-      OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+-      OUT_BYTE (drive->select.all,IDE_SELECT_REG);
++              OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
++      OUT_BYTE(dma_ok ? 1:0,IDE_FEATURE_REG);         /* Use PIO/DMA */
++      OUT_BYTE(bcount.b.high,IDE_BCOUNTH_REG);
++      OUT_BYTE(bcount.b.low,IDE_BCOUNTL_REG);
++      OUT_BYTE(drive->select.all,IDE_SELECT_REG);
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (dma_ok) {                                                   /* Begin DMA, if necessary */
++      if (dma_ok) {                           /* Begin DMA, if necessary */
+               set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+               (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+       }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
++      /* Can we transfer the packet when we get the interrupt or wait? */
++      if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
++              pkt_xfer_routine = &idefloppy_transfer_pc1;     /* wait */
++      } else {
++              pkt_xfer_routine = &idefloppy_transfer_pc;      /* immediate */
++      }
++      
+       if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+-              ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+-              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);              /* Issue the packet command */
++              if (HWGROUP(drive)->handler != NULL)
++                      BUG();
++              ide_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);               /* Issue the packet command */
+               return ide_started;
+       } else {
+-              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
+-              return idefloppy_transfer_pc (drive);
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
++              return (*pkt_xfer_routine) (drive);
+       }
+ }
+@@ -1104,7 +1228,7 @@
+       printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+-      idefloppy_end_request(1, HWGROUP(drive));
++      idefloppy_do_end_request(drive, 1);
+       return;
+ }
+@@ -1227,25 +1351,33 @@
+       idefloppy_pc_t *pc;
+ #if IDEFLOPPY_DEBUG_LOG
+-      printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+-      printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
++      printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
++              rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
++      printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
++                      "current_nr_sectors: %ld\n", rq->sector,
++                      rq->nr_sectors, rq->current_nr_sectors);
+ #endif /* IDEFLOPPY_DEBUG_LOG */
+       if (rq->errors >= ERROR_MAX) {
+               if (floppy->failed_pc != NULL)
+-                      printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+-                              drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
++                      printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
++                                      " key = %2x, asc = %2x, ascq = %2x\n",
++                              drive->name, floppy->failed_pc->c[0],
++                              floppy->sense_key, floppy->asc, floppy->ascq);
+               else
+-                      printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
+-              idefloppy_end_request (0, HWGROUP(drive));
++                      printk(KERN_ERR "ide-floppy: %s: I/O error\n",
++                              drive->name);
++              idefloppy_do_end_request(drive, 0);
+               return ide_stopped;
+       }
+       switch (rq->cmd) {
+               case READ:
+               case WRITE:
+-                      if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
+-                              printk ("%s: unsupported r/w request size\n", drive->name);
+-                              idefloppy_end_request (0, HWGROUP(drive));
++                      if (rq->sector % floppy->bs_factor ||
++                          rq->nr_sectors % floppy->bs_factor) {
++                              printk("%s: unsupported r/w request size\n",
++                                      drive->name);
++                              idefloppy_do_end_request(drive, 0);
+                               return ide_stopped;
+                       }
+                       pc = idefloppy_next_pc_storage (drive);
+@@ -1255,8 +1387,9 @@
+                       pc = (idefloppy_pc_t *) rq->buffer;
+                       break;
+               default:
+-                      printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
+-                      idefloppy_end_request (0,HWGROUP (drive));
++                      printk(KERN_ERR "ide-floppy: unsupported command %x"
++                              " in request queue\n", rq->cmd);
++                      idefloppy_do_end_request(drive, 0);
+                       return ide_stopped;
+       }
+       pc->rq = rq;
+@@ -1304,8 +1437,10 @@
+       page->rpm = ntohs (page->rpm);
+       capacity = page->cyls * page->heads * page->sectors * page->sector_size;
+       if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
+-              printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
+-                      drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
++              printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
++                              "%d sector size, %d rpm\n",
++                      drive->name, capacity / 1024, page->cyls,
++                      page->heads, page->sectors,
+                       page->transfer_rate / 8, page->sector_size, page->rpm);
+       floppy->flexible_disk_page = *page;
+@@ -1314,8 +1449,8 @@
+       drive->bios_sect = page->sectors;
+       lba_capacity = floppy->blocks * floppy->block_size;
+       if (capacity < lba_capacity) {
+-              printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
+-                      "but the drive only handles %d\n",
++              printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
++                      "bytes, but the drive only handles %d\n",
+                       drive->name, lba_capacity, capacity);
+               floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
+       }
+@@ -1410,8 +1545,7 @@
+       }
+       /* Clik! disk does not support get_flexible_disk_page */
+-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+-      {
++        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+               (void) idefloppy_get_flexible_disk_page (drive);
+       }
+@@ -1586,10 +1720,9 @@
+               idefloppy_status_reg_t status;
+               unsigned long flags;
+-              __save_flags(flags);
+-              __cli();
++              local_irq_save(flags);
+               status.all=GET_STAT();
+-              __restore_flags(flags);
++              local_irq_restore(flags);
+               progress_indication= !status.b.dsc ? 0:0x10000;
+       }
+@@ -1914,13 +2047,18 @@
+ {
+       int major = HWIF(drive)->major;
+       int minor = drive->select.b.unit << PARTN_BITS;
++      idefloppy_floppy_t *floppy = drive->driver_data;
++/*
++ *                    drive   setting name    read/write      ioctl   ioctl           data type       min     max     mul_factor      div_factor      data pointer            set function
++ */
+       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);
+       ide_add_setting(drive,  "file_readahead",       SETTING_RW,                                     BLKFRAGET,              BLKFRASET,              TYPE_INTA,      0,      INT_MAX,                        1,      1024,   &max_readahead[major][minor],   NULL);
+       ide_add_setting(drive,  "max_kb_per_request",   SETTING_RW,                                     BLKSECTGET,             BLKSECTSET,             TYPE_INTA,      1,      255,                            1,      2,      &max_sectors[major][minor],     NULL);
++      ide_add_setting(drive,  "ticks",                SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &floppy->ticks,         NULL);
+ }
+@@ -1954,27 +2092,19 @@
+       if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
+       {
++              set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
++              /* This value will be visible in the /proc/ide/hdx/settings */
++              floppy->ticks = IDEFLOPPY_TICKS_DELAY;
+               for (i = 0; i < 1 << PARTN_BITS; i++)
+                       max_sectors[major][minor + i] = 64;
+       }
+-  /*
+-   *      Guess what?  The IOMEGA Clik! drive also needs the
+-   *      above fix.  It makes nasty clicking noises without
+-   *      it, so please don't remove this.
+-   */
+-  if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0)
+-  {
+-    for (i = 0; i < 1 << PARTN_BITS; i++)
+-      max_sectors[major][minor + i] = 64;
+-    set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
+-  }
+       /*
+       *      Guess what?  The IOMEGA Clik! drive also needs the
+       *      above fix.  It makes nasty clicking noises without
+       *      it, so please don't remove this.
+       */
+-      if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) 
++      if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
+       {
+               for (i = 0; i < 1 << PARTN_BITS; i++)
+                       max_sectors[major][minor + i] = 64;
+@@ -2019,10 +2149,8 @@
+ #endif        /* CONFIG_PROC_FS */
+-static int idefloppy_reinit (ide_drive_t *drive)
+-{
+-      return 0;
+-}
++int idefloppy_init (void);
++int idefloppy_reinit(ide_drive_t *drive);
+ /*
+  *    IDE subdriver functions, registered with ide.c
+@@ -2032,11 +2160,21 @@
+       version:                IDEFLOPPY_VERSION,
+       media:                  ide_floppy,
+       busy:                   0,
++#ifdef CONFIG_IDEDMA_ONLYDISK
++      supports_dma:           0,
++#else
+       supports_dma:           1,
++#endif
+       supports_dsc_overlap:   0,
+       cleanup:                idefloppy_cleanup,
++      standby:                NULL,
++      suspend:                NULL,
++      resume:                 NULL,
++      flushcache:             NULL,
+       do_request:             idefloppy_do_request,
+-      end_request:            idefloppy_end_request,
++      end_request:            idefloppy_do_end_request,
++      sense:                  NULL,
++      error:                  NULL,
+       ioctl:                  idefloppy_ioctl,
+       open:                   idefloppy_open,
+       release:                idefloppy_release,
+@@ -2046,10 +2184,12 @@
+       capacity:               idefloppy_capacity,
+       special:                NULL,
+       proc:                   idefloppy_proc,
+-      driver_reinit:          idefloppy_reinit,
++      init:                   idefloppy_init,
++      reinit:                 idefloppy_reinit,
++      ata_prebuilder:         NULL,
++      atapi_prebuilder:       NULL,
+ };
+-int idefloppy_init (void);
+ static ide_module_t idefloppy_module = {
+       IDE_DRIVER_MODULE,
+       idefloppy_init,
+@@ -2057,6 +2197,40 @@
+       NULL
+ };
++int idefloppy_reinit (ide_drive_t *drive)
++{
++      idefloppy_floppy_t *floppy;
++      int failed = 0;
++
++      MOD_INC_USE_COUNT;
++      while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
++              if (!idefloppy_identify_device (drive, drive->id)) {
++                      printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
++                      continue;
++              }
++              if (drive->scsi) {
++                      printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
++                      continue;
++              }
++              if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
++                      printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
++                      continue;
++              }
++              if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
++                      printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
++                      kfree (floppy);
++                      continue;
++              }
++              DRIVER(drive)->busy++;
++              idefloppy_setup (drive, floppy);
++              DRIVER(drive)->busy--;
++              failed--;
++      }
++      ide_register_module(&idefloppy_module);
++      MOD_DEC_USE_COUNT;
++      return 0;
++}
++
+ MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
+ static void __exit idefloppy_exit (void)
+@@ -2108,7 +2282,9 @@
+                       kfree (floppy);
+                       continue;
+               }
++              DRIVER(drive)->busy++;
+               idefloppy_setup (drive, floppy);
++              DRIVER(drive)->busy--;
+               failed--;
+       }
+       ide_register_module(&idefloppy_module);
+diff -Nur linux.org/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c
+--- linux.org/drivers/ide/ide-geometry.c       Fri Nov  9 23:23:34 2001
++++ linux/drivers/ide/ide-geometry.c   Thu Jul 18 14:23:00 2002
+@@ -6,6 +6,8 @@
+ #include <linux/mc146818rtc.h>
+ #include <asm/io.h>
++#ifdef CONFIG_BLK_DEV_IDE
++
+ /*
+  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
+  * controller that is BIOS compatible with ST-506, and thus showing up in our
+@@ -40,7 +42,11 @@
+  * Consequently, also the former "drive->present = 1" below was a mistake.
+  *
+  * Eventually the entire routine below should be removed.
++ *
++ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
++ * chip.
+  */
++
+ void probe_cmos_for_drives (ide_hwif_t *hwif)
+ {
+ #ifdef __i386__
+@@ -80,9 +86,10 @@
+       }
+ #endif
+ }
++#endif /* CONFIG_BLK_DEV_IDE */
+-#ifdef CONFIG_BLK_DEV_IDE
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ extern ide_drive_t * get_info_ptr(kdev_t);
+ extern unsigned long current_capacity (ide_drive_t *);
+@@ -214,4 +221,4 @@
+                      drive->bios_cyl, drive->bios_head, drive->bios_sect);
+       return ret;
+ }
+-#endif /* CONFIG_BLK_DEV_IDE */
++#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+diff -Nur linux.org/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
+--- linux.org/drivers/ide/ide-pci.c    Thu Oct 25 22:53:47 2001
++++ linux/drivers/ide/ide-pci.c        Thu Jul 18 14:24:33 2002
+@@ -12,6 +12,13 @@
+  *  configuration of all PCI IDE interfaces present in a system.  
+  */
++/*
++ * Chipsets that are on the IDE_IGNORE list because of problems of not being
++ * set at compile time.
++ *
++ * CONFIG_BLK_DEV_PDC202XX
++ */
++
+ #include <linux/config.h>
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+@@ -38,15 +45,24 @@
+ #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_PIIX4U6 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
++#define DEVID_PIIX4U7 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
++#define DEVID_PIIX4U8   ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
+ #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
+ #define DEVID_MR_IDE  ((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
+ #define DEVID_VP_IDE  ((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
+ #define DEVID_PDC20246        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+ #define DEVID_PDC20262        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
++#define DEVID_PDC20263        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263})
+ #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_PDC20270 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270})
++#define DEVID_PDC20269        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
++#define DEVID_PDC20271        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271})
++#define DEVID_PDC20275        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
++#define DEVID_PDC20276        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
++#define DEVID_PDC20277        ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277})
+ #define DEVID_RZ1000  ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
+ #define DEVID_RZ1001  ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
+ #define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
+@@ -55,6 +71,7 @@
+ #define DEVID_CMD646  ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
+ #define DEVID_CMD648  ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
+ #define DEVID_CMD649  ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
++#define DEVID_CMD680  ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
+ #define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
+ #define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
+ #define DEVID_OPTI621V        ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
+@@ -66,12 +83,18 @@
+ #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_AEC6280 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865})
++#define DEVID_AEC6880 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865R})
+ #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
+ #define DEVID_UM8673F ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
+ #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
+ #define DEVID_UM8886BF        ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
+ #define DEVID_HPT34X  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+ #define DEVID_HPT366  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
++#define DEVID_HPT372  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT372})
++#define DEVID_HPT302  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT302})
++#define DEVID_HPT371  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT371}) 
++#define DEVID_HPT374  ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT374})
+ #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})
+@@ -79,59 +102,71 @@
+ #define DEVID_AMD7401 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
+ #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
+ #define DEVID_AMD7411 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
++#define DEVID_AMD7441 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
+ #define DEVID_PDCADMA ((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
+ #define DEVID_SLC90E66        ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
+ #define DEVID_OSB4    ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
+ #define DEVID_CSB5    ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
++#define DEVID_CSB6    ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE})
+ #define DEVID_ITE8172G        ((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
+ #define       IDE_IGNORE      ((void *)-1)
++#define IDE_NO_DRIVER ((void *)-2)
+ #ifdef CONFIG_BLK_DEV_AEC62XX
++extern void fixup_device_aec6x80(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_AEC62XX &fixup_device_aec6x80
+ #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 FIXUP_AEC62XX NULL
+ #define PCI_AEC62XX   NULL
+ #define ATA66_AEC62XX NULL
+-#define INIT_AEC62XX  NULL
++#define INIT_AEC62XX  IDE_NO_DRIVER
+ #define DMA_AEC62XX   NULL
+ #endif
+ #ifdef CONFIG_BLK_DEV_ALI15X3
++extern void fixup_device_ali15x3(struct pci_dev *, ide_pci_device_t *);
+ extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+ extern unsigned int ata66_ali15x3(ide_hwif_t *);
+ extern void ide_init_ali15x3(ide_hwif_t *);
+ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
++#define FIXUP_ALI15X3 &fixup_device_ali15x3
+ #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 FIXUP_ALI15X3 NULL
+ #define PCI_ALI15X3   NULL
+ #define ATA66_ALI15X3 NULL
+-#define INIT_ALI15X3  NULL
++#define INIT_ALI15X3  IDE_NO_DRIVER
+ #define DMA_ALI15X3   NULL
+ #endif
+ #ifdef CONFIG_BLK_DEV_AMD74XX
++extern void fixup_device_amd74xx(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_AMD74XX &fixup_device_amd74xx
+ #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 FIXUP_AMD74XX NULL
+ #define PCI_AMD74XX   NULL
+ #define ATA66_AMD74XX NULL
+-#define INIT_AMD74XX  NULL
++#define INIT_AMD74XX  IDE_NO_DRIVER
+ #define DMA_AMD74XX   NULL
+ #endif
+@@ -149,18 +184,21 @@
+ #ifdef __sparc_v9__
+ #define INIT_CMD64X   IDE_IGNORE
+ #else
+-#define INIT_CMD64X   NULL
++#define INIT_CMD64X   IDE_NO_DRIVER
+ #endif
+ #endif
+ #ifdef CONFIG_BLK_DEV_CY82C693
++extern void fixup_device_cy82c693(struct pci_dev *, ide_pci_device_t *);
+ extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
+ extern void ide_init_cy82c693(ide_hwif_t *);
++#define FIXUP_CY82C693        &fixup_device_cy82c693
+ #define PCI_CY82C693  &pci_init_cy82c693
+ #define INIT_CY82C693 &ide_init_cy82c693
+ #else
++#define FIXUP_CY82C693        NULL
+ #define PCI_CY82C693  NULL
+-#define INIT_CY82C693 NULL
++#define INIT_CY82C693 IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_CS5530
+@@ -170,36 +208,41 @@
+ #define INIT_CS5530   &ide_init_cs5530
+ #else
+ #define PCI_CS5530    NULL
+-#define INIT_CS5530   NULL
++#define INIT_CS5530   IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_HPT34X
++extern void fixup_device_hpt343(struct pci_dev *, ide_pci_device_t *);
+ extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
+ extern void ide_init_hpt34x(ide_hwif_t *);
++#define FIXUP_HPT34X  &fixup_device_hpt343
+ #define PCI_HPT34X    &pci_init_hpt34x
+ #define INIT_HPT34X   &ide_init_hpt34x
+ #else
++#define FIXUP_HPT34X  NULL
+ #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 void fixup_device_hpt366(struct pci_dev *, ide_pci_device_t *);
++extern void fixup_device_hpt374(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_HPT366  &fixup_device_hpt366
++#define FIXUP_HPT374  &fixup_device_hpt374
+ #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 FIXUP_HPT366  NULL
++#define FIXUP_HPT374  NULL
+ #define PCI_HPT366    NULL
+ #define ATA66_HPT366  NULL
+-#define INIT_HPT366   NULL
++#define INIT_HPT366   IDE_NO_DRIVER
+ #define DMA_HPT366    NULL
+ #endif
+@@ -211,10 +254,13 @@
+ #endif
+ #ifdef CONFIG_BLK_DEV_OPTI621
++extern void fixup_device_opti621(struct pci_dev *, ide_pci_device_t *);
+ extern void ide_init_opti621(ide_hwif_t *);
++#define FIXUP_OPTI621 &fixup_device_opti621
+ #define INIT_OPTI621  &ide_init_opti621
+ #else
+-#define INIT_OPTI621  NULL
++#define FIXUP_OPTI621 NULL
++#define INIT_OPTI621  IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_PDC_ADMA
+@@ -234,41 +280,54 @@
+ #endif
+ #ifdef CONFIG_BLK_DEV_PDC202XX
++extern void fixup_device_pdc20265(struct pci_dev *, ide_pci_device_t *);
++extern void fixup_device_pdc20270(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_PDC20265        &fixup_device_pdc20265
++#define FIXUP_PDC20270        &fixup_device_pdc20270
+ #define PCI_PDC202XX  &pci_init_pdc202xx
+ #define ATA66_PDC202XX        &ata66_pdc202xx
+ #define INIT_PDC202XX &ide_init_pdc202xx
+ #else
+-#define PCI_PDC202XX  NULL
+-#define ATA66_PDC202XX        NULL
+-#define INIT_PDC202XX NULL
++#define FIXUP_PDC20265        IDE_IGNORE
++#define FIXUP_PDC20270        IDE_IGNORE
++#define PCI_PDC202XX  IDE_IGNORE
++#define ATA66_PDC202XX        IDE_IGNORE
++#define INIT_PDC202XX IDE_IGNORE
+ #endif
+ #ifdef CONFIG_BLK_DEV_PIIX
++extern void fixup_device_piix(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_PIIX    &fixup_device_piix
+ #define PCI_PIIX      &pci_init_piix
+ #define ATA66_PIIX    &ata66_piix
+ #define INIT_PIIX     &ide_init_piix
+ #else
++#define FIXUP_PIIX    NULL
+ #define PCI_PIIX      NULL
+ #define ATA66_PIIX    NULL
+-#define INIT_PIIX     NULL
++#define INIT_PIIX     IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_IT8172
++extern void fixup_device_it8172(struct pci_dev *, ide_pci_device_t *);
+ extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
+ extern unsigned int ata66_it8172(ide_hwif_t *);
+ extern void ide_init_it8172(ide_hwif_t *);
++#define FIXUP_IT8172  &fixup_device_it8172
+ #define PCI_IT8172    &pci_init_it8172
++#define ATA66_IT8172  &ata66_it8172
+ #define INIT_IT8172   &ide_init_it8172
+ #else
++#define FIXUP_IT8172  NULL
+ #define PCI_IT8172    NULL
+ #define ATA66_IT8172  NULL
+-#define INIT_IT8172   NULL
++#define INIT_IT8172   IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_RZ1000
+@@ -281,29 +340,38 @@
+ #define INIT_SAMURAI  NULL
+ #ifdef CONFIG_BLK_DEV_SVWKS
++extern void fixup_device_csb6(struct pci_dev *, ide_pci_device_t *);
+ 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 *);
++extern void ide_dmacapable_svwks(ide_hwif_t *, unsigned long);
++#define FIXUP_CSB6    &fixup_device_csb6
+ #define PCI_SVWKS     &pci_init_svwks
+ #define ATA66_SVWKS   &ata66_svwks
+ #define INIT_SVWKS    &ide_init_svwks
++#define DMA_SVWKS     &ide_dmacapable_svwks
+ #else
++#define FIXUP_CSB6    NULL
+ #define PCI_SVWKS     NULL
+ #define ATA66_SVWKS   NULL
+-#define INIT_SVWKS    NULL
++#define INIT_SVWKS    IDE_NO_DRIVER
++#define DMA_SVWKS     NULL
+ #endif
+ #ifdef CONFIG_BLK_DEV_SIS5513
++extern void fixup_device_sis5513(struct pci_dev *, ide_pci_device_t *);
+ 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 FIXUP_SIS5513 &fixup_device_sis5513
+ #define PCI_SIS5513   &pci_init_sis5513
+ #define ATA66_SIS5513 &ata66_sis5513
+ #define INIT_SIS5513  &ide_init_sis5513
+ #else
++#define FIXUP_SIS5513 NULL
+ #define PCI_SIS5513   NULL
+ #define ATA66_SIS5513 NULL
+-#define INIT_SIS5513  NULL
++#define INIT_SIS5513  IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_SLC90E66
+@@ -316,7 +384,7 @@
+ #else
+ #define PCI_SLC90E66  NULL
+ #define ATA66_SLC90E66        NULL
+-#define INIT_SLC90E66 NULL
++#define INIT_SLC90E66 IDE_NO_DRIVER
+ #endif
+ #ifdef CONFIG_BLK_DEV_SL82C105
+@@ -351,98 +419,102 @@
+ #else
+ #define PCI_VIA82CXXX NULL
+ #define ATA66_VIA82CXXX       NULL
+-#define INIT_VIA82CXXX        NULL
++#define INIT_VIA82CXXX        IDE_NO_DRIVER
+ #define DMA_VIA82CXXX NULL
+ #endif
+-typedef struct ide_pci_enablebit_s {
+-      byte    reg;    /* byte pci reg holding the enable-bit */
+-      byte    mask;   /* mask to isolate the enable-bit */
+-      byte    val;    /* value of masked reg when "enabled" */
+-} ide_pci_enablebit_t;
+-
+-typedef struct ide_pci_device_s {
+-      ide_pci_devid_t         devid;
+-      char                    *name;
+-      unsigned int            (*init_chipset)(struct pci_dev *dev, const char *name);
+-      unsigned int            (*ata66_check)(ide_hwif_t *hwif);
+-      void                    (*init_hwif)(ide_hwif_t *hwif);
+-      void                    (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
+-      ide_pci_enablebit_t     enablebits[2];
+-      byte                    bootable;
+-      unsigned int            extra;
+-} ide_pci_device_t;
+-
+ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
+-      {DEVID_PIIXa,   "PIIX",         NULL,           NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIXb,   "PIIX",         NULL,           NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_MPIIX,   "MPIIX",        NULL,           NULL,           INIT_PIIX,      NULL,           {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX3,   "PIIX3",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4,   "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4E,  "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4E2, "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4U,  "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4U2, "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4NX, "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4U3, "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4U4, "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_PIIX4U5, "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_VIA_IDE, "VIA_IDE",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_MR_IDE,  "VP_IDE",       PCI_VIA82CXXX,  ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX,  {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
+-      {DEVID_VP_IDE,  "VP_IDE",       PCI_VIA82CXXX,  ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX,  {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
++      {DEVID_PIIXa,   "PIIX",         FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIXb,   "PIIX",         FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_MPIIX,   "MPIIX",        FIXUP_PIIX,     NULL,           NULL,           INIT_PIIX,      NULL,           {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX3,   "PIIX3",        FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4,   "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4E,  "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4E2, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U,  "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U2, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4NX, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U3, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U4, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U5, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U6, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U7, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_PIIX4U8, "PIIX4",        FIXUP_PIIX,     PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_VIA_IDE, "VIA_IDE",      NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_MR_IDE,  "VP_IDE",       NULL,           PCI_VIA82CXXX,  ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX,  {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
++      {DEVID_VP_IDE,  "VP_IDE",       NULL,           PCI_VIA82CXXX,  ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX,  {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
+ #ifdef CONFIG_PDC202XX_FORCE
+-        {DEVID_PDC20246,"PDC20246",   PCI_PDC202XX,   NULL,           INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      16 },
+-        {DEVID_PDC20262,"PDC20262",   PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
+-        {DEVID_PDC20265,"PDC20265",   PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
+-        {DEVID_PDC20267,"PDC20267",   PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
++      {DEVID_PDC20246,"PDC20246",     NULL,           PCI_PDC202XX,   NULL,           INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      16 },
++      {DEVID_PDC20262,"PDC20262",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
++      {DEVID_PDC20263,"PDC20263",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
++      {DEVID_PDC20265,"PDC20265",     FIXUP_PDC20265, PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       48 },
++      {DEVID_PDC20267,"PDC20267",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      48 },
+ #else /* !CONFIG_PDC202XX_FORCE */
+-      {DEVID_PDC20246,"PDC20246",     PCI_PDC202XX,   NULL,           INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      16 },
+-      {DEVID_PDC20262,"PDC20262",     PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
+-      {DEVID_PDC20265,"PDC20265",     PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
+-      {DEVID_PDC20267,"PDC20267",     PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
+-#endif
+-      {DEVID_PDC20268,"PDC20268",     PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      16 },
+-      /* Promise used a different PCI ident for the raid card apparently to try and
+-         prevent Linux detecting it and using our own raid code. We want to detect
+-         it for the ataraid drivers, so we have to list both here.. */
+-      {DEVID_PDC20268R,"PDC20268",    PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      16 },
+-      {DEVID_RZ1000,  "RZ1000",       NULL,           NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_RZ1001,  "RZ1001",       NULL,           NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_SAMURAI, "SAMURAI",      NULL,           NULL,           INIT_SAMURAI,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CMD640,  "CMD640",       NULL,           NULL,           IDE_IGNORE,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_NS87410, "NS87410",      NULL,           NULL,           NULL,           NULL,           {{0x43,0x08,0x08}, {0x47,0x08,0x08}},   ON_BOARD,       0 },
+-      {DEVID_SIS5513, "SIS5513",      PCI_SIS5513,    ATA66_SIS5513,  INIT_SIS5513,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   ON_BOARD,       0 },
+-      {DEVID_CMD643,  "CMD643",       PCI_CMD64X,     NULL,           INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CMD646,  "CMD646",       PCI_CMD64X,     NULL,           INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x51,0x80,0x80}},   ON_BOARD,       0 },
+-      {DEVID_CMD648,  "CMD648",       PCI_CMD64X,     ATA66_CMD64X,   INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CMD649,  "CMD649",       PCI_CMD64X,     ATA66_CMD64X,   INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_HT6565,  "HT6565",       NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_OPTI621, "OPTI621",      NULL,           NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
+-      {DEVID_OPTI621X,"OPTI621X",     NULL,           NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
+-      {DEVID_TRM290,  "TRM290",       NULL,           NULL,           INIT_TRM290,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_NS87415, "NS87415",      NULL,           NULL,           INIT_NS87415,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_AEC6210, "AEC6210",      PCI_AEC62XX,    NULL,           INIT_AEC62XX,   DMA_AEC62XX,    {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
+-      {DEVID_AEC6260, "AEC6260",      PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    0 },
+-      {DEVID_AEC6260R,"AEC6260R",     PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
+-      {DEVID_W82C105, "W82C105",      PCI_W82C105,    NULL,           INIT_W82C105,   DMA_W82C105,    {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
+-      {DEVID_UM8673F, "UM8673F",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_UM8886A, "UM8886A",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_UM8886BF,"UM8886BF",     NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_HPT34X,  "HPT34X",       PCI_HPT34X,     NULL,           INIT_HPT34X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
+-      {DEVID_HPT366,  "HPT366",       PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      240 },
+-      {DEVID_ALI15X3, "ALI15X3",      PCI_ALI15X3,    ATA66_ALI15X3,  INIT_ALI15X3,   DMA_ALI15X3,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CY82C693,"CY82C693",     PCI_CY82C693,   NULL,           INIT_CY82C693,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_HINT,    "HINT_IDE",     NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CS5530,  "CS5530",       PCI_CS5530,     NULL,           INIT_CS5530,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_AMD7401, "AMD7401",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_AMD7409, "AMD7409",      PCI_AMD74XX,    ATA66_AMD74XX,  INIT_AMD74XX,   DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
+-      {DEVID_AMD7411, "AMD7411",      PCI_AMD74XX,    ATA66_AMD74XX,  INIT_AMD74XX,   DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
+-      {DEVID_PDCADMA, "PDCADMA",      PCI_PDCADMA,    ATA66_PDCADMA,  INIT_PDCADMA,   DMA_PDCADMA,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
+-      {DEVID_SLC90E66,"SLC90E66",     PCI_SLC90E66,   ATA66_SLC90E66, INIT_SLC90E66,  NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+-        {DEVID_OSB4,    "ServerWorks OSB4",           PCI_SVWKS,      ATA66_SVWKS,    INIT_SVWKS,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_CSB5,    "ServerWorks CSB5",             PCI_SVWKS,      ATA66_SVWKS,    INIT_SVWKS,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+-      {DEVID_ITE8172G,"IT8172G",      PCI_IT8172,     NULL,   INIT_IT8172,    NULL,           {{0x00,0x00,0x00}, {0x40,0x00,0x01}},   ON_BOARD,       0 },
+-      {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 }};
++      {DEVID_PDC20246,"PDC20246",     NULL,           PCI_PDC202XX,   NULL,           INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      16 },
++      {DEVID_PDC20262,"PDC20262",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
++      {DEVID_PDC20263,"PDC20263",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
++      {DEVID_PDC20265,"PDC20265",     FIXUP_PDC20265, PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
++      {DEVID_PDC20267,"PDC20267",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
++#endif
++      {DEVID_PDC20268,"PDC20268",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      /*
++       * Promise used a different PCI ident for the raid card apparently
++       * to try and prevent Linux detecting it and using our own raid code.
++       * We want to detect it for the ataraid drivers, so we have to list
++       * both here..
++       */
++      {DEVID_PDC20270,"PDC20270",     FIXUP_PDC20270, PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_PDC20269,"PDC20269",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX,  INIT_PDC202XX, NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_PDC20271,"PDC20271",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_PDC20275,"PDC20275",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_PDC20276,"PDC20276",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_PDC20277,"PDC20277",     NULL,           PCI_PDC202XX,   ATA66_PDC202XX, INIT_PDC202XX,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_RZ1000,  "RZ1000",       NULL,           NULL,           NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_RZ1001,  "RZ1001",       NULL,           NULL,           NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_SAMURAI, "SAMURAI",      NULL,           NULL,           NULL,           INIT_SAMURAI,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CMD640,  "CMD640",       NULL,           NULL,           NULL,           IDE_IGNORE,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_NS87410, "NS87410",      NULL,           NULL,           NULL,           NULL,           NULL,           {{0x43,0x08,0x08}, {0x47,0x08,0x08}},   ON_BOARD,       0 },
++      {DEVID_SIS5513, "SIS5513",      FIXUP_SIS5513,  PCI_SIS5513,    ATA66_SIS5513,  INIT_SIS5513,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   ON_BOARD,       0 },
++      {DEVID_CMD643,  "CMD643",       NULL,           PCI_CMD64X,     NULL,           INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CMD646,  "CMD646",       NULL,           PCI_CMD64X,     NULL,           INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x51,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_CMD648,  "CMD648",       NULL,           PCI_CMD64X,     ATA66_CMD64X,   INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CMD649,  "CMD649",       NULL,           PCI_CMD64X,     ATA66_CMD64X,   INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CMD680,  "CMD680",       NULL,           PCI_CMD64X,     ATA66_CMD64X,   INIT_CMD64X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_HT6565,  "HT6565",       NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_OPTI621, "OPTI621",      FIXUP_OPTI621,  NULL,           NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
++      {DEVID_OPTI621X,"OPTI621X",     FIXUP_OPTI621,  NULL,           NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
++      {DEVID_TRM290,  "TRM290",       NULL,           NULL,           NULL,           INIT_TRM290,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_NS87415, "NS87415",      NULL,           NULL,           NULL,           INIT_NS87415,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_AEC6210, "AEC6210",      NULL,           PCI_AEC62XX,    NULL,           INIT_AEC62XX,   DMA_AEC62XX,    {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
++      {DEVID_AEC6260, "AEC6260",      NULL,           PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    0 },
++      {DEVID_AEC6260R,"AEC6260R",     NULL,           PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
++      {DEVID_AEC6280, "AEC6X80",      FIXUP_AEC62XX,  PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    0 },
++      {DEVID_AEC6880, "AEC6X80R",     FIXUP_AEC62XX,  PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
++      {DEVID_W82C105, "W82C105",      NULL,           PCI_W82C105,    NULL,           INIT_W82C105,   DMA_W82C105,    {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
++      {DEVID_UM8673F, "UM8673F",      NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_UM8886A, "UM8886A",      NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_UM8886BF,"UM8886BF",     NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_HPT34X,  "HPT34X",       FIXUP_HPT34X,   PCI_HPT34X,     NULL,           INIT_HPT34X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
++      {DEVID_HPT366,  "HPT366",       FIXUP_HPT366,   PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      240 },
++      {DEVID_HPT372,  "HPT372A",      NULL,           PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_HPT302,  "HPT302",       NULL,           PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_HPT371,  "HPT371",       NULL,           PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_HPT374,  "HPT374",       FIXUP_HPT374,   PCI_HPT366,     ATA66_HPT366,   INIT_HPT366,    DMA_HPT366,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_ALI15X3, "ALI15X3",      FIXUP_ALI15X3,  PCI_ALI15X3,    ATA66_ALI15X3,  INIT_ALI15X3,   DMA_ALI15X3,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CY82C693,"CY82C693",     FIXUP_CY82C693, PCI_CY82C693,   NULL,           INIT_CY82C693,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_HINT,    "HINT_IDE",     NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CS5530,  "CS5530",       NULL,           PCI_CS5530,     NULL,           INIT_CS5530,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_AMD7401, "AMD7401",      FIXUP_AMD74XX,  NULL,           NULL,           NULL,           DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
++      {DEVID_AMD7409, "AMD7409",      FIXUP_AMD74XX,  PCI_AMD74XX,    ATA66_AMD74XX,  INIT_AMD74XX,   DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
++      {DEVID_AMD7411, "AMD7411",      FIXUP_AMD74XX,  PCI_AMD74XX,    ATA66_AMD74XX,  INIT_AMD74XX,   DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
++      {DEVID_AMD7441, "AMD7441",      FIXUP_AMD74XX,  PCI_AMD74XX,    ATA66_AMD74XX,  INIT_AMD74XX,   DMA_AMD74XX,    {{0x40,0x01,0x01}, {0x40,0x02,0x02}},   ON_BOARD,       0 },
++      {DEVID_PDCADMA, "PDCADMA",      NULL,           PCI_PDCADMA,    ATA66_PDCADMA,  INIT_PDCADMA,   DMA_PDCADMA,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
++      {DEVID_SLC90E66,"SLC90E66",     NULL,           PCI_SLC90E66,   ATA66_SLC90E66, INIT_SLC90E66,  NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
++      {DEVID_OSB4,    "SvrWks OSB4",  NULL,           PCI_SVWKS,      ATA66_SVWKS,    INIT_SVWKS,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CSB5,    "SvrWks CSB5",  NULL,           PCI_SVWKS,      ATA66_SVWKS,    INIT_SVWKS,     DMA_SVWKS,      {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_CSB6,    "SvrWks CSB6",  FIXUP_CSB6,     PCI_SVWKS,      ATA66_SVWKS,    INIT_SVWKS,     DMA_SVWKS,      {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
++      {DEVID_ITE8172G,"IT8172G",      FIXUP_IT8172,   PCI_IT8172,     NULL,           INIT_IT8172,    NULL,           {{0x00,0x00,0x00}, {0x40,0x00,0x01}},   ON_BOARD,       0 },
++      {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 }};
+ /*
+  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
+@@ -453,14 +525,33 @@
+ {
+       switch(dev->device) {
+               case PCI_DEVICE_ID_TTI_HPT366:
++              case PCI_DEVICE_ID_TTI_HPT372:
++              case PCI_DEVICE_ID_TTI_HPT302:
++              case PCI_DEVICE_ID_TTI_HPT371:
++              case PCI_DEVICE_ID_TTI_HPT374:
+               case PCI_DEVICE_ID_PROMISE_20246:
+               case PCI_DEVICE_ID_PROMISE_20262:
++              case PCI_DEVICE_ID_PROMISE_20263:
+               case PCI_DEVICE_ID_PROMISE_20265:
+               case PCI_DEVICE_ID_PROMISE_20267:
+               case PCI_DEVICE_ID_PROMISE_20268:
+-              case PCI_DEVICE_ID_ARTOP_ATP850UF:
+-              case PCI_DEVICE_ID_ARTOP_ATP860:
+-              case PCI_DEVICE_ID_ARTOP_ATP860R:
++              case PCI_DEVICE_ID_PROMISE_20270:
++              case PCI_DEVICE_ID_PROMISE_20269:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20277:
++      /*
++       *      case PCI_DEVICE_ID_ARTOP_ATP850UF:
++       *              same device ID value as PCI_DEVICE_ID_TTI_HPT372
++       *      case PCI_DEVICE_ID_ARTOP_ATP860:
++       *              same device ID value as PCI_DEVICE_ID_TTI_HPT302
++       *      case PCI_DEVICE_ID_ARTOP_ATP860R:
++       *              same device ID value as PCI_DEVICE_ID_TTI_HPT371
++       *      case PCI_DEVICE_ID_ARTOP_ATP865:
++       *              same device ID value as PCI_DEVICE_ID_TTI_HPT374
++       */
++              case PCI_DEVICE_ID_ARTOP_ATP865R:
+                       return dev->irq;
+               default:
+                       break;
+@@ -498,7 +589,8 @@
+               if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+                       if (hwif->chipset == ide_unknown)
+                               return hwif; /* match */
+-                      printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name);
++                      printk("%s: port 0x%04lx already claimed by %s\n",
++                              name, io_base, hwif->name);
+                       return NULL;    /* already claimed */
+               }
+       }
+@@ -541,9 +633,11 @@
+       /*
+        * Place both IDE interfaces into PCI "native" mode:
+        */
+-      if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
++      if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
++                       (progif & 5) != 5) {
+               if ((progif & 0xa) != 0xa) {
+-                      printk("%s: device not capable of full native PCI mode\n", name);
++                      printk("%s: device not capable of full "
++                              "native PCI mode\n", name);
+                       return 1;
+               }
+               printk("%s: placing both ports into native PCI mode\n", name);
+@@ -578,7 +672,7 @@
+  * we "know" about, this information is in the ide_pci_device_t struct;
+  * for all other chipsets, we just assume both interfaces are enabled.
+  */
+-static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
++void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+ {
+       unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
+       unsigned short pcicmd = 0, tried_config = 0;
+@@ -592,7 +686,17 @@
+               autodma = 1;
+ #endif
+-      pci_enable_device(dev);
++      if (d->init_hwif == IDE_NO_DRIVER) {
++              printk(KERN_WARNING "%s: detected chipset, "
++                      "but driver not compiled in!\n", d->name);
++              d->init_hwif = NULL;
++      }
++
++      if (pci_enable_device(dev)) {
++              printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
++                      "Could not enable device.\n", d->name);
++              return;
++      }
+ check_if_enabled:
+       if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+@@ -621,14 +725,6 @@
+       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);
+       /*
+@@ -642,13 +738,12 @@
+                  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))
++              if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276))
+               {
+-                      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)
++                              (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960 || dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))
+                       {
+-                              printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
++                              printk(KERN_INFO "ide: Skipping Promise IDE controller attached to I2O RAID controller.\n");
+                               return;
+                       }
+               }
+@@ -656,7 +751,8 @@
+                  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);
++              printk("%s: not 100%% native mode: "
++                      "will probe irqs later\n", d->name);
+               /*
+                * This allows offboard ide-pci cards the enable a BIOS,
+                * verify interrupt settings of split-mirror pci-config
+@@ -689,34 +785,52 @@
+               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. 
++               * 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)  ) 
++              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)  ) 
++              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))
++              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))
++              if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) &&
++                  (port) && (class_rev < 0x03))
++                      return;
++              if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) && (port))
++                      return;
++              if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
++                  (port) && (!(PCI_FUNC(dev->devfn) & 1)))
+                       return;
+-              if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
++              if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE ||
++                  (dev->class & (port ? 4 : 1)) != 0) {
+                       ctl  = dev->resource[(2*port)+1].start;
+                       base = dev->resource[2*port].start;
+                       if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
+                           !(base & PCI_BASE_ADDRESS_IO_MASK)) {
+-                              printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@linux-ide.org>.\n", d->name);
++                              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! */
++                              /*
++                               * 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);
++                      printk("%s: inconsistent baseregs (BIOS) "
++                              "for port %d, skipping\n", d->name, port);
+                       continue;
+               }
+               if (!ctl)
+@@ -752,9 +866,11 @@
+               }
+               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
+                       goto bypass_piix_dma;
+-
++              if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
++                      goto bypass_legacy_dma;
+               if (hwif->udma_four) {
+-                      printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
++                      printk("%s: ATA-66/100 forced bit set (WARNING)!!\n",
++                              d->name);
+               } else {
+                       hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
+               }
+@@ -769,22 +885,36 @@
+                       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_PDC20263) ||
+                   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_PDC20270) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20271) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20277) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6880) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT372) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT374) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
++                  IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
+                   ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
+                       unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
+@@ -811,6 +941,7 @@
+                       }
+               }
+ #endif        /* CONFIG_BLK_DEV_IDEDMA */
++bypass_legacy_dma:
+ bypass_piix_dma:
+ bypass_umc_dma:
+               if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
+@@ -822,62 +953,6 @@
+               printk("%s: neither IDE port enabled (BIOS)\n", d->name);
+ }
+-static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
+-{
+-      struct pci_dev *dev2 = NULL, *findev;
+-      ide_pci_device_t *d2;
+-      unsigned char pin1 = 0, pin2 = 0;
+-      unsigned int class_rev;
+-      char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
+-
+-      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);
+-      pci_for_each_dev(findev) {
+-              if ((findev->vendor == dev->vendor) &&
+-                  (findev->device == dev->device) &&
+-                  ((findev->devfn - dev->devfn) == 1) &&
+-                  (PCI_FUNC(findev->devfn) & 1)) {
+-                      dev2 = findev;
+-                      pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+-                      hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
+-                      hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
+-                      if (hpt363_shared_pin && hpt363_shared_irq) {
+-                              d->bootable = ON_BOARD;
+-                              printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
+-#if 0
+-                              /* I forgot why I did this once, but it fixed something. */
+-                              pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
+-                              printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
+-                              pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
+-#endif
+-                      }
+-                      break;
+-              }
+-      }
+-      printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+-      ide_setup_pci_device(dev, d);
+-      if (!dev2)
+-              return;
+-      d2 = d;
+-      printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+-      ide_setup_pci_device(dev2, d2);
+-}
+-
+ /*
+  * ide_scan_pcibus() gets invoked at boot time from ide.c.
+  * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
+@@ -889,25 +964,32 @@
+       devid.vid = dev->vendor;
+       devid.did = dev->device;
+-      for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
++      for (d = ide_pci_chipsets;
++           d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
++
+       if (d->init_hwif == IDE_IGNORE)
+-              printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
+-      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
++              printk("%s: ignored by ide_scan_pci_device() "
++                      "(uses own driver)\n", d->name);
++      else if (d->fixup_device)
++              d->fixup_device(dev, d);
++#if 0
++      else if (((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) &&
++               (!(PCI_FUNC(dev->devfn) & 1)))
+               return;
+-      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+-              return; /* CY82C693 is more than only a IDE controller */
+-      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+-              return; /* IT8172G is also more than only an IDE controller */
+-      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
++#endif
++      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) &&
++               (!(PCI_FUNC(dev->devfn) & 1)))
+               return; /* UM8886A/BF pair */
+-      else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
+-              hpt366_device_order_fixup(dev, d);
+-      else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
++      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);
++                      printk("%s: unknown IDE controller on PCI bus "
++                              "%02x device %02x, VID=%04x, DID=%04x\n",
++                              d->name, dev->bus->number, dev->devfn,
++                              devid.vid, devid.did);
+               else
+-                      printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
++                      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 -Nur linux.org/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
+--- linux.org/drivers/ide/ide-pmac.c   Mon Feb 25 20:37:57 2002
++++ linux/drivers/ide/ide-pmac.c       Thu Jul 18 14:24:33 2002
+@@ -26,11 +26,14 @@
+ #include <linux/ide.h>
+ #include <linux/notifier.h>
+ #include <linux/reboot.h>
++#include <linux/pci.h>
++
+ #include <asm/prom.h>
+ #include <asm/io.h>
+ #include <asm/dbdma.h>
+ #include <asm/ide.h>
+ #include <asm/mediabay.h>
++#include <asm/pci-bridge.h>
+ #include <asm/machdep.h>
+ #include <asm/pmac_feature.h>
+ #include <asm/sections.h>
+@@ -41,7 +44,6 @@
+ #endif
+ #include "ide_modes.h"
+-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+ extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+ #define IDE_PMAC_DEBUG
+@@ -55,11 +57,18 @@
+       int                             aapl_bus_id;
+       struct device_node*             node;
+       u32                             timings[2];
+-      struct resource*                reg_resource;
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
++      /* Those fields are duplicating what is in hwif. We currently
++       * can't use the hwif ones because of some assumptions that are
++       * beeing done by the generic code about the kind of dma controller
++       * and format of the dma table. This will have to be fixed though.
++       */
+       volatile struct dbdma_regs*     dma_regs;
+-      struct dbdma_cmd*               dma_table;
+-      struct resource*                dma_resource;
++      struct dbdma_cmd*               dma_table_cpu;
++      dma_addr_t                      dma_table_dma;
++      struct scatterlist*             sg_table;
++      int                             sg_nents;
++      int                             sg_dma_direction;
+ #endif
+       
+ } pmac_ide[MAX_HWIFS] __pmacdata;
+@@ -308,7 +317,7 @@
+       ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
+       ide_hwifs[ix].selectproc = pmac_ide_selectproc;
+       ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
+-      if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
++      if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
+               ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+               if (!noautodma)
+@@ -352,41 +361,6 @@
+ }
+-/* Note: We don't use the generic routine here because for some
+- * yet unexplained reasons, it cause some media-bay CD-ROMs to
+- * lockup the bus. Strangely, this new version of the code is
+- * almost identical to the generic one and works, I've not yet
+- * managed to figure out what bit is causing the lockup in the
+- * generic code, possibly a timing issue...
+- * 
+- * --BenH
+- */
+-static int __pmac
+-wait_for_ready(ide_drive_t *drive)
+-{
+-      /* Timeout bumped for some powerbooks */
+-      int timeout = 2000;
+-      byte stat;
+-
+-      while(--timeout) {
+-              stat = GET_STAT();
+-              if(!(stat & BUSY_STAT)) {
+-                      if (drive->ready_stat == 0)
+-                              break;
+-                      else if((stat & drive->ready_stat) || (stat & ERR_STAT))
+-                              break;
+-              }
+-              mdelay(1);
+-      }
+-      if((stat & ERR_STAT) || timeout <= 0) {
+-              if (stat & ERR_STAT) {
+-                      printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat);
+-              }
+-              return 1;
+-      }
+-      return 0;
+-}
+-
+ static int __pmac
+ pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
+ {
+@@ -400,7 +374,7 @@
+       SELECT_MASK(HWIF(drive), drive, 0);
+       udelay(1);
+       (void)GET_STAT(); /* Get rid of pending error state */
+-      if(wait_for_ready(drive)) {
++      if(wait_for_ready(drive, 2000)) {       /* Timeout bumped for some powerbooks */
+               printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
+               goto out;
+       }
+@@ -410,10 +384,9 @@
+       OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+       OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+       udelay(1);
+-      __save_flags(flags);    /* local CPU only */
+-      ide__sti();             /* local CPU only -- for jiffies */
+-      result = wait_for_ready(drive);
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_set(flags);
++      result = wait_for_ready(drive, 2000);   /* Timeout bumped for some powerbooks */
++      local_irq_restore(flags);
+       OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+       if (result)
+               printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+@@ -823,6 +796,8 @@
+               struct pmac_ide_hwif* pmhw;
+               int *bidp;
+               int in_bay = 0;
++              u8 pbus, pid;
++              struct pci_dev *pdev = NULL;
+               /*
+                * If this node is not under a mac-io or dbdma node,
+@@ -841,6 +816,15 @@
+                       continue;
+               }
++              /* We need to find the pci_dev of the mac-io holding the
++               * IDE interface
++               */
++              if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
++                      pdev = pci_find_slot(pbus, pid);
++              if (pdev == NULL)
++                      printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
++                             np->full_name);
++
+               /*
+                * If this slot is taken (e.g. by ide-pci.c) try the next one.
+                */
+@@ -860,8 +844,7 @@
+               if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+                       np->addrs[1].size = 0x100;
+-              pmhw->reg_resource = request_OF_resource(np, 0, "  (mac-io IDE IO)");
+-              if (!pmhw->reg_resource) {
++              if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+                       printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+                       continue;
+               }
+@@ -935,6 +918,7 @@
+               hwif->chipset = ide_pmac;
+               hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+               hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
++              hwif->pci_dev = pdev;
+ #ifdef CONFIG_PMAC_PBOOK
+               if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
+                       hwif->noprobe = 0;
+@@ -964,13 +948,14 @@
+ static void __init 
+ pmac_ide_setup_dma(struct device_node *np, int ix)
+ {
+-      pmac_ide[ix].dma_resource = request_OF_resource(np, 1, " (mac-io IDE DMA)");
+-      if (!pmac_ide[ix].dma_resource) {
++      struct pmac_ide_hwif *pmif = &pmac_ide[ix];
++
++      if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+               printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
+               return;
+       }
+-      pmac_ide[ix].dma_regs =
++      pmif->dma_regs =
+               (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
+       /*
+@@ -978,14 +963,24 @@
+        * The +2 is +1 for the stop command and +1 to allow for
+        * aligning the start address to a multiple of 16 bytes.
+        */
+-      pmac_ide[ix].dma_table = (struct dbdma_cmd*)
+-             kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
+-      if (pmac_ide[ix].dma_table == 0) {
++      pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
++              ide_hwifs[ix].pci_dev,
++              (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
++              &pmif->dma_table_dma);
++      if (pmif->dma_table_cpu == NULL) {
+               printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+                      ide_hwifs[ix].name);
+               return;
+       }
++      pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
++                               GFP_KERNEL);
++      if (pmif->sg_table == NULL) {
++              pci_free_consistent(    ide_hwifs[ix].pci_dev,
++                                      (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
++                                      pmif->dma_table_cpu, pmif->dma_table_dma);
++              return;
++      }
+       ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+       if (!noautodma)
+@@ -993,65 +988,116 @@
+ #endif
+ }
++static int
++pmac_ide_build_sglist (int ix, struct request *rq)
++{
++      ide_hwif_t *hwif = &ide_hwifs[ix];
++      struct pmac_ide_hwif *pmif = &pmac_ide[ix];
++      struct buffer_head *bh;
++      struct scatterlist *sg = pmif->sg_table;
++      int nents = 0;
++
++      if (hwif->sg_dma_active)
++              BUG();
++              
++      if (rq->cmd == READ)
++              pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++      else
++              pmif->sg_dma_direction = PCI_DMA_TODEVICE;
++      bh = rq->bh;
++      do {
++              unsigned char *virt_addr = bh->b_data;
++              unsigned int size = bh->b_size;
++
++              if (nents >= MAX_DCMDS)
++                      return 0;
++
++              while ((bh = bh->b_reqnext) != NULL) {
++                      if ((virt_addr + size) != (unsigned char *) bh->b_data)
++                              break;
++                      size += bh->b_size;
++              }
++              memset(&sg[nents], 0, sizeof(*sg));
++              sg[nents].address = virt_addr;
++              sg[nents].length = size;
++              nents++;
++      } while (bh != NULL);
++
++      return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
++}
++
++static int
++pmac_ide_raw_build_sglist (int ix, struct request *rq)
++{
++      ide_hwif_t *hwif = &ide_hwifs[ix];
++      struct pmac_ide_hwif *pmif = &pmac_ide[ix];
++      struct scatterlist *sg = hwif->sg_table;
++      int nents = 0;
++      ide_task_t *args = rq->special;
++      unsigned char *virt_addr = rq->buffer;
++      int sector_count = rq->nr_sectors;
++
++      if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
++              pmif->sg_dma_direction = PCI_DMA_TODEVICE;
++      else
++              pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++      
++      if (sector_count > 128) {
++              memset(&sg[nents], 0, sizeof(*sg));
++              sg[nents].address = virt_addr;
++              sg[nents].length = 128  * SECTOR_SIZE;
++              nents++;
++              virt_addr = virt_addr + (128 * SECTOR_SIZE);
++              sector_count -= 128;
++      }
++      memset(&sg[nents], 0, sizeof(*sg));
++      sg[nents].address = virt_addr;
++      sg[nents].length =  sector_count  * SECTOR_SIZE;
++      nents++;
++   
++      return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
++}
++
+ /*
+  * pmac_ide_build_dmatable builds the DBDMA command list
+  * for a transfer and sets the DBDMA channel to point to it.
+  */
+-static int __pmac
++static int
+ pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
+ {
+-      struct dbdma_cmd *table, *tstart;
+-      int count = 0;
++      struct dbdma_cmd *table;
++      int i, count = 0;
+       struct request *rq = HWGROUP(drive)->rq;
+-      struct buffer_head *bh = rq->bh;
+-      unsigned int size, addr;
+       volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
++      struct scatterlist *sg;
+-      table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
++      /* DMA table is already aligned */
++      table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
+-#ifdef IDE_PMAC_DEBUG
+-      if (in_le32(&dma->status) & (RUN|ACTIVE))
+-              printk("ide-pmac: channel status not stopped ! (%x)\n",
+-                      in_le32(&dma->status));
+-#endif        
+-      /* Make sure channel is stopped and all error conditions are clear */
++      /* Make sure DMA controller is stopped (necessary ?) */
+       out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
+       while (in_le32(&dma->status) & RUN)
+               udelay(1);
+-      do {
+-              /*
+-               * Determine addr and size of next buffer area.  We assume that
+-               * individual virtual buffers are always composed linearly in
+-               * physical memory.  For example, we assume that any 8kB buffer
+-               * is always composed of two adjacent physical 4kB pages rather
+-               * than two possibly non-adjacent physical 4kB pages.
+-               */
+-              if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
+-                      addr = virt_to_bus(rq->buffer);
+-                      size = rq->nr_sectors << 9;
+-              } else {
+-                      /* group sequential buffers into one large buffer */
+-                      addr = virt_to_bus(bh->b_data);
+-                      size = bh->b_size;
+-                      while ((bh = bh->b_reqnext) != NULL) {
+-                              if ((addr + size) != virt_to_bus(bh->b_data))
+-                                      break;
+-                              size += bh->b_size;
+-                      }
+-              }
++      /* Build sglist */
++      if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
++              pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
++      else
++              pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
++      if (!i)
++              return 0;
+-              /*
+-               * Fill in the next DBDMA command block.
+-               * Note that one DBDMA command can transfer
+-               * at most 65535 bytes.
+-               */
+-#ifdef IDE_PMAC_DEBUG
+-              if (size & 0x01)
+-                      printk("ide-pmac: odd size transfer ! (%d)\n", size);
+-#endif                        
+-              while (size) {
+-                      unsigned int tc = (size < 0xfe00)? size: 0xfe00;
++      /* Build DBDMA commands list */
++      sg = pmac_ide[ix].sg_table;
++      while (i) {
++              u32 cur_addr;
++              u32 cur_len;
++
++              cur_addr = sg_dma_address(sg);
++              cur_len = sg_dma_len(sg);
++
++              while (cur_len) {
++                      unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+                       if (++count >= MAX_DCMDS) {
+                               printk(KERN_WARNING "%s: DMA table too small\n",
+@@ -1060,15 +1106,17 @@
+                       }
+                       st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
+                       st_le16(&table->req_count, tc);
+-                      st_le32(&table->phy_addr, addr);
++                      st_le32(&table->phy_addr, cur_addr);
+                       table->cmd_dep = 0;
+                       table->xfer_status = 0;
+                       table->res_count = 0;
+-                      addr += tc;
+-                      size -= tc;
++                      cur_addr += tc;
++                      cur_len -= tc;
+                       ++table;
+               }
+-      } while (bh != NULL);
++              sg++;
++              i--;
++      }
+       /* convert the last command to an input/output last command */
+       if (count)
+@@ -1080,10 +1128,23 @@
+       memset(table, 0, sizeof(struct dbdma_cmd));
+       out_le16(&table->command, DBDMA_STOP);
+-      out_le32(&dma->cmdptr, virt_to_bus(tstart));
++      out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
+       return 1;
+ }
++/* Teardown mappings after DMA has completed.  */
++static void
++pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
++{
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
++      struct scatterlist *sg = pmac_ide[ix].sg_table;
++      int nents = pmac_ide[ix].sg_nents;
++
++      if (nents) {
++              pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
++              pmac_ide[ix].sg_nents = 0;
++      }
++}
+ static __inline__ unsigned char
+ dma_bits_to_command(unsigned char bits)
+@@ -1233,10 +1294,12 @@
+ static int __pmac
+ pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+ {
++//    ide_task_t *args = HWGROUP(drive)->rq->special;
+       int ix, dstat;
+       volatile struct dbdma_regs *dma;
+       byte unit = (drive->select.b.unit & 0x01);
+       byte ata4;
++      int reading = 0;
+       /* Can we stuff a pointer to our intf structure in config_data
+        * or select_data in hwif ?
+@@ -1259,22 +1322,38 @@
+               pmac_ide_check_dma(drive);
+               break;
+       case ide_dma_read:
++              reading = 1;
+       case ide_dma_write:
+-              if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
++              SELECT_READ_WRITE(HWIF(drive),drive,func);
++              if (!pmac_ide_build_dmatable(drive, ix, !reading))
+                       return 1;
+               /* Apple adds 60ns to wrDataSetup on reads */
+               if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
+                       out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+                               pmac_ide[ix].timings[unit] + 
+-                              ((func == ide_dma_read) ? 0x00800000UL : 0));
++                              (reading ? 0x00800000UL : 0));
+                       (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
+               }
+               drive->waiting_for_dma = 1;
+               if (drive->media != ide_disk)
+                       return 0;
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+-              OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
+-                       IDE_COMMAND_REG);
++#if 0
++      {
++              ide_task_t *args = HWGROUP(drive)->rq->special;
++              OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++      }
++#else
++              if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
++                      ide_task_t *args = HWGROUP(drive)->rq->special;
++                      OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++              } else if (drive->addressing == 1)
++                      OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
++              else
++                      OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++#endif
+       case ide_dma_begin:
+               out_le32(&dma->control, (RUN << 16) | RUN);
+               /* Make sure it gets to the controller right now */
+@@ -1284,6 +1363,7 @@
+               drive->waiting_for_dma = 0;
+               dstat = in_le32(&dma->status);
+               out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
++              pmac_ide_destroy_dmatable(drive, ix);
+               /* verify good dma status */
+               return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+       case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+@@ -1358,19 +1438,19 @@
+       switch (drive->media) {
+       case ide_disk:
+               /* Spin down the drive */
+-              outb(drive->select.all, base+0x60);
+-              (void)inb(base+0x60);
++              OUT_BYTE(drive->select.all, base+0x60);
++              (void) IN_BYTE(base+0x60);
+               udelay(100);
+-              outb(0x0, base+0x30);
+-              outb(0x0, base+0x20);
+-              outb(0x0, base+0x40);
+-              outb(0x0, base+0x50);
+-              outb(0xe0, base+0x70);
+-              outb(0x2, base+0x160);   
++              OUT_BYTE(0x0, base+0x30);
++              OUT_BYTE(0x0, base+0x20);
++              OUT_BYTE(0x0, base+0x40);
++              OUT_BYTE(0x0, base+0x50);
++              OUT_BYTE(0xe0, base+0x70);
++              OUT_BYTE(0x2, base+0x160);   
+               for (j = 0; j < 10; j++) {
+                       int status;
+                       mdelay(100);
+-                      status = inb(base+0x70);
++                      status = IN_BYTE(base+0x70);
+                       if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+                               break;
+               }
+@@ -1483,10 +1563,10 @@
+       for (j = 0; j < 200; j++) {
+               int status;
+               mdelay(100);
+-              outb(drive->select.all, base + 0x60);
+-              if (inb(base + 0x60) != drive->select.all)
++              OUT_BYTE(drive->select.all, base + 0x60);
++              if (IN_BYTE(base + 0x60) != drive->select.all)
+                       continue;
+-              status = inb(base + 0x70);
++              status = IN_BYTE(base + 0x70);
+               if (!(status & BUSY_STAT))
+                       break;
+       }
+diff -Nur linux.org/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
+--- linux.org/drivers/ide/ide-probe.c  Mon Nov 26 14:29:17 2001
++++ linux/drivers/ide/ide-probe.c      Thu Jul 18 14:24:33 2002
+@@ -54,16 +54,33 @@
+ static inline void do_identify (ide_drive_t *drive, byte cmd)
+ {
++      ide_hwif_t *hwif = HWIF(drive);
+       int bswap = 1;
+       struct hd_driveid *id;
+       id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);  /* called with interrupts disabled! */
+-      ide_input_data(drive, id, SECTOR_WORDS);                /* read 512 bytes of id info */
+-      ide__sti();     /* local CPU only */
++      if (!id) {
++              printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
++              goto err_kmalloc;
++      }
++      /* read 512 bytes of id info */
++#if 1
++      ata_input_data(drive, id, SECTOR_WORDS);
++#else
++      {
++              unsigned long   *ptr = (unsigned long *)id ;
++              unsigned long   lcount = 256/2 ;
++                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
++              while( lcount-- )
++                      *ptr++ = inl(IDE_DATA_REG);
++      }
++#endif
++      local_irq_enable();
+       ide_fix_driveid(id);
+       if (id->word156 == 0x4d42) {
+-              printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
++              printk("%s: drive->id->word156 == 0x%04x \n",
++                      drive->name, drive->id->word156);
+       }
+       if (!drive->forced_lun)
+@@ -76,8 +93,7 @@
+       if ((id->model[0] == 'P' && id->model[1] == 'M')
+        || (id->model[0] == 'S' && id->model[1] == 'K')) {
+               printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
+-              drive->present = 0;
+-              return;
++              goto err_misc;
+       }
+ #endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
+@@ -96,7 +112,7 @@
+       ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+       if (strstr(id->model, "E X A B Y T E N E S T"))
+-              return;
++              goto err_misc;
+       id->model[sizeof(id->model)-1] = '\0';  /* we depend on this a lot! */
+       printk("%s: %s, ", drive->name, id->model);
+@@ -109,16 +125,17 @@
+               byte type = (id->config >> 8) & 0x1f;
+               printk("ATAPI ");
+ #ifdef CONFIG_BLK_DEV_PDC4030
+-              if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
++              if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
+                       printk(" -- not supported on 2nd Promise port\n");
+-                      drive->present = 0;
+-                      return;
++                      goto err_misc;
+               }
+ #endif /* CONFIG_BLK_DEV_PDC4030 */
+               switch (type) {
+                       case ide_floppy:
+                               if (!strstr(id->model, "CD-ROM")) {
+-                                      if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
++                                      if (!strstr(id->model, "oppy") &&
++                                          !strstr(id->model, "poyp") &&
++                                          !strstr(id->model, "ZIP"))
+                                               printk("cdrom or floppy?, assuming ");
+                                       if (drive->media != ide_cdrom) {
+                                               printk ("FLOPPY");
+@@ -130,7 +147,8 @@
+                               drive->removable = 1;
+ #ifdef CONFIG_PPC
+                               /* kludge for Apple PowerBook internal zip */
+-                              if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
++                              if (!strstr(id->model, "CD-ROM") &&
++                                  strstr(id->model, "ZIP")) {
+                                       printk ("FLOPPY");
+                                       type = ide_floppy;
+                                       break;
+@@ -161,10 +179,11 @@
+               drive->removable = 1;
+       /*
+        * Prevent long system lockup probing later for non-existant
+-       * slave drive if the hwif is actually a flash memory card of some variety:
++       * slave drive if the hwif is actually a flash memory card of
++       * some variety:
+        */
+       if (drive_is_flashcard(drive)) {
+-              ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
++              ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];
+               if (!mate->ata_flash) {
+                       mate->present = 0;
+                       mate->noprobe = 1;
+@@ -172,7 +191,13 @@
+       }
+       drive->media = ide_disk;
+       printk("ATA DISK drive\n");
+-      QUIRK_LIST(HWIF(drive),drive);
++      QUIRK_LIST(hwif, drive);
++      return;
++
++err_misc:
++      kfree(id);
++err_kmalloc:
++      drive->present = 0;
+       return;
+ }
+@@ -188,6 +213,7 @@
+  */
+ static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+ {
++//    ide_hwif_t *hwif = HWIF(drive);
+       int rc;
+       ide_ioreg_t hd_status;
+       unsigned long timeout;
+@@ -226,7 +252,7 @@
+       timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+       timeout += jiffies;
+       do {
+-              if (0 < (signed long)(jiffies - timeout)) {
++              if (time_after(jiffies, timeout)) {
+                       return 1;       /* drive timed-out */
+               }
+               ide_delay_50ms();               /* give drive a breather */
+@@ -235,12 +261,12 @@
+       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 */
++              local_irq_save(flags);
++                      /* 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 */
++              local_irq_restore(flags);
+       } else
+               rc = 2;                 /* drive refused ID */
+       return rc;
+@@ -248,11 +274,12 @@
+ static int try_to_identify (ide_drive_t *drive, byte cmd)
+ {
++      ide_hwif_t *hwif = HWIF(drive);
+       int retval;
+       int autoprobe = 0;
+       unsigned long cookie = 0;
+-      if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
++      if (IDE_CONTROL_REG && !hwif->irq) {
+               autoprobe = 1;
+               cookie = probe_irq_on();
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
+@@ -266,14 +293,14 @@
+               (void) GET_STAT();                      /* clear drive IRQ */
+               udelay(5);
+               irq = probe_irq_off(cookie);
+-              if (!HWIF(drive)->irq) {
++              if (!hwif->irq) {
+                       if (irq > 0) {
+-                              HWIF(drive)->irq = irq;
++                              hwif->irq = irq;
+                       } else {        /* Mmmm.. multiple IRQs.. don't know which was ours */
+                               printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+ #ifdef CONFIG_BLK_DEV_CMD640
+ #ifdef CMD640_DUMP_REGS
+-                              if (HWIF(drive)->chipset == ide_cmd640) {
++                              if (hwif->chipset == ide_cmd640) {
+                                       printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+                                       CMD640_DUMP_REGS;
+                               }
+@@ -326,9 +353,8 @@
+               return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+       }
+-      if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
+-       || drive->present || cmd == WIN_PIDENTIFY)
+-      {
++      if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) ||
++          drive->present || cmd == WIN_PIDENTIFY) {
+               if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
+                       rc = try_to_identify(drive,cmd); /* failed: try again */
+               if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+@@ -362,15 +388,16 @@
+  */
+ static void enable_nest (ide_drive_t *drive)
+ {
++      ide_hwif_t *hwif = HWIF(drive);
+       unsigned long timeout;
+-      printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
+-      SELECT_DRIVE(HWIF(drive), drive);
++      printk("%s: enabling %s -- ", hwif->name, drive->id->model);
++      SELECT_DRIVE(hwif, drive);
+       ide_delay_50ms();
+       OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+       timeout = jiffies + WAIT_WORSTCASE;
+       do {
+-              if (jiffies > timeout) {
++              if (time_after(jiffies, timeout)) {
+                       printk("failed (timeout)\n");
+                       return;
+               }
+@@ -381,9 +408,9 @@
+               printk("failed (status = 0x%02x)\n", GET_STAT());
+       else
+               printk("success\n");
+-      if (do_probe(drive, WIN_IDENTIFY) >= 2) {       /* if !(success||timed-out) */
++
++      if (do_probe(drive, WIN_IDENTIFY) >= 2) /* if !(success||timed-out) */
+               (void) do_probe(drive, WIN_PIDENTIFY);  /* look for ATAPI device */
+-      }
+ }
+ /*
+@@ -521,8 +548,7 @@
+               return; 
+       }
+-      __save_flags(flags);    /* local CPU only */
+-      __sti();                /* local CPU only; needed for jiffies and irq probing */
++      local_irq_set(flags);
+       /*
+        * Second drive should only exist if first drive was found,
+        * but a lot of cdrom drives are configured as single slaves.
+@@ -532,7 +558,8 @@
+               (void) probe_for_drive (drive);
+               if (drive->present && !hwif->present) {
+                       hwif->present = 1;
+-                      if (hwif->chipset != ide_4drives || !hwif->mate->present) {
++                      if (hwif->chipset != ide_4drives ||
++                          !hwif->mate->present) {
+                               hwif_register(hwif);
+                       }
+               }
+@@ -548,16 +575,16 @@
+               do {
+                       ide_delay_50ms();
+                       stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+-              } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
++              } while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+       }
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+               ide_drive_t *drive = &hwif->drives[unit];
+               if (drive->present) {
+-                      ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+-                      if (tuneproc != NULL && drive->autotune == 1)
+-                              tuneproc(drive, 255);   /* auto-tune PIO mode */
++                      if (hwif->tuneproc != NULL && drive->autotune == 1)
++                              /* auto-tune PIO mode */
++                              hwif->tuneproc(drive, 255);
+               }
+       }
+ }
+@@ -581,7 +608,8 @@
+       if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
+               if (!new->hwgroup)
+                       return;
+-              printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
++              printk("%s: potential irq problem with %s and %s\n",
++                      hwif->name, new->name, m->name);
+       }
+       if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
+               *match = new;
+@@ -597,8 +625,15 @@
+       q->queuedata = HWGROUP(drive);
+       blk_init_queue(q, do_ide_request);
++
++      if (drive->media == ide_disk) {
++#ifdef CONFIG_BLK_DEV_ELEVATOR_NOOP
++              elevator_init(&q->elevator, ELEVATOR_NOOP);
++#endif
++      }
+ }
++#undef __IRQ_HELL_SPIN
+ /*
+  * This routine sets up the irq for an ide interface, and creates a new
+  * hwgroup for the irq/hwif if none was previously assigned.
+@@ -624,8 +659,11 @@
+       
+       new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+       
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++#ifndef __IRQ_HELL_SPIN
++      save_and_cli(flags);
++#else
++      spin_lock_irqsave(&io_request_lock, flags);
++#endif
+       hwif->hwgroup = NULL;
+ #if MAX_HWIFS > 1
+@@ -662,7 +700,11 @@
+       } else {
+               hwgroup = new_hwgroup;
+               if (!hwgroup) {
+-                      restore_flags(flags);   /* all CPUs */
++#ifndef __IRQ_HELL_SPIN
++                      restore_flags(flags);
++#else
++                      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+                       return 1;
+               }
+               memset(hwgroup, 0, sizeof(ide_hwgroup_t));
+@@ -685,10 +727,18 @@
+ #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);
+-                      restore_flags(flags);   /* all CPUs */
++#ifndef __IRQ_HELL_SPIN
++                      restore_flags(flags);
++#else
++                      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+                       return 1;
+               }
+       }
+@@ -716,7 +766,12 @@
+               printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
+ #endif
+       }
+-      restore_flags(flags);   /* all CPUs; safe now that hwif->hwgroup is set up */
++#ifndef __IRQ_HELL_SPIN
++      restore_flags(flags);
++#else
++      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
++              /* all CPUs; safe now that hwif->hwgroup is set up */
+ #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+       printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+@@ -752,18 +807,35 @@
+       int *bs, *max_sect, *max_ra;
+       extern devfs_handle_t ide_devfs_handle;
++#if 1
++      units = MAX_DRIVES;
++#else
+       /* figure out maximum drive number on the interface */
+       for (units = MAX_DRIVES; units > 0; --units) {
+               if (hwif->drives[units-1].present)
+                       break;
+       }
++#endif
++
+       minors    = units * (1<<PARTN_BITS);
+       gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
++      if (!gd)
++              goto err_kmalloc_gd;
+       gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
++      if (!gd->sizes)
++              goto err_kmalloc_gd_sizes;
+       gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
++      if (!gd->part)
++              goto err_kmalloc_gd_part;
+       bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
++      if (!bs)
++              goto err_kmalloc_bs;
+       max_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));
+@@ -773,12 +845,10 @@
+       max_readahead[hwif->major] = max_ra;
+       for (unit = 0; unit < minors; ++unit) {
+               *bs++ = BLOCK_SIZE;
+-#ifdef CONFIG_BLK_DEV_PDC4030
+-              *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 255);
+-#else
+-              /* IDE can do up to 128K per request. */
+-              *max_sect++ = 255;
+-#endif
++              /*
++               * IDE can do up to 128K per request == 256
++               */
++              *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+               *max_ra++ = vm_max_readahead;
+       }
+@@ -804,6 +874,17 @@
+       add_gendisk(gd);
+       for (unit = 0; unit < units; ++unit) {
++#if 1
++              char name[64];
++              ide_add_generic_settings(hwif->drives + unit);
++              hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
++              sprintf (name, "host%d/bus%d/target%d/lun%d",
++                      (hwif->channel && hwif->mate) ?
++                      hwif->mate->index : hwif->index,
++                      hwif->channel, unit, hwif->drives[unit].lun);
++              if (hwif->drives[unit].present)
++                      hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
++#else
+               if (hwif->drives[unit].present) {
+                       char name[64];
+@@ -815,7 +896,23 @@
+                       hwif->drives[unit].de =
+                               devfs_mk_dir (ide_devfs_handle, name, NULL);
+               }
++#endif
+       }
++      return;
++
++err_kmalloc_max_ra:
++      kfree(max_sect);
++err_kmalloc_max_sect:
++      kfree(bs);
++err_kmalloc_bs:
++      kfree(gd->part);
++err_kmalloc_gd_part:
++      kfree(gd->sizes);
++err_kmalloc_gd_sizes:
++      kfree(gd);
++err_kmalloc_gd:
++      printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
++      return;
+ }
+ static int hwif_init (ide_hwif_t *hwif)
+@@ -831,7 +928,8 @@
+       }
+ #ifdef CONFIG_BLK_DEV_HD
+       if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+-              printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
++              printk("%s: CANNOT SHARE IRQ WITH OLD "
++                      "HARDDISK DRIVER (hd.c)\n", hwif->name);
+               return (hwif->present = 0);
+       }
+ #endif /* CONFIG_BLK_DEV_HD */
+@@ -839,7 +937,8 @@
+       hwif->present = 0; /* we set it back to 1 if all is ok below */
+       if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
+-              printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
++              printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
++                      hwif->name, hwif->major);
+               return (hwif->present = 0);
+       }
+       
+@@ -850,7 +949,8 @@
+                *      this port and try that.
+                */
+               if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+-                      printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
++                      printk("%s: Disabled unable to get IRQ %d.\n",
++                              hwif->name, i);
+                       (void) unregister_blkdev (hwif->major, hwif->name);
+                       return (hwif->present = 0);
+               }
+@@ -880,6 +980,19 @@
+       return hwif->present;
+ }
++void export_ide_init_queue (ide_drive_t *drive)
++{
++      ide_init_queue(drive);
++}
++
++byte export_probe_for_drive (ide_drive_t *drive)
++{
++      return probe_for_drive(drive);
++}
++
++EXPORT_SYMBOL(export_ide_init_queue);
++EXPORT_SYMBOL(export_probe_for_drive);
++
+ int ideprobe_init (void);
+ static ide_module_t ideprobe_module = {
+       IDE_PROBE_MODULE,
+@@ -913,6 +1026,8 @@
+ }
+ #ifdef MODULE
++extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
++
+ int init_module (void)
+ {
+       unsigned int index;
+@@ -921,12 +1036,14 @@
+               ide_unregister(index);
+       ideprobe_init();
+       create_proc_ide_interfaces();
++      ide_xlate_1024_hook = ide_xlate_1024;
+       return 0;
+ }
+ void cleanup_module (void)
+ {
+       ide_probe = NULL;
++      ide_xlate_1024_hook = 0;
+ }
+ MODULE_LICENSE("GPL");
+ #endif /* MODULE */
+diff -Nur linux.org/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
+--- linux.org/drivers/ide/ide-proc.c   Fri Sep  7 18:28:38 2001
++++ linux/drivers/ide/ide-proc.c       Thu Jul 18 14:24:33 2002
+@@ -65,6 +65,7 @@
+ #include <linux/mm.h>
+ #include <linux/pci.h>
+ #include <linux/ctype.h>
++#include <linux/hdreg.h>
+ #include <linux/ide.h>
+ #include <asm/io.h>
+@@ -159,6 +160,8 @@
+ static struct proc_dir_entry * proc_ide_root = NULL;
++#undef __PROC_HELL
++
+ static int proc_ide_write_config
+       (struct file *file, const char *buffer, unsigned long count, void *data)
+ {
+@@ -180,7 +183,11 @@
+        * Do one full pass to verify all parameters,
+        * then do another to actually write the regs.
+        */
++#ifndef __PROC_HELL
+       save_flags(flags);      /* all CPUs */
++#else
++      spin_lock_irqsave(&io_request_lock, flags);
++#endif
+       do {
+               const char *p;
+               if (for_real) {
+@@ -189,15 +196,32 @@
+                       ide_hwgroup_t *mategroup = NULL;
+                       if (hwif->mate && hwif->mate->hwgroup)
+                               mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
++#ifndef __PROC_HELL
+                       cli();  /* all CPUs; ensure all writes are done together */
+-                      while (mygroup->busy || (mategroup && mategroup->busy)) {
++#else
++                      spin_lock_irqsave(&io_request_lock, flags);
++#endif
++                      while (mygroup->busy ||
++                             (mategroup && mategroup->busy)) {
++#ifndef __PROC_HELL
+                               sti();  /* all CPUs */
+-                              if (0 < (signed long)(jiffies - timeout)) {
++#else
++                              spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
++                              if (time_after(jiffies, timeout)) {
+                                       printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
++#ifndef __PROC_HELL
+                                       restore_flags(flags);   /* all CPUs */
++#else
++                                      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+                                       return -EBUSY;
+                               }
++#ifndef __PROC_HELL
+                               cli();  /* all CPUs */
++#else
++                              spin_lock_irqsave(&io_request_lock, flags);
++#endif
+                       }
+               }
+               p = buffer;
+@@ -280,7 +304,11 @@
+                                                       break;
+                                       }
+                                       if (rc) {
++#ifndef __PROC_HELL
+                                               restore_flags(flags);   /* all CPUs */
++#else
++                                              spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+                                               printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
+                                                       msg, dev->bus->number, dev->devfn, reg, val);
+                                               printk("proc_ide_write_config: error %d\n", rc);
+@@ -310,9 +338,9 @@
+  * 
+  */
+                                       switch (digits) {
+-                                              case 2: outb(val, reg);
++                                              case 2: OUT_BYTE(val, reg);
+                                                       break;
+-                                              case 4: outw(val, reg);
++                                              case 4: OUT_WORD(val, reg);
+                                                       break;
+                                               case 8: outl(val, reg);
+                                                       break;
+@@ -322,10 +350,18 @@
+                       }
+               }
+       } while (!for_real++);
++#ifndef __PROC_HELL
+       restore_flags(flags);   /* all CPUs */
++#else
++      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+       return count;
+ parse_error:
++#ifndef __PROC_HELL
+       restore_flags(flags);   /* all CPUs */
++#else
++      spin_unlock_irqrestore(&io_request_lock, flags);
++#endif
+       printk("parse error\n");
+       return xx_xx_parse_error(start, startn, msg);
+ }
+@@ -445,19 +481,14 @@
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ }
+-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);
+-}
+-
+ static int proc_ide_read_identify
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+ {
+       ide_drive_t     *drive = (ide_drive_t *)data;
+       int             len = 0, i = 0;
+-      if (drive && !proc_ide_get_identify(drive, page)) {
+-              unsigned short *val = ((unsigned short *)page) + 2;
++      if (drive && !taskfile_lib_get_identify(drive, page)) {
++              unsigned short *val = (unsigned short *) page;
+               char *out = ((char *)val) + (SECTOR_WORDS * 4);
+               page = out;
+               do {
+@@ -588,7 +619,8 @@
+       if (!driver)
+               len = sprintf(page, "(none)\n");
+         else
+-              len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
++              len = sprintf(page,"%llu\n",
++                            (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ }
+@@ -732,16 +764,38 @@
+       }
+ }
+-void destroy_proc_ide_drives(ide_hwif_t *hwif)
++void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+ {
+-      int     d;
++      struct proc_dir_entry *ent;
++      struct proc_dir_entry *parent = hwif->proc;
++      char name[64];
++//    ide_driver_t *driver = drive->driver;
+-      for (d = 0; d < MAX_DRIVES; d++) {
+-              ide_drive_t *drive = &hwif->drives[d];
+-              ide_driver_t *driver = drive->driver;
++      if (drive->present && !drive->proc) {
++              drive->proc = proc_mkdir(drive->name, parent);
++              if (drive->proc)
++                      ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+-              if (!drive->proc)
+-                      continue;
++/*
++ * assume that we have these already, however, should test FIXME!
++ * if (driver) {
++ *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
++ *      ide_add_proc_entries(drive->proc, driver->proc, drive);
++ * }
++ *
++ */
++              sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
++              ent = proc_symlink(drive->name, proc_ide_root, name);
++              if (!ent)
++                      return;
++      }
++}
++
++void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
++{
++      ide_driver_t *driver = drive->driver;
++
++      if (drive->proc) {
+               if (driver)
+                       ide_remove_proc_entries(drive->proc, driver->proc);
+               ide_remove_proc_entries(drive->proc, generic_drive_entries);
+@@ -751,6 +805,19 @@
+       }
+ }
++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 },
+diff -Nur linux.org/drivers/ide/ide-swarm.c linux/drivers/ide/ide-swarm.c
+--- linux.org/drivers/ide/ide-swarm.c  Thu Jan  1 01:00:00 1970
++++ linux/drivers/ide/ide-swarm.c      Thu Jul 18 14:23:01 2002
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2001 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ * 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++/*  Derived loosely from ide-pmac.c, so:
++ *  
++ *  Copyright (C) 1998 Paul Mackerras.
++ *  Copyright (C) 1995-1998 Mark Lord
++ */
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/ide.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/sibyte/sb1250_int.h>
++#include <asm/sibyte/swarm_ide.h>
++
++void __init swarm_ide_probe(void)
++{
++      int i;
++      ide_hwif_t *hwif;
++      /* 
++       * Find the first untaken slot in hwifs 
++       */
++      for (i = 0; i < MAX_HWIFS; i++) {
++              if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
++                      break;
++              }
++      }
++      if (i == MAX_HWIFS) {
++              printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
++              return;
++      }
++
++      /* Set up our stuff */
++      hwif = &ide_hwifs[i];
++      hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
++      hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
++      hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
++      hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
++      hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
++      hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
++      hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
++      hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
++      hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
++      hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
++//    hwif->hw->ack_intr                     = swarm_ide_ack_intr;
++      hwif->hw.irq                          = SWARM_IDE_INT;
++      hwif->ideproc                         = swarm_ideproc;
++
++      memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
++      hwif->irq = hwif->hw.irq;
++      printk("SWARM onboard IDE configured as device %i\n", i);
++}
++
+diff -Nur linux.org/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
+--- linux.org/drivers/ide/ide-tape.c   Fri Dec 21 18:41:54 2001
++++ linux/drivers/ide/ide-tape.c       Thu Jul 18 14:24:33 2002
+@@ -1835,10 +1835,9 @@
+  *    idetape_end_request is used to finish servicing a request, and to
+  *    insert a pending pipeline request into the main device queue.
+  */
+-static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
++static int idetape_end_request (ide_drive_t *drive, int uptodate)
+ {
+-      ide_drive_t *drive = hwgroup->drive;
+-      struct request *rq = hwgroup->rq;
++      struct request *rq = HWGROUP(drive)->rq;
+       idetape_tape_t *tape = drive->driver_data;
+       unsigned long flags;
+       int error;
+@@ -1932,6 +1931,7 @@
+       if (tape->active_data_request == NULL)
+               clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
+       spin_unlock_irqrestore(&tape->spinlock, flags);
++      return 0;
+ }
+ static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+@@ -1944,10 +1944,10 @@
+ #endif /* IDETAPE_DEBUG_LOG */
+       if (!tape->pc->error) {
+               idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+-              idetape_end_request (1, HWGROUP (drive));
++              idetape_end_request(drive, 1);
+       } else {
+               printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+-              idetape_end_request (0, HWGROUP (drive));
++              idetape_end_request(drive, 0);
+       }
+       return ide_stopped;
+ }
+@@ -2050,10 +2050,11 @@
+ #if IDETAPE_DEBUG_LOG
+       if (tape->debug_level >= 4)
+-              printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
++              printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
++                              "interrupt handler\n");
+ #endif /* IDETAPE_DEBUG_LOG */        
+-      status.all = GET_STAT();                                        /* Clear the interrupt */
++      status.all = GET_STAT();        /* Clear the interrupt */
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+       if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+@@ -2090,11 +2091,14 @@
+ #endif /* IDETAPE_DEBUG_LOG */
+               clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+-              ide__sti();     /* local CPU only */
++              local_irq_enable();
+ #if SIMULATE_ERRORS
+-              if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
+-                      printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
++              if ((pc->c[0] == IDETAPE_WRITE_CMD ||
++                   pc->c[0] == IDETAPE_READ_CMD) &&
++                  (++error_sim_count % 100) == 0) {
++                      printk(KERN_INFO "ide-tape: %s: simulating error\n",
++                              tape->name);
+                       status.b.check = 1;
+               }
+ #endif
+@@ -2103,10 +2107,10 @@
+               if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {    /* Error detected */
+ #if IDETAPE_DEBUG_LOG
+                       if (tape->debug_level >= 1)
+-                              printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
++                              printk(KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
+ #endif /* IDETAPE_DEBUG_LOG */
+                       if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+-                              printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
++                              printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+                               return ide_do_reset (drive);
+                       }
+ #if IDETAPE_DEBUG_LOG
+@@ -2116,31 +2120,34 @@
+                       return idetape_retry_pc (drive);                                /* Retry operation */
+               }
+               pc->error = 0;
+-              if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {       /* Media access command */
++              if (!tape->onstream &&
++                   test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {
++                      /* Media access command */
+                       tape->dsc_polling_start = jiffies;
+                       tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+                       tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
+-                      idetape_postpone_request (drive);               /* Allow ide.c to handle other requests */
++                      idetape_postpone_request(drive);                /* Allow ide.c to handle other requests */
+                       return ide_stopped;
+               }
+               if (tape->failed_pc == pc)
+                       tape->failed_pc = NULL;
+-              return pc->callback(drive);                     /* Command finished - Call the callback function */
++              return pc->callback(drive);     /* Command finished - Call the callback function */
+       }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+       if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+-              printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
+-              printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
++              printk(KERN_ERR "ide-tape: The tape wants to issue more "
++                              "interrupts in DMA mode\n");
++              printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+               (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+               return ide_do_reset (drive);
+       }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-      bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);                      /* Get the number of bytes to transfer */
+-      bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);                      /* on this interrupt */
+-      ireason.all   = IN_BYTE (IDE_IREASON_REG);
++      bcount.b.high = IN_BYTE(IDE_BCOUNTH_REG);       /* Get the number of bytes to transfer */
++      bcount.b.low  = IN_BYTE(IDE_BCOUNTL_REG);       /* on this interrupt */
++      ireason.all   = IN_BYTE(IDE_IREASON_REG);
+       if (ireason.b.cod) {
+-              printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
++              printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+               return ide_do_reset (drive);
+       }
+       if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {        /* Hopefully, we will never get here */
+@@ -2154,6 +2161,8 @@
+                       if (temp > pc->buffer_size) {
+                               printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+                               idetape_discard_data (drive, bcount.all);
++                              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                                      BUG();
+                               ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+                               return ide_started;
+                       }
+@@ -2180,6 +2189,8 @@
+       if (tape->debug_level >= 2)
+               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+ #endif
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
+       ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);      /* And set the interrupt handler again */
+       return ide_started;
+ }
+@@ -2234,28 +2245,33 @@
+       int retries = 100;
+       ide_startstop_t startstop;
+-      if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+-              printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
++      if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
++              printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+               return startstop;
+       }
+-      ireason.all = IN_BYTE (IDE_IREASON_REG);
++      ireason.all = IN_BYTE(IDE_IREASON_REG);
+       while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+-              printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
++              printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
++                              "a packet command, retrying\n");
+               udelay(100);
+               ireason.all = IN_BYTE(IDE_IREASON_REG);
+               if (retries == 0) {
+-                      printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
++                      printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
++                                      "issuing a packet command, ignoring\n");
+                       ireason.b.cod = 1;
+                       ireason.b.io = 0;
+               }
+       }
+       if (!ireason.b.cod || ireason.b.io) {
+-              printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
++              printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
++                              "a packet command\n");
+               return ide_do_reset (drive);
+       }
+       tape->cmd_start_time = jiffies;
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
+       ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);       /* Set the interrupt routine */
+-      atapi_output_bytes (drive,pc->c,12);                    /* Send the actual packet */
++      atapi_output_bytes(drive,pc->c,12);     /* Send the actual packet */
+       return ide_started;
+ }
+@@ -2266,16 +2282,19 @@
+       int dma_ok = 0;
+ #if IDETAPE_DEBUG_BUGS
+-      if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+-              printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
++      if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
++          pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
++              printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
++                      "Two request sense in serial were issued\n");
+       }
+ #endif /* IDETAPE_DEBUG_BUGS */
+       if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
+               tape->failed_pc = pc;
+-      tape->pc = pc;                                                  /* Set the current packet command */
++      tape->pc = pc;                  /* Set the current packet command */
+-      if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
++      if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
++          test_bit(PC_ABORT, &pc->flags)) {
+               /*
+                *      We will "abort" retrying a packet command in case
+                *      a legitimate error code was received (crossing a
+@@ -2283,14 +2302,19 @@
+                *      example).
+                */
+               if (!test_bit (PC_ABORT, &pc->flags)) {
+-                      if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
+-                            tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
+-                              printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+-                                      tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
++                      if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
++                            tape->sense_key == 2 && tape->asc == 4 &&
++                           (tape->ascq == 1 || tape->ascq == 8))) {
++                              printk(KERN_ERR "ide-tape: %s: I/O error, "
++                                              "pc = %2x, key = %2x, "
++                                              "asc = %2x, ascq = %2x\n",
++                                              tape->name, pc->c[0],
++                                              tape->sense_key, tape->asc,
++                                              tape->ascq);
+                               if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+                                       printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
+                       }
+-                      pc->error = IDETAPE_ERROR_GENERAL;              /* Giving up */
++                      pc->error = IDETAPE_ERROR_GENERAL;      /* Giving up */
+               }
+               tape->failed_pc = NULL;
+               return pc->callback(drive);
+@@ -2301,13 +2325,14 @@
+ #endif /* IDETAPE_DEBUG_LOG */
+       pc->retries++;
+-      pc->actually_transferred = 0;                                   /* We haven't transferred any data yet */
++      pc->actually_transferred = 0;           /* We haven't transferred any data yet */
+       pc->current_position=pc->buffer;
+-      bcount.all=pc->request_transfer;                                /* Request to transfer the entire buffer at once */
++      bcount.all=pc->request_transfer;        /* Request to transfer the entire buffer at once */
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+-              printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
++      if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
++              printk(KERN_WARNING "ide-tape: DMA disabled, "
++                              "reverting to PIO\n");
+               (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+       }
+       if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+@@ -2315,18 +2340,20 @@
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+       if (IDE_CONTROL_REG)
+-              OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+-      OUT_BYTE (dma_ok ? 1 : 0,    IDE_FEATURE_REG);                  /* Use PIO/DMA */
+-      OUT_BYTE (bcount.b.high,     IDE_BCOUNTH_REG);
+-      OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
+-      OUT_BYTE (drive->select.all, IDE_SELECT_REG);
++              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
++      OUT_BYTE(dma_ok ? 1 : 0,    IDE_FEATURE_REG);   /* Use PIO/DMA */
++      OUT_BYTE(bcount.b.high,     IDE_BCOUNTH_REG);
++      OUT_BYTE(bcount.b.low,      IDE_BCOUNTL_REG);
++      OUT_BYTE(drive->select.all, IDE_SELECT_REG);
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (dma_ok) {                                           /* Begin DMA, if necessary */
++      if (dma_ok) {                   /* Begin DMA, if necessary */
+               set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+               (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+       }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+       if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+               OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+               return ide_started;
+@@ -2348,7 +2375,7 @@
+               printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
+ #endif /* IDETAPE_DEBUG_LOG */
+-      idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
++      idetape_end_request(drive, tape->pc->error ? 0 : 1);
+       return ide_stopped;
+ }
+@@ -2360,10 +2387,10 @@
+       idetape_init_pc (pc);
+       pc->c[0] = IDETAPE_MODE_SENSE_CMD;
+       if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
+-              pc->c[1] = 8;                   /* DBD = 1 - Don't return block descriptors */
++              pc->c[1] = 8;   /* DBD = 1 - Don't return block descriptors */
+       pc->c[2] = page_code;
+-      pc->c[3] = 255;                         /* Don't limit the returned information */
+-      pc->c[4] = 255;                         /* (We will just discard data in that case) */
++      pc->c[3] = 255;         /* Don't limit the returned information */
++      pc->c[4] = 255;         /* (We will just discard data in that case) */
+       if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
+               pc->request_transfer = 12;
+       else if (page_code == IDETAPE_CAPABILITIES_PAGE)
+@@ -2391,13 +2418,15 @@
+       }
+       tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
+ #if USE_IOTRACE
+-      IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
++      IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
++                      tape->tape_head, tape->minor);
+ #endif
+ #if IDETAPE_DEBUG_LOG
+       if (tape->debug_level >= 1)
+-              printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
++              printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
++                      tape->cur_frames, tape->max_frames);
+ #endif
+-      idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
++      idetape_end_request(drive, tape->pc->error ? 0 : 1);
+       return ide_stopped;
+ }
+@@ -2418,26 +2447,26 @@
+       idetape_tape_t *tape = drive->driver_data;
+       int full = 125, empty = 75;
+-      if (jiffies > tape->controlled_pipeline_head_time + 120 * HZ) {
++      if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
+               tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
+               tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
+               tape->controlled_last_pipeline_head = tape->pipeline_head;
+               tape->controlled_pipeline_head_time = jiffies;
+       }
+-      if (jiffies > tape->controlled_pipeline_head_time + 60 * HZ)
++      if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
+               tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
+-      else if (jiffies > tape->controlled_previous_head_time)
++      else if (time_after(jiffies, tape->controlled_previous_head_time))
+               tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
+       if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
+-              if (jiffies > tape->uncontrolled_previous_head_time + 10 * HZ) {
++              if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
+                       tape->uncontrolled_pipeline_head_time = jiffies;
+                       tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
+               }
+       } else {
+               tape->uncontrolled_previous_head_time = jiffies;
+               tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
+-              if (jiffies > tape->uncontrolled_pipeline_head_time + 30 * HZ) {
++              if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
+                       tape->uncontrolled_pipeline_head_time = jiffies;
+               }
+       }
+@@ -2471,9 +2500,9 @@
+               printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
+       status.all = GET_STAT();
+       if (status.b.dsc) {
+-              if (status.b.check) {                                   /* Error detected */
++              if (status.b.check) {           /* Error detected */
+                       printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
+-                      return idetape_retry_pc (drive);                        /* Retry operation */
++                      return idetape_retry_pc (drive);        /* Retry operation */
+               }
+               pc->error = 0;
+               if (tape->failed_pc == pc)
+@@ -2500,7 +2529,7 @@
+               tape->insert_time = jiffies;
+               tape->insert_size = 0;
+       }
+-      if (jiffies > tape->insert_time)
++      if (time_after(jiffies, tape->insert_time))
+               tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+       if (jiffies - tape->avg_time >= HZ) {
+               tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
+@@ -2517,9 +2546,9 @@
+       rq->current_nr_sectors -= blocks;
+       if (!tape->pc->error)
+-              idetape_end_request (1, HWGROUP (drive));
++              idetape_end_request(drive, 1);
+       else
+-              idetape_end_request (tape->pc->error, HWGROUP (drive));
++              idetape_end_request(drive, tape->pc->error);
+       return ide_stopped;
+ }
+@@ -2607,6 +2636,38 @@
+ }
+ /*
++ * This is our end_request replacement function.
++ */
++static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
++{
++      struct request *rq;
++      unsigned long flags;
++      int ret = 1;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      rq = HWGROUP(drive)->rq;
++
++      /*
++       * decide whether to reenable DMA -- 3 is a random magic for now,
++       * if we DMA timeout more than 3 times, just stay in PIO
++       */
++      if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
++              drive->state = 0;
++              HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
++      }
++
++      if (!end_that_request_first(rq, uptodate, drive->name)) {
++              add_blkdev_randomness(MAJOR(rq->rq_dev));
++              blkdev_dequeue_request(rq);
++              HWGROUP(drive)->rq = NULL;
++              end_that_request_last(rq);
++              ret = 0;
++      }
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      return ret;
++}
++
++/*
+  *    idetape_do_request is our request handling function.    
+  */
+ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+@@ -2618,31 +2679,38 @@
+ #if IDETAPE_DEBUG_LOG
+       if (tape->debug_level >= 5)
+-              printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
++              printk (KERN_INFO "ide-tape: rq_status: %d, "
++                      "rq_dev: %u, cmd: %d, errors: %d\n", rq->rq_status,
++                      (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+       if (tape->debug_level >= 2)
+-              printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
++              printk (KERN_INFO "ide-tape: sector: %ld, "
++                      "nr_sectors: %ld, current_nr_sectors: %ld\n",
++                      rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+ #endif /* IDETAPE_DEBUG_LOG */
+       if (!IDETAPE_RQ_CMD (rq->cmd)) {
+               /*
+                *      We do not support buffer cache originated requests.
+                */
+-              printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+-              ide_end_request (0, HWGROUP (drive));                   /* Let the common code handle it */
++              printk (KERN_NOTICE "ide-tape: %s: Unsupported command in "
++                      "request queue (%d)\n", drive->name, rq->cmd);
++              idetape_do_end_request(drive, 0);
+               return ide_stopped;
+       }
+       /*
+        *      Retry a failed packet command
+        */
+-      if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
++      if (tape->failed_pc != NULL &&
++          tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+               return idetape_issue_packet_command (drive, tape->failed_pc);
+       }
+ #if IDETAPE_DEBUG_BUGS
+       if (postponed_rq != NULL)
+               if (rq != postponed_rq) {
+-                      printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
+-                      idetape_end_request (0, HWGROUP (drive));
++                      printk (KERN_ERR "ide-tape: ide-tape.c bug - "
++                                      "Two DSC requests were queued\n");
++                      idetape_end_request(drive, 0);
+                       return ide_stopped;
+               }
+ #endif /* IDETAPE_DEBUG_BUGS */
+@@ -2674,17 +2742,18 @@
+        */
+       if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
+               tape->measure_insert_time = 1;
+-      if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
++      if (tape->req_buffer_fill &&
++          (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+               tape->req_buffer_fill = 0;
+               tape->writes_since_buffer_fill = 0;
+               tape->reads_since_buffer_fill = 0;
+               tape->last_buffer_fill = jiffies;
+               idetape_queue_onstream_buffer_fill(drive);
+-              if (jiffies > tape->insert_time)
++              if (time_after(jiffies, tape->insert_time))
+                       tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+               return ide_stopped;
+       }
+-      if (jiffies > tape->insert_time)
++      if (time_after(jiffies, tape->insert_time))
+               tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+       calculate_speeds(drive);
+       if (tape->onstream && tape->max_frames &&
+@@ -2699,7 +2768,8 @@
+                       tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
+ #if IDETAPE_DEBUG_LOG
+               if (tape->debug_level >= 4)
+-                      printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
++                      printk(KERN_INFO "ide-tape: postponing request, "
++                                      "cmd %d, cur %d, max %d\n",
+                               rq->cmd, tape->cur_frames, tape->max_frames);
+ #endif
+               if (tape->postpone_cnt++ < 500) {
+@@ -2708,7 +2778,8 @@
+               }
+ #if ONSTREAM_DEBUG
+               else if (tape->debug_level >= 4) 
+-                      printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
++                      printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
++                              tape->name, tape->postpone_cnt);
+ #endif
+       }
+       if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+@@ -2740,7 +2811,7 @@
+                       if (tape->onstream) {
+                               if (tape->cur_frames - tape->reads_since_buffer_fill <= 0)
+                                       tape->req_buffer_fill = 1;
+-                              if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
++                              if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
+                                       tape->req_buffer_fill = 1;
+                       }
+                       pc = idetape_next_pc_storage (drive);
+@@ -2756,7 +2827,7 @@
+                       if (tape->onstream) {
+                               if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames)
+                                       tape->req_buffer_fill = 1;
+-                              if (jiffies > tape->last_buffer_fill + 5 * HZ / 100)
++                              if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
+                                       tape->req_buffer_fill = 1;
+                               calculate_speeds(drive);
+                       }
+@@ -2770,7 +2841,7 @@
+                       break;
+               case IDETAPE_ABORTED_WRITE_RQ:
+                       rq->cmd = IDETAPE_WRITE_RQ;
+-                      idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
++                      idetape_end_request(drive, IDETAPE_ERROR_EOD);
+                       return ide_stopped;
+               case IDETAPE_ABORTED_READ_RQ:
+ #if IDETAPE_DEBUG_LOG
+@@ -2778,7 +2849,7 @@
+                               printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+ #endif
+                       rq->cmd = IDETAPE_READ_RQ;
+-                      idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
++                      idetape_end_request(drive, IDETAPE_ERROR_EOD);
+                       return ide_stopped;
+               case IDETAPE_PC_RQ1:
+                       pc = (idetape_pc_t *) rq->buffer;
+@@ -2789,7 +2860,7 @@
+                       return ide_stopped;
+               default:
+                       printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
+-                      idetape_end_request (0, HWGROUP (drive));
++                      idetape_end_request(drive, 0);
+                       return ide_stopped;
+       }
+       return idetape_issue_packet_command (drive, pc);
+@@ -3096,10 +3167,10 @@
+       idetape_tape_t *tape = drive->driver_data;
+       idetape_read_position_result_t *result;
+       
+-//#if IDETAPE_DEBUG_LOG
+-//    if (tape->debug_level >= 4)
++#if IDETAPE_DEBUG_LOG
++      if (tape->debug_level >= 4)
+               printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+-//#endif /* IDETAPE_DEBUG_LOG */
++#endif /* IDETAPE_DEBUG_LOG */
+       if (!tape->pc->error) {
+               result = (idetape_read_position_result_t *) tape->pc->buffer;
+@@ -3112,7 +3183,7 @@
+               if (result->bpu) {
+                       printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+                       clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
+-                      idetape_end_request (0, HWGROUP (drive));
++                      idetape_end_request(drive, 0);
+               } else {
+ #if IDETAPE_DEBUG_LOG
+                       if (tape->debug_level >= 2)
+@@ -3123,10 +3194,10 @@
+                       tape->last_frame_position = ntohl (result->last_block);
+                       tape->blocks_in_buffer = result->blocks_in_buffer[2];
+                       set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
+-                      idetape_end_request (1, HWGROUP (drive));
++                      idetape_end_request(drive, 1);
+               }
+       } else {
+-              idetape_end_request (0, HWGROUP (drive));
++              idetape_end_request(drive, 0);
+       }
+       return ide_stopped;
+ }
+@@ -3214,7 +3285,7 @@
+        * Wait for the tape to become ready
+        */
+       timeout += jiffies;
+-      while (jiffies < timeout) {
++      while (time_before(jiffies, timeout)) {
+               idetape_create_test_unit_ready_cmd(&pc);
+               if (!__idetape_queue_pc_tail(drive, &pc))
+                       return 0;
+@@ -3273,10 +3344,10 @@
+       idetape_pc_t pc;
+       int position;
+-//#if IDETAPE_DEBUG_LOG
+-//        if (tape->debug_level >= 4)
++#if IDETAPE_DEBUG_LOG
++        if (tape->debug_level >= 4)
+       printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+-//#endif /* IDETAPE_DEBUG_LOG */
++#endif /* IDETAPE_DEBUG_LOG */
+ #ifdef NO_LONGER_REQUIRED
+       idetape_flush_tape_buffers(drive);
+@@ -6085,14 +6156,14 @@
+       int minor = tape->minor;
+       unsigned long flags;
+-      save_flags (flags);     /* all CPUs (overkill?) */
+-      cli();                  /* all CPUs (overkill?) */
+-      if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
+-              restore_flags(flags);   /* all CPUs (overkill?) */
++      spin_lock_irqsave(&io_request_lock, flags);
++      if (test_bit (IDETAPE_BUSY, &tape->flags) || drive->usage ||
++          tape->first_stage != NULL || tape->merge_stage_size) {
++              spin_unlock_irqrestore(&io_request_lock, flags);
+               return 1;
+       }
+       idetape_chrdevs[minor].drive = NULL;
+-      restore_flags (flags);  /* all CPUs (overkill?) */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       DRIVER(drive)->busy = 0;
+       (void) ide_unregister_subdriver (drive);
+       drive->driver_data = NULL;
+@@ -6132,10 +6203,8 @@
+ #endif
+-static int idetape_reinit (ide_drive_t *drive)
+-{
+-      return 0;
+-}
++int idetape_init (void);
++int idetape_reinit(ide_drive_t *drive);
+ /*
+  *    IDE subdriver functions, registered with ide.c
+@@ -6145,11 +6214,21 @@
+       version:                IDETAPE_VERSION,
+       media:                  ide_tape,
+       busy:                   1,
++#ifdef CONFIG_IDEDMA_ONLYDISK
++      supports_dma:           0,
++#else
+       supports_dma:           1,
++#endif
+       supports_dsc_overlap:   1,
+       cleanup:                idetape_cleanup,
++      standby:                NULL,
++      suspend:                NULL,
++      resume:                 NULL,
++      flushcache:             NULL,
+       do_request:             idetape_do_request,
+       end_request:            idetape_end_request,
++      sense:                  NULL,
++      error:                  NULL,
+       ioctl:                  idetape_blkdev_ioctl,
+       open:                   idetape_blkdev_open,
+       release:                idetape_blkdev_release,
+@@ -6157,11 +6236,14 @@
+       revalidate:             NULL,
+       pre_reset:              idetape_pre_reset,
+       capacity:               NULL,
++      special:                NULL,
+       proc:                   idetape_proc,
+-      driver_reinit:          idetape_reinit,
++      init:                   idetape_init,
++      reinit:                 idetape_reinit,
++      ata_prebuilder:         NULL,
++      atapi_prebuilder:       NULL,
+ };
+-int idetape_init (void);
+ static ide_module_t idetape_module = {
+       IDE_DRIVER_MODULE,
+       idetape_init,
+@@ -6181,6 +6263,92 @@
+       release:        idetape_chrdev_release,
+ };
++int idetape_reinit (ide_drive_t *drive)
++{
++#if 0
++      idetape_tape_t *tape;
++      int minor, failed = 0, supported = 0;
++/* DRIVER(drive)->busy++; */
++      MOD_INC_USE_COUNT;
++#if ONSTREAM_DEBUG
++        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
++#endif
++      if (!idetape_chrdev_present)
++              for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
++                      idetape_chrdevs[minor].drive = NULL;
++
++      if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
++              ide_register_module (&idetape_module);
++              MOD_DEC_USE_COUNT;
++#if ONSTREAM_DEBUG
++              printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
++#endif
++              return 0;
++      }
++      if (!idetape_chrdev_present &&
++          devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
++              printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
++              MOD_DEC_USE_COUNT;
++#if ONSTREAM_DEBUG
++              printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
++#endif
++              return -EBUSY;
++      }
++      do {
++              if (!idetape_identify_device (drive, drive->id)) {
++                      printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
++                      continue;
++              }
++              if (drive->scsi) {
++                      if (strstr(drive->id->model, "OnStream DI-30")) {
++                              printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
++                      } else {
++                              printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
++                              continue;
++                      }
++              }
++              tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
++              if (tape == NULL) {
++                      printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
++                      continue;
++              }
++              if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
++                      printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
++                      kfree (tape);
++                      continue;
++              }
++              for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
++              idetape_setup (drive, tape, minor);
++              idetape_chrdevs[minor].drive = drive;
++              tape->de_r =
++                  devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
++                                  HWIF(drive)->major, minor,
++                                  S_IFCHR | S_IRUGO | S_IWUGO,
++                                  &idetape_fops, NULL);
++              tape->de_n =
++                  devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
++                                  HWIF(drive)->major, minor + 128,
++                                  S_IFCHR | S_IRUGO | S_IWUGO,
++                                  &idetape_fops, NULL);
++              devfs_register_tape (tape->de_r);
++              supported++; failed--;
++      } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
++      if (!idetape_chrdev_present && !supported) {
++              devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
++      } else
++              idetape_chrdev_present = 1;
++      ide_register_module (&idetape_module);
++      MOD_DEC_USE_COUNT;
++#if ONSTREAM_DEBUG
++      printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
++#endif
++
++      return 0;
++#else
++      return 1;
++#endif
++}
++
+ MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+ MODULE_LICENSE("GPL");
+@@ -6205,7 +6373,7 @@
+       ide_drive_t *drive;
+       idetape_tape_t *tape;
+       int minor, failed = 0, supported = 0;
+-
++/* DRIVER(drive)->busy++; */
+       MOD_INC_USE_COUNT;
+ #if ONSTREAM_DEBUG
+         printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+diff -Nur linux.org/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
+--- linux.org/drivers/ide/ide-taskfile.c       Thu Jan  1 01:00:00 1970
++++ linux/drivers/ide/ide-taskfile.c   Thu Jul 18 14:24:33 2002
+@@ -0,0 +1,2826 @@
++/*
++ * linux/drivers/ide/ide-taskfile.c   Version 0.33    April 11, 2002
++ *
++ *  Copyright (C) 2000-2002   Michael Cornwell <cornwell@acm.org>
++ *  Copyright (C) 2000-2002   Andre Hedrick <andre@linux-ide.org>
++ *  Copyright (C) 2001-2002   Klaus Smolin
++ *                                    IBM Storage Technology Division
++ *
++ *  The big the bad and the ugly.
++ *
++ *  Problems to be fixed because of BH interface or the lack therefore.
++ *
++ *  Fill me in stupid !!!
++ *
++ *  HOST:
++ *    General refers to the Controller and Driver "pair".
++ *  DATA HANDLER:
++ *    Under the context of Linux it generally refers to an interrupt handler.
++ *    However, it correctly describes the 'HOST'
++ *  DATA BLOCK:
++ *    The amount of data needed to be transfered as predefined in the
++ *    setup of the device.
++ *  STORAGE ATOMIC:
++ *    The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
++ *    small as a single sector or as large as the entire command block
++ *    request.
++ */
++
++#include <linux/config.h>
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/major.h>
++#include <linux/errno.h>
++#include <linux/genhd.h>
++#include <linux/blkpg.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/hdreg.h>
++#include <linux/ide.h>
++
++#include <asm/byteorder.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/bitops.h>
++
++#define DEBUG_TASKFILE        0       /* unset when fixed */
++
++#if DEBUG_TASKFILE
++#define DTF(x...) printk(x)
++#else
++#define DTF(x...)
++#endif
++
++/*
++ *
++ */
++#define task_rq_offset(rq) \
++      (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
++
++/*
++ * for now, taskfile requests are special :/
++ *
++ * However, upon the creation of the atapi version of packet_command
++ * data-phase ISR plus it own diagnostics and extensions for direct access
++ * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will
++ * come localized.
++ */
++inline char *task_map_rq (struct request *rq, unsigned long *flags)
++{
++      if (rq->bh)
++              return ide_map_buffer(rq, flags);
++      return rq->buffer + task_rq_offset(rq);
++}
++
++inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags)
++{
++      if (rq->bh)
++              ide_unmap_buffer(buf, flags);
++}
++
++inline u32 task_read_24 (ide_drive_t *drive)
++{
++      return  (IN_BYTE(IDE_HCYL_REG)<<16) |
++              (IN_BYTE(IDE_LCYL_REG)<<8) |
++               IN_BYTE(IDE_SECTOR_REG);
++}
++
++static void ata_bswap_data (void *buffer, int wcount)
++{
++      u16 *p = buffer;
++
++      while (wcount--) {
++              *p = *p << 8 | *p >> 8; p++;
++              *p = *p << 8 | *p >> 8; p++;
++      }
++}
++
++#if SUPPORT_VLB_SYNC
++/*
++ * Some localbus EIDE interfaces require a special access sequence
++ * when using 32-bit I/O instructions to transfer data.  We call this
++ * the "vlb_sync" sequence, which consists of three successive reads
++ * of the sector count register location, with interrupts disabled
++ * to ensure that the reads all happen together.
++ */
++static inline void task_vlb_sync (ide_ioreg_t port)
++{
++      (void) IN_BYTE (port);
++      (void) IN_BYTE (port);
++      (void) IN_BYTE (port);
++}
++#endif /* SUPPORT_VLB_SYNC */
++
++/*
++ * This is used for most PIO data transfers *from* the IDE interface
++ */
++void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
++{
++      byte io_32bit;
++
++      /*
++       * first check if this controller has defined a special function
++       * for handling polled ide transfers
++       */
++
++      if (HWIF(drive)->ideproc) {
++              HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
++              return;
++      }
++
++      io_32bit = drive->io_32bit;
++
++      if (io_32bit) {
++#if SUPPORT_VLB_SYNC
++              if (io_32bit & 2) {
++                      unsigned long flags;
++                      local_irq_save(flags);
++                      task_vlb_sync(IDE_NSECTOR_REG);
++                      insl(IDE_DATA_REG, buffer, wcount);
++                      local_irq_restore(flags);
++              } else
++#endif /* SUPPORT_VLB_SYNC */
++                      insl(IDE_DATA_REG, buffer, wcount);
++      } else {
++#if SUPPORT_SLOW_DATA_PORTS
++              if (drive->slow) {
++                      unsigned short *ptr = (unsigned short *) buffer;
++                      while (wcount--) {
++                              *ptr++ = inw_p(IDE_DATA_REG);
++                              *ptr++ = inw_p(IDE_DATA_REG);
++                      }
++              } else
++#endif /* SUPPORT_SLOW_DATA_PORTS */
++                      insw(IDE_DATA_REG, buffer, wcount<<1);
++      }
++}
++
++/*
++ * This is used for most PIO data transfers *to* the IDE interface
++ */
++void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
++{
++      byte io_32bit;
++
++      if (HWIF(drive)->ideproc) {
++              HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
++              return;
++      }
++
++      io_32bit = drive->io_32bit;
++
++      if (io_32bit) {
++#if SUPPORT_VLB_SYNC
++              if (io_32bit & 2) {
++                      unsigned long flags;
++                      local_irq_save(flags);
++                      task_vlb_sync(IDE_NSECTOR_REG);
++                      outsl(IDE_DATA_REG, buffer, wcount);
++                      local_irq_restore(flags);
++              } else
++#endif /* SUPPORT_VLB_SYNC */
++                      outsl(IDE_DATA_REG, buffer, wcount);
++      } else {
++#if SUPPORT_SLOW_DATA_PORTS
++              if (drive->slow) {
++                      unsigned short *ptr = (unsigned short *) buffer;
++                      while (wcount--) {
++                              outw_p(*ptr++, IDE_DATA_REG);
++                              outw_p(*ptr++, IDE_DATA_REG);
++                      }
++              } else
++#endif /* SUPPORT_SLOW_DATA_PORTS */
++                      outsw(IDE_DATA_REG, buffer, wcount<<1);
++      }
++}
++
++/*
++ * The following routines are mainly used by the ATAPI drivers.
++ *
++ * These routines will round up any request for an odd number of bytes,
++ * so if an odd bytecount is specified, be sure that there's at least one
++ * extra byte allocated for the buffer.
++ */
++void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
++{
++      if (HWIF(drive)->ideproc) {
++              HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
++              return;
++      }
++
++      ++bytecount;
++#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
++      if (MACH_IS_ATARI || MACH_IS_Q40) {
++              /* Atari has a byte-swapped IDE interface */
++              insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
++              return;
++      }
++#endif /* CONFIG_ATARI */
++      ata_input_data (drive, buffer, bytecount / 4);
++      if ((bytecount & 0x03) >= 2)
++              insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
++}
++
++void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
++{
++      if (HWIF(drive)->ideproc) {
++              HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
++              return;
++      }
++
++      ++bytecount;
++#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
++      if (MACH_IS_ATARI || MACH_IS_Q40) {
++              /* Atari has a byte-swapped IDE interface */
++              outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
++              return;
++      }
++#endif /* CONFIG_ATARI */
++      ata_output_data (drive, buffer, bytecount / 4);
++      if ((bytecount & 0x03) >= 2)
++              outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
++}
++
++void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
++{
++      ata_input_data(drive, buffer, wcount);
++      if (drive->bswap)
++              ata_bswap_data(buffer, wcount);
++}
++
++void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
++{
++      if (drive->bswap) {
++              ata_bswap_data(buffer, wcount);
++              ata_output_data(drive, buffer, wcount);
++              ata_bswap_data(buffer, wcount);
++      } else {
++              ata_output_data(drive, buffer, wcount);
++      }
++}
++
++/*
++ * Needed for PCI irq sharing
++ */
++int drive_is_ready (ide_drive_t *drive)
++{
++      byte stat = 0;
++      if (drive->waiting_for_dma)
++              return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
++#if 0
++      /* need to guarantee 400ns since last command was issued */
++      udelay(1);
++#endif
++
++#ifdef CONFIG_IDEPCI_SHARE_IRQ
++      /*
++       * We do a passive status test under shared PCI interrupts on
++       * cards that truly share the ATA side interrupt, but may also share
++       * an interrupt with another pci card/device.  We make no assumptions
++       * about possible isa-pnp and pci-pnp issues yet.
++       */
++      if (IDE_CONTROL_REG)
++              stat = GET_ALTSTAT();
++      else
++#endif /* CONFIG_IDEPCI_SHARE_IRQ */
++      stat = GET_STAT();      /* Note: this may clear a pending IRQ!! */
++
++      if (stat & BUSY_STAT)
++              return 0;       /* drive busy:  definitely not interrupting */
++      return 1;               /* drive ready: *might* be interrupting */
++}
++
++/*
++ * Global for All, and taken from ide-pmac.c
++ */
++int wait_for_ready (ide_drive_t *drive, int timeout)
++{
++      byte stat = 0;
++
++      while(--timeout) {
++              stat = GET_STAT();
++              if(!(stat & BUSY_STAT)) {
++                      if (drive->ready_stat == 0)
++                              break;
++                      else if((stat & drive->ready_stat) || (stat & ERR_STAT))
++                              break;
++              }
++              mdelay(1);
++      }
++      if((stat & ERR_STAT) || timeout <= 0) {
++              if (stat & ERR_STAT) {
++                      printk(KERN_ERR "%s: wait_for_ready, error status: %x\n", drive->name, stat);
++              }
++              return 1;
++      }
++      return 0;
++}
++
++/*
++ * This routine busy-waits for the drive status to be not "busy".
++ * It then checks the status for all of the "good" bits and none
++ * of the "bad" bits, and if all is okay it returns 0.  All other
++ * cases return 1 after invoking ide_error() -- caller should just return.
++ *
++ * This routine should get fixed to not hog the cpu during extra long waits..
++ * That could be done by busy-waiting for the first jiffy or two, and then
++ * setting a timer to wake up at half second intervals thereafter,
++ * until timeout is achieved, before timing out.
++ */
++int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
++{
++      byte stat;
++      int i;
++      unsigned long flags;
++ 
++      /* bail early if we've exceeded max_failures */
++      if (drive->max_failures && (drive->failures > drive->max_failures)) {
++              *startstop = ide_stopped;
++              return 1;
++      }
++
++      udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
++      if ((stat = GET_STAT()) & BUSY_STAT) {
++              local_irq_set(flags);
++              timeout += jiffies;
++              while ((stat = GET_STAT()) & BUSY_STAT) {
++                      if (time_after(jiffies, timeout)) {
++                              local_irq_restore(flags);
++                              *startstop = DRIVER(drive)->error(drive, "status timeout", stat);
++                              return 1;
++                      }
++              }
++              local_irq_restore(flags);
++      }
++      /*
++       * Allow status to settle, then read it again.
++       * A few rare drives vastly violate the 400ns spec here,
++       * so we'll wait up to 10usec for a "good" status
++       * rather than expensively fail things immediately.
++       * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
++       */
++      for (i = 0; i < 10; i++) {
++              udelay(1);
++              if (OK_STAT((stat = GET_STAT()), good, bad))
++                      return 0;
++      }
++      *startstop = DRIVER(drive)->error(drive, "status error", stat);
++      return 1;
++}
++
++void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
++{
++#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
++      printk(KERN_INFO "%s: ", drive->name);
++//    printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
++      printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
++      printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
++      printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
++      printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
++      printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
++      printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
++      printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
++      printk(KERN_INFO "%s: ", drive->name);
++//    printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
++      printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
++      printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
++      printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
++      printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
++      printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
++      printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
++      printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
++#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
++}
++
++ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
++{
++      task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
++      hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
++      struct hd_driveid *id = drive->id;
++      byte HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF;
++
++#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
++      void debug_taskfile(drive, task);
++#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
++
++      /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
++      if (IDE_CONTROL_REG)
++              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
++      SELECT_MASK(HWIF(drive), drive, 0);
++
++      if ((id->command_set_2 & 0x0400) &&
++          (id->cfs_enable_2 & 0x0400) &&
++          (drive->addressing == 1)) {
++              OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
++              OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
++              OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
++              OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
++              OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
++      }
++
++      OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
++      OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
++      /* refers to number of sectors to transfer */
++      OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
++      /* refers to sector offset or start sector */
++      OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
++      OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
++
++      OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
++      if (task->handler != NULL) {
++              ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
++              OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
++              if (task->prehandler != NULL)
++                      return task->prehandler(drive, task->rq);
++              return ide_started;
++      }
++#if 0
++      switch(task->data_phase) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
++              case TASKFILE_OUT_DMAQ:
++              case TASKFILE_OUT_DMA:
++                      HWIF(drive)->dmaproc(ide_dma_write, drive);
++                      break;
++              case TASKFILE_IN_DMAQ:
++              case TASKFILE_IN_DMA:
++                      HWIF(drive)->dmaproc(ide_dma_read, drive);
++                      break;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++              default:
++                      if (task->handler == NULL)
++                              return ide_stopped;
++                      ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
++                      /* Issue the command */
++                      OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
++                      if (task->prehandler != NULL)
++                              return task->prehandler(drive, HWGROUP(drive)->rq);
++      }
++#else
++      //      if ((rq->cmd == WRITE) && (drive->using_dma))
++      /* for dma commands we down set the handler */
++      if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
++#endif
++      return ide_started;
++}
++
++#if 0
++/*
++ * Error reporting, in human readable form (luxurious, but a memory hog).
++ */
++byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
++{
++      unsigned long flags;
++      byte err = 0;
++
++      local_irq_set(flags);
++      printk("%s: %s: status=0x%02x", drive->name, msg, stat);
++#if FANCY_STATUS_DUMPS
++      printk(" { ");
++      if (stat & BUSY_STAT)
++              printk("Busy ");
++      else {
++              if (stat & READY_STAT)  printk("DriveReady ");
++              if (stat & WRERR_STAT)  printk("DeviceFault ");
++              if (stat & SEEK_STAT)   printk("SeekComplete ");
++              if (stat & DRQ_STAT)    printk("DataRequest ");
++              if (stat & ECC_STAT)    printk("CorrectedError ");
++              if (stat & INDEX_STAT)  printk("Index ");
++              if (stat & ERR_STAT)    printk("Error ");
++      }
++      printk("}");
++#endif  /* FANCY_STATUS_DUMPS */
++      printk("\n");
++      if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
++              err = GET_ERR();
++              printk("%s: %s: error=0x%02x", drive->name, msg, err);
++#if FANCY_STATUS_DUMPS
++              if (drive->media == ide_disk) {
++                      printk(" { ");
++                      if (err & ABRT_ERR)     printk("DriveStatusError ");
++                      if (err & ICRC_ERR)     printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
++                      if (err & ECC_ERR)      printk("UncorrectableError ");
++                      if (err & ID_ERR)       printk("SectorIdNotFound ");
++                      if (err & TRK0_ERR)     printk("TrackZeroNotFound ");
++                      if (err & MARK_ERR)     printk("AddrMarkNotFound ");
++                      printk("}");
++                      if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
++                              if ((drive->id->command_set_2 & 0x0400) &&
++                                  (drive->id->cfs_enable_2 & 0x0400) &&
++                                  (drive->addressing == 1)) {
++                                      __u64 sectors = 0;
++                                      u32 low = 0, high = 0;
++                                      low = task_read_24(drive);
++                                      OUT_BYTE(0x80, IDE_CONTROL_REG);
++                                      high = task_read_24(drive);
++                                      sectors = ((__u64)high << 24) | low;
++                                      printk(", LBAsect=%lld", sectors);
++                              } else {
++                                      byte cur = IN_BYTE(IDE_SELECT_REG);
++                                      if (cur & 0x40) {       /* using LBA? */
++                                              printk(", LBAsect=%ld", (unsigned long)
++                                               ((cur&0xf)<<24)
++                                               |(IN_BYTE(IDE_HCYL_REG)<<16)
++                                               |(IN_BYTE(IDE_LCYL_REG)<<8)
++                                               | IN_BYTE(IDE_SECTOR_REG));
++                                      } else {
++                                              printk(", CHS=%d/%d/%d",
++                                                (IN_BYTE(IDE_HCYL_REG)<<8) +
++                                                 IN_BYTE(IDE_LCYL_REG),
++                                                cur & 0xf,
++                                                IN_BYTE(IDE_SECTOR_REG));
++                                      }
++                              }
++                              if (HWGROUP(drive)->rq)
++                                      printk(", sector=%lu", (__u64) HWGROUP(drive)->rq->sector);
++                      }
++              }
++#endif  /* FANCY_STATUS_DUMPS */
++              printk("\n");
++      }
++      local_irq_restore(flags);
++      return err;
++}
++#endif
++
++/*
++ * Clean up after success/failure of an explicit taskfile operation.
++ */
++void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
++{
++      unsigned long flags;
++      struct request *rq;
++      ide_task_t *args;
++      task_ioreg_t command;
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      rq = HWGROUP(drive)->rq;
++      spin_unlock_irqrestore(&io_request_lock, flags);
++      args = (ide_task_t *) rq->special;
++
++      command = args->tfRegister[IDE_COMMAND_OFFSET];
++
++      if (rq->errors == 0)
++              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
++
++      if (args->tf_in_flags.b.data) {
++              unsigned short data = IN_WORD(IDE_DATA_REG);
++              args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
++              args->hobRegister[IDE_DATA_OFFSET_HOB]  = (data >> 8) & 0xFF;
++      }
++      args->tfRegister[IDE_ERROR_OFFSET]   = err;
++      args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
++      args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
++      args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
++      args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
++      args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
++      args->tfRegister[IDE_STATUS_OFFSET]  = stat;
++      if ((drive->id->command_set_2 & 0x0400) &&
++          (drive->id->cfs_enable_2 & 0x0400) &&
++          (drive->addressing == 1)) {
++              OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
++              args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
++              args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
++              args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
++              args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
++              args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
++      }
++
++#if 0
++/*    taskfile_settings_update(drive, args, command); */
++
++      if (args->posthandler != NULL)
++              args->posthandler(drive, args);
++#endif
++
++      spin_lock_irqsave(&io_request_lock, flags);
++      blkdev_dequeue_request(rq);
++      HWGROUP(drive)->rq = NULL;
++      end_that_request_last(rq);
++      spin_unlock_irqrestore(&io_request_lock, flags);
++}
++
++#if 0
++/*
++ * try_to_flush_leftover_data() is invoked in response to a drive
++ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
++ * resetting the drive, this routine tries to clear the condition
++ * by read a sector's worth of data from the drive.  Of course,
++ * this may not help if the drive is *waiting* for data from *us*.
++ */
++void task_try_to_flush_leftover_data (ide_drive_t *drive)
++{
++      int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
++
++      if (drive->media != ide_disk)
++              return;
++      while (i > 0) {
++              u32 buffer[16];
++              unsigned int wcount = (i > 16) ? 16 : i;
++              i -= wcount;
++              taskfile_input_data (drive, buffer, wcount);
++      }
++}
++
++/*
++ * taskfile_error() takes action based on the error returned by the drive.
++ */
++ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
++{
++      struct request *rq;
++      byte err;
++
++        err = taskfile_dump_status(drive, msg, stat);
++      if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
++              return ide_stopped;
++      /* retry only "normal" I/O: */
++      if (rq->cmd == IDE_DRIVE_TASKFILE) {
++              rq->errors = 1;
++              ide_end_taskfile(drive, stat, err);
++              return ide_stopped;
++      }
++      if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
++              rq->errors |= ERROR_RESET;
++      } else {
++              if (drive->media == ide_disk && (stat & ERR_STAT)) {
++                      /* err has different meaning on cdrom and tape */
++                      if (err == ABRT_ERR) {
++                              if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
++                                      return ide_stopped;     /* some newer drives don't support WIN_SPECIFY */
++                      } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
++                              drive->crc_count++;     /* UDMA crc error -- just retry the operation */
++                      } else if (err & (BBD_ERR | ECC_ERR))   /* retries won't help these */
++                              rq->errors = ERROR_MAX;
++                      else if (err & TRK0_ERR)        /* help it find track zero */
++                                rq->errors |= ERROR_RECAL;
++                }
++                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
++                        task_try_to_flush_leftover_data(drive);
++      }
++      if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
++              OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);    /* force an abort */
++
++      if (rq->errors >= ERROR_MAX) {
++                      DRIVER(drive)->end_request(drive, 0);
++      } else {
++              if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++                      ++rq->errors;
++                      return ide_do_reset(drive);
++              }
++              if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
++                      drive->special.b.recalibrate = 1;
++              ++rq->errors;
++      }
++      return ide_stopped;
++}
++#endif
++
++/*
++ * Handler for special commands without a data phase from ide-disk
++ */
++
++/*
++ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
++ */
++ide_startstop_t set_multmode_intr (ide_drive_t *drive)
++{
++      byte stat;
++
++      if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
++              drive->mult_count = drive->mult_req;
++      } else {
++              drive->mult_req = drive->mult_count = 0;
++              drive->special.b.recalibrate = 1;
++              (void) ide_dump_status(drive, "set_multmode", stat);
++      }
++      return ide_stopped;
++}
++
++/*
++ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
++ */
++ide_startstop_t set_geometry_intr (ide_drive_t *drive)
++{
++      byte stat;
++
++      if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
++              return ide_stopped;
++
++      if (stat & (ERR_STAT|DRQ_STAT))
++              return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
++
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
++      ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
++      return ide_started;
++}
++
++/*
++ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
++ */
++ide_startstop_t recal_intr (ide_drive_t *drive)
++{
++      byte stat = GET_STAT();
++
++      if (!OK_STAT(stat,READY_STAT,BAD_STAT))
++              return DRIVER(drive)->error(drive, "recal_intr", stat);
++      return ide_stopped;
++}
++
++/*
++ * Handler for commands without a data phase
++ */
++ide_startstop_t task_no_data_intr (ide_drive_t *drive)
++{
++      ide_task_t *args        = HWGROUP(drive)->rq->special;
++      byte stat               = GET_STAT();
++
++      local_irq_enable();
++      if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
++              DTF("%s: command opcode 0x%02x\n", drive->name,
++                      args->tfRegister[IDE_COMMAND_OFFSET]);
++              return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
++              /* calls ide_end_drive_cmd */
++      }
++      if (args)
++              ide_end_drive_cmd (drive, stat, GET_ERR());
++
++      return ide_stopped;
++}
++
++/*
++ * Handler for command with PIO data-in phase, READ
++ */
++/*
++ * FIXME before 2.4 enable ...
++ *    DATA integrity issue upon error. <andre@linux-ide.org>
++ */
++ide_startstop_t task_in_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      unsigned long flags;
++
++      if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
++              if (stat & (ERR_STAT|DRQ_STAT)) {
++#if 0
++                      DTF("%s: attempting to recover last " \
++                              "sector counter status=0x%02x\n",
++                              drive->name, stat);
++                      /*
++                       * Expect a BUG BOMB if we attempt to rewind the
++                       * offset in the BH aka PAGE in the current BLOCK
++                       * segment.  This is different than the HOST segment.
++                       */
++#endif
++                      if (!rq->bh)
++                              rq->current_nr_sectors++;
++                      return DRIVER(drive)->error(drive, "task_in_intr", stat);
++              }
++              if (!(stat & BUSY_STAT)) {
++                      DTF("task_in_intr to Soon wait for next interrupt\n");
++                      if (HWGROUP(drive)->handler == NULL)
++                              ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
++                      return ide_started;  
++              }
++      }
++#if 0
++
++      /*
++       * Holding point for a brain dump of a thought :-/
++       */
++
++      if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
++              DTF("%s: READ attempting to recover last " \
++                      "sector counter status=0x%02x\n",
++                      drive->name, stat);
++              rq->current_nr_sectors++;
++              return DRIVER(drive)->error(drive, "task_in_intr", stat);
++        }
++      if (!rq->current_nr_sectors)
++              if (!DRIVER(drive)->end_request(drive, 1))
++                      return ide_stopped;
++
++      if (--rq->current_nr_sectors <= 0)
++              if (!DRIVER(drive)->end_request(drive, 1))
++                      return ide_stopped;
++#endif
++
++      pBuf = task_map_rq(rq, &flags);
++      DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
++              pBuf, (int) rq->current_nr_sectors, stat);
++      taskfile_input_data(drive, pBuf, SECTOR_WORDS);
++      task_unmap_rq(rq, pBuf, &flags);
++      /*
++       * FIXME :: We really can not legally get a new page/bh
++       * regardless, if this is the end of our segment.
++       * BH walking or segment can only be updated after we have a good
++       * GET_STAT(); return.
++       */
++      if (--rq->current_nr_sectors <= 0)
++              if (!DRIVER(drive)->end_request(drive, 1))
++                      return ide_stopped;
++      /*
++       * ERM, it is techincally legal to leave/exit here but it makes
++       * a mess of the code ...
++       */
++      if (HWGROUP(drive)->handler == NULL)
++              ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
++      return ide_started;
++}
++
++#undef ALTSTAT_SCREW_UP
++
++#ifdef ALTSTAT_SCREW_UP
++/*
++ * (ks/hs): Poll Alternate Status Register to ensure
++ * that drive is not busy.
++ */
++byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
++{
++      int i;
++
++      DTF("multi%s: ASR = %x\n", msg, stat);
++      if (stat & BUSY_STAT) {
++              /* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
++              for (i=0; i<100; i++) {
++                      stat = GET_ALTSTAT();
++                      if ((stat & BUSY_STAT) == 0)
++                              break;
++              }
++      }
++      /*
++       * (ks/hs): Read Status AFTER Alternate Status Register
++       */
++      return(GET_STAT());
++}
++
++/*
++ * (ks/hs): Poll Alternate status register to wait for drive
++ * to become ready for next transfer
++ */
++byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
++{
++
++      /* (ks/hs): FIXME: Error handling, time-out? */
++      while (stat & BUSY_STAT)
++              stat = GET_ALTSTAT();
++      DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
++      return(GET_STAT());     /* (ks/hs): Clear pending IRQ */
++}
++#endif /* ALTSTAT_SCREW_UP */
++
++/*
++ * Handler for command with Read Multiple
++ */
++ide_startstop_t task_mulin_intr (ide_drive_t *drive)
++{
++#ifdef ALTSTAT_SCREW_UP
++      byte stat       = altstat_multi_busy(drive, GET_ALTSTAT(), "read");
++#else
++      byte stat               = GET_STAT();
++#endif /* ALTSTAT_SCREW_UP */
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      unsigned int msect      = drive->mult_count;
++      unsigned int nsect;
++      unsigned long flags;
++
++      if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
++              if (stat & (ERR_STAT|DRQ_STAT)) {
++                      if (!rq->bh) {
++                              rq->current_nr_sectors += drive->mult_count;
++                              /*
++                               * NOTE: could rewind beyond beginning :-/
++                               */
++                      } else {
++                              printk("%s: MULTI-READ assume all data " \
++                                      "transfered is bad status=0x%02x\n",
++                                      drive->name, stat);
++                      }
++                      return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
++              }
++              /* no data yet, so wait for another interrupt */
++              if (HWGROUP(drive)->handler == NULL)
++                      ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
++              return ide_started;
++      }
++
++#ifdef ALTSTAT_SCREW_UP
++      /*
++       * Screw the request we do not support bad data-phase setups!
++       * Either read and learn the ATA standard or crash yourself!
++       */
++      if (!msect) {
++              /*
++               * (ks/hs): Drive supports multi-sector transfer,
++               * drive->mult_count was not set
++               */
++              nsect = 1;
++              while (rq->current_nr_sectors) {
++                      pBuf = task_map_rq(rq, &flags);
++                      DTF("Multiread: %p, nsect: %d, " \
++                              "rq->current_nr_sectors: %ld\n",
++                              pBuf, nsect, rq->current_nr_sectors);
++//                    rq->current_nr_sectors -= nsect;
++                      taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
++                      task_unmap_rq(rq, pBuf, &flags);
++                      rq->errors = 0;
++                      rq->current_nr_sectors -= nsect;
++                      stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
++              }
++              DRIVER(drive)->end_request(drive, 1);
++              return ide_stopped;
++      }
++#endif /* ALTSTAT_SCREW_UP */
++
++      do {
++              nsect = rq->current_nr_sectors;
++              if (nsect > msect)
++                      nsect = msect;
++              pBuf = task_map_rq(rq, &flags);
++              DTF("Multiread: %p, nsect: %d, msect: %d, " \
++                      " rq->current_nr_sectors: %d\n",
++                      pBuf, nsect, msect, rq->current_nr_sectors);
++//            rq->current_nr_sectors -= nsect;
++//            msect -= nsect;
++              taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
++              task_unmap_rq(rq, pBuf, &flags);
++              rq->errors = 0;
++              rq->current_nr_sectors -= nsect;
++              msect -= nsect;
++              /*
++               * FIXME :: We really can not legally get a new page/bh
++               * regardless, if this is the end of our segment.
++               * BH walking or segment can only be updated after we have a
++               * good GET_STAT(); return.
++               */
++              if (!rq->current_nr_sectors) {
++                      if (!DRIVER(drive)->end_request(drive, 1))
++                              return ide_stopped;
++              }
++      } while (msect);
++      if (HWGROUP(drive)->handler == NULL)
++              ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
++      return ide_started;
++}
++
++/*
++ * VERIFY ME before 2.4 ... unexpected race is possible based on details
++ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
++ */
++ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
++{
++      char *pBuf              = NULL;
++      unsigned long flags;
++      ide_startstop_t startstop;
++
++      if (ide_wait_stat(&startstop, drive, DATA_READY,
++                      drive->bad_wstat, WAIT_DRQ)) {
++              printk(KERN_ERR "%s: no DRQ after issuing %s\n",
++                      drive->name,
++                      drive->addressing ? "WRITE_EXT" : "WRITE");
++              return startstop;
++      }
++      /* For Write_sectors we need to stuff the first sector */
++      pBuf = task_map_rq(rq, &flags);
++//    rq->current_nr_sectors--;
++      taskfile_output_data(drive, pBuf, SECTOR_WORDS);
++      rq->current_nr_sectors--;
++      /*
++       * WARNING :: Interrupt could happen instantly :-/
++       */
++      task_unmap_rq(rq, pBuf, &flags);
++      return ide_started;
++}
++
++/*
++ * Handler for command with PIO data-out phase WRITE
++ *
++ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
++ */
++ide_startstop_t task_out_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      unsigned long flags;
++
++      if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
++              DTF("%s: WRITE attempting to recover last " \
++                      "sector counter status=0x%02x\n",
++                      drive->name, stat);
++              rq->current_nr_sectors++;
++              return DRIVER(drive)->error(drive, "task_out_intr", stat);
++      }
++      /*
++       * Safe to update request for partial completions.
++       * We have a good STATUS CHECK!!!
++       */
++      if (!rq->current_nr_sectors)
++              if (!DRIVER(drive)->end_request(drive, 1))
++                      return ide_stopped;
++      if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
++              rq = HWGROUP(drive)->rq;
++              pBuf = task_map_rq(rq, &flags);
++              DTF("write: %p, rq->current_nr_sectors: %d\n",
++                      pBuf, (int) rq->current_nr_sectors);
++//            rq->current_nr_sectors--;
++              taskfile_output_data(drive, pBuf, SECTOR_WORDS);
++              task_unmap_rq(rq, pBuf, &flags);
++              rq->errors = 0;
++              rq->current_nr_sectors--;
++      }
++      if (HWGROUP(drive)->handler == NULL)
++              ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
++      return ide_started;
++}
++
++ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
++{
++      ide_task_t *args = rq->special;
++      ide_startstop_t startstop;
++
++#if 0
++      /*
++       * assign private copy for multi-write
++       */
++      memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
++#endif
++
++      if (ide_wait_stat(&startstop, drive, DATA_READY,
++                      drive->bad_wstat, WAIT_DRQ)) {
++              printk(KERN_ERR "%s: no DRQ after issuing %s\n",
++                      drive->name,
++                      drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
++              return startstop;
++      }
++#if 0
++      if (wait_for_ready(drive, 100))
++              IDE_DEBUG(__LINE__);            //BUG();
++#else
++      if (!(drive_is_ready(drive))) {
++              int i;
++              for (i=0; i<100; i++) {
++                      if (drive_is_ready(drive))
++                              break;
++              }
++      }
++#endif
++      /*
++       * WARNING :: if the drive as not acked good status we may not
++       * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
++       */
++      return args->handler(drive);
++}
++
++/*
++ * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
++ */
++/*
++ * Handler for command write multiple
++ * Called directly from execute_drive_cmd for the first bunch of sectors,
++ * afterwards only by the ISR
++ */
++ide_startstop_t task_mulout_intr (ide_drive_t *drive)
++{
++#ifdef ALTSTAT_SCREW_UP
++      byte stat       = altstat_multi_busy(drive, GET_ALTSTAT(), "write");
++#else
++      byte stat               = GET_STAT();
++#endif /* ALTSTAT_SCREW_UP */
++
++      struct request *rq              = HWGROUP(drive)->rq;
++      char *pBuf                      = NULL;
++      ide_startstop_t startstop       = ide_stopped;
++      unsigned int msect              = drive->mult_count;
++      unsigned int nsect;
++      unsigned long flags;
++
++      /*
++       * (ks/hs): Handle last IRQ on multi-sector transfer,
++       * occurs after all data was sent in this chunk
++       */
++      if (rq->current_nr_sectors == 0) {
++              if (stat & (ERR_STAT|DRQ_STAT)) {
++                      if (!rq->bh) {
++                                rq->current_nr_sectors += drive->mult_count;
++                              /*
++                               * NOTE: could rewind beyond beginning :-/
++                               */
++                      } else {
++                              printk("%s: MULTI-WRITE assume all data " \
++                                      "transfered is bad status=0x%02x\n",
++                                      drive->name, stat);
++                      }
++                      return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
++              }
++              if (!rq->bh)
++                      DRIVER(drive)->end_request(drive, 1);
++              return startstop;
++      }
++      /*
++       * DON'T be lazy code the above and below togather !!!
++       */
++      if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
++              if (stat & (ERR_STAT|DRQ_STAT)) {
++                      if (!rq->bh) {
++                              rq->current_nr_sectors += drive->mult_count;
++                              /*
++                               * NOTE: could rewind beyond beginning :-/
++                               */
++                      } else {
++                              printk("%s: MULTI-WRITE assume all data " \
++                                      "transfered is bad status=0x%02x\n",
++                                      drive->name, stat);
++                      }
++                      return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
++              }
++              /* no data yet, so wait for another interrupt */
++              if (HWGROUP(drive)->handler == NULL)
++                      ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
++              return ide_started;
++      }
++
++      if (HWGROUP(drive)->handler != NULL) {
++              unsigned long lflags;
++              spin_lock_irqsave(&io_request_lock, lflags);
++              HWGROUP(drive)->handler = NULL;
++              del_timer(&HWGROUP(drive)->timer);
++              spin_unlock_irqrestore(&io_request_lock, lflags);
++      }
++
++#ifdef ALTSTAT_SCREW_UP
++      /*
++       * Screw the request we do not support bad data-phase setups!
++       * Either read and learn the ATA standard or crash yourself!
++       */
++      if (!msect) {
++              nsect = 1;
++              while (rq->current_nr_sectors) {
++                      pBuf = task_map_rq(rq, &flags);
++                      DTF("Multiwrite: %p, nsect: %d, " \
++                              "rq->current_nr_sectors: %d\n",
++                              pBuf, nsect, rq->current_nr_sectors);
++//                    rq->current_nr_sectors -= nsect;
++                      taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
++                      task_unmap_rq(pBuf, &flags);
++                      rq->errors = 0;
++                      rq->current_nr_sectors -= nsect;
++                      stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
++              }
++              DRIVER(drive)->end_request(drive, 1);
++              return ide_stopped;
++      }
++#endif /* ALTSTAT_SCREW_UP */
++
++      do {
++              nsect = rq->current_nr_sectors;
++              if (nsect > msect)
++                      nsect = msect;
++              pBuf = task_map_rq(rq, &flags);
++              DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
++                      "rq->current_nr_sectors: %ld\n",
++                      pBuf, nsect, msect, rq->current_nr_sectors);
++              msect -= nsect;
++//            rq->current_nr_sectors -= nsect;
++              taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
++              task_unmap_rq(rq, pBuf, &flags);
++              rq->current_nr_sectors -= nsect;
++              /*
++               * FIXME :: We really can not legally get a new page/bh
++               * regardless, if this is the end of our segment.
++               * BH walking or segment can only be updated after we
++               * have a good  GET_STAT(); return.
++               */
++              if (!rq->current_nr_sectors) {
++                      if (!DRIVER(drive)->end_request(drive, 1))
++                              if (!rq->bh)
++                                      return ide_stopped;
++              }
++      } while (msect);
++      rq->errors = 0;
++      if (HWGROUP(drive)->handler == NULL)
++              ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
++      return ide_started;
++}
++
++/* Called by internal to feature out type of command being called */
++ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
++{
++      switch(taskfile->command) {
++                              /* IDE_DRIVE_TASK_RAW_WRITE */
++              case CFA_WRITE_MULTI_WO_ERASE:
++      //      case WIN_WRITE_LONG:
++      //      case WIN_WRITE_LONG_ONCE:
++              case WIN_MULTWRITE:
++              case WIN_MULTWRITE_EXT:
++                      return &pre_task_mulout_intr;
++                      
++                              /* IDE_DRIVE_TASK_OUT */
++              case WIN_WRITE:
++      //      case WIN_WRITE_ONCE:
++              case WIN_WRITE_EXT:
++              case WIN_WRITE_VERIFY:
++              case WIN_WRITE_BUFFER:
++              case CFA_WRITE_SECT_WO_ERASE:
++              case WIN_DOWNLOAD_MICROCODE:
++                      return &pre_task_out_intr;
++                              /* IDE_DRIVE_TASK_OUT */
++              case WIN_SMART:
++                      if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
++                              return &pre_task_out_intr;
++              case WIN_WRITEDMA:
++      //      case WIN_WRITEDMA_ONCE:
++              case WIN_WRITEDMA_QUEUED:
++              case WIN_WRITEDMA_EXT:
++              case WIN_WRITEDMA_QUEUED_EXT:
++                              /* IDE_DRIVE_TASK_OUT */
++              default:
++                      break;
++      }
++      return(NULL);
++}
++
++/* Called by internal to feature out type of command being called */
++ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
++{
++      switch(taskfile->command) {
++              case WIN_IDENTIFY:
++              case WIN_PIDENTIFY:
++              case CFA_TRANSLATE_SECTOR:
++              case WIN_READ_BUFFER:
++              case WIN_READ:
++      //      case WIN_READ_ONCE:
++              case WIN_READ_EXT:
++                      return &task_in_intr;
++              case WIN_SECURITY_DISABLE:
++              case WIN_SECURITY_ERASE_UNIT:
++              case WIN_SECURITY_SET_PASS:
++              case WIN_SECURITY_UNLOCK:
++              case WIN_DOWNLOAD_MICROCODE:
++              case CFA_WRITE_SECT_WO_ERASE:
++              case WIN_WRITE_BUFFER:
++              case WIN_WRITE_VERIFY:
++              case WIN_WRITE:
++      //      case WIN_WRITE_ONCE:    
++              case WIN_WRITE_EXT:
++                      return &task_out_intr;
++      //      case WIN_READ_LONG:
++      //      case WIN_READ_LONG_ONCE:
++              case WIN_MULTREAD:
++              case WIN_MULTREAD_EXT:
++                      return &task_mulin_intr;
++      //      case WIN_WRITE_LONG:
++      //      case WIN_WRITE_LONG_ONCE:
++              case CFA_WRITE_MULTI_WO_ERASE:
++              case WIN_MULTWRITE:
++              case WIN_MULTWRITE_EXT:
++                      return &task_mulout_intr;
++              case WIN_SMART:
++                      switch(taskfile->feature) {
++                              case SMART_READ_VALUES:
++                              case SMART_READ_THRESHOLDS:
++                              case SMART_READ_LOG_SECTOR:
++                                      return &task_in_intr;
++                              case SMART_WRITE_LOG_SECTOR:
++                                      return &task_out_intr;
++                              default:
++                                      return &task_no_data_intr;
++                      }
++              case CFA_REQ_EXT_ERROR_CODE:
++              case CFA_ERASE_SECTORS:
++              case WIN_VERIFY:
++      //      case WIN_VERIFY_ONCE:
++              case WIN_VERIFY_EXT:
++              case WIN_SEEK:
++                      return &task_no_data_intr;
++              case WIN_SPECIFY:
++                      return &set_geometry_intr;
++              case WIN_RECAL:
++      //      case WIN_RESTORE:
++                      return &recal_intr;
++              case WIN_NOP:
++              case WIN_DIAGNOSE:
++              case WIN_FLUSH_CACHE:
++              case WIN_FLUSH_CACHE_EXT:
++              case WIN_STANDBYNOW1:
++              case WIN_STANDBYNOW2:
++              case WIN_SLEEPNOW1:
++              case WIN_SLEEPNOW2:
++              case WIN_SETIDLE1:
++              case WIN_CHECKPOWERMODE1:
++              case WIN_CHECKPOWERMODE2:
++              case WIN_GETMEDIASTATUS:
++              case WIN_MEDIAEJECT:
++                      return &task_no_data_intr;
++              case WIN_SETMULT:
++                      return &set_multmode_intr;
++              case WIN_READ_NATIVE_MAX:
++              case WIN_SET_MAX:
++              case WIN_READ_NATIVE_MAX_EXT:
++              case WIN_SET_MAX_EXT:
++              case WIN_SECURITY_ERASE_PREPARE:
++              case WIN_SECURITY_FREEZE_LOCK:
++              case WIN_DOORLOCK:
++              case WIN_DOORUNLOCK:
++              case WIN_SETFEATURES:
++                      return &task_no_data_intr;
++              case DISABLE_SEAGATE:
++              case EXABYTE_ENABLE_NEST:
++                      return &task_no_data_intr;
++#ifdef CONFIG_BLK_DEV_IDEDMA
++              case WIN_READDMA:
++      //      case WIN_READDMA_ONCE:
++              case WIN_IDENTIFY_DMA:
++              case WIN_READDMA_QUEUED:
++              case WIN_READDMA_EXT:
++              case WIN_READDMA_QUEUED_EXT:
++              case WIN_WRITEDMA:
++      //      case WIN_WRITEDMA_ONCE:
++              case WIN_WRITEDMA_QUEUED:
++              case WIN_WRITEDMA_EXT:
++              case WIN_WRITEDMA_QUEUED_EXT:
++#endif
++              case WIN_FORMAT:
++              case WIN_INIT:
++              case WIN_DEVICE_RESET:
++              case WIN_QUEUED_SERVICE:
++              case WIN_PACKETCMD:
++              default:
++                      return(NULL);
++      }       
++}
++
++ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
++{
++      switch(taskfile->command) {
++              case WIN_SPECIFY:       /* set_geometry_intr */
++              case WIN_RESTORE:       /* recal_intr */
++              case WIN_SETMULT:       /* set_multmode_intr */
++              default:
++                      return(NULL);
++      }
++}
++
++/* Called by ioctl to feature out type of command being called */
++int ide_cmd_type_parser (ide_task_t *args)
++{
++      struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
++      struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
++
++      args->prehandler        = ide_pre_handler_parser(taskfile, hobfile);
++      args->handler           = ide_handler_parser(taskfile, hobfile);
++      args->posthandler       = ide_post_handler_parser(taskfile, hobfile);
++
++      switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
++              case WIN_IDENTIFY:
++              case WIN_PIDENTIFY:
++                      return IDE_DRIVE_TASK_IN;
++              case CFA_TRANSLATE_SECTOR:
++              case WIN_READ:
++      //      case WIN_READ_ONCE:
++              case WIN_READ_EXT:
++              case WIN_READ_BUFFER:
++                      return IDE_DRIVE_TASK_IN;
++              case WIN_WRITE:
++      //      case WIN_WRITE_ONCE:
++              case WIN_WRITE_EXT:
++              case WIN_WRITE_VERIFY:
++              case WIN_WRITE_BUFFER:
++              case CFA_WRITE_SECT_WO_ERASE:
++              case WIN_DOWNLOAD_MICROCODE:
++                      return IDE_DRIVE_TASK_RAW_WRITE;
++      //      case WIN_READ_LONG:
++      //      case WIN_READ_LONG_ONCE:
++              case WIN_MULTREAD:
++              case WIN_MULTREAD_EXT:
++                      return IDE_DRIVE_TASK_IN;
++      //      case WIN_WRITE_LONG:
++      //      case WIN_WRITE_LONG_ONCE:
++              case CFA_WRITE_MULTI_WO_ERASE:
++              case WIN_MULTWRITE:
++              case WIN_MULTWRITE_EXT:
++                      return IDE_DRIVE_TASK_RAW_WRITE;
++              case WIN_SECURITY_DISABLE:
++              case WIN_SECURITY_ERASE_UNIT:
++              case WIN_SECURITY_SET_PASS:
++              case WIN_SECURITY_UNLOCK:
++                      return IDE_DRIVE_TASK_OUT;
++              case WIN_SMART:
++                      args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
++                      args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
++                      switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
++                              case SMART_READ_VALUES:
++                              case SMART_READ_THRESHOLDS:
++                              case SMART_READ_LOG_SECTOR:
++                                      return IDE_DRIVE_TASK_IN;
++                              case SMART_WRITE_LOG_SECTOR:
++                                      return IDE_DRIVE_TASK_OUT;
++                              default:
++                                      return IDE_DRIVE_TASK_NO_DATA;
++                      }
++#ifdef CONFIG_BLK_DEV_IDEDMA
++              case WIN_READDMA:
++      //      case WIN_READDMA_ONCE:
++              case WIN_IDENTIFY_DMA:
++              case WIN_READDMA_QUEUED:
++              case WIN_READDMA_EXT:
++              case WIN_READDMA_QUEUED_EXT:
++                      return IDE_DRIVE_TASK_IN;
++              case WIN_WRITEDMA:
++      //      case WIN_WRITEDMA_ONCE:
++              case WIN_WRITEDMA_QUEUED:
++              case WIN_WRITEDMA_EXT:
++              case WIN_WRITEDMA_QUEUED_EXT:
++                      return IDE_DRIVE_TASK_RAW_WRITE;
++#endif
++              case WIN_SETFEATURES:
++                      switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
++                              case SETFEATURES_EN_8BIT:
++                              case SETFEATURES_EN_WCACHE:
++                                      return IDE_DRIVE_TASK_NO_DATA;
++                              case SETFEATURES_XFER:
++                                      return IDE_DRIVE_TASK_SET_XFER;
++                              case SETFEATURES_DIS_DEFECT:
++                              case SETFEATURES_EN_APM:
++                              case SETFEATURES_DIS_MSN:
++                              case SETFEATURES_DIS_RETRY:
++                              case SETFEATURES_EN_AAM:
++                              case SETFEATURES_RW_LONG:
++                              case SETFEATURES_SET_CACHE:
++                              case SETFEATURES_DIS_RLA:
++                              case SETFEATURES_EN_RI:
++                              case SETFEATURES_EN_SI:
++                              case SETFEATURES_DIS_RPOD:
++                              case SETFEATURES_DIS_WCACHE:
++                              case SETFEATURES_EN_DEFECT:
++                              case SETFEATURES_DIS_APM:
++                              case SETFEATURES_EN_ECC:
++                              case SETFEATURES_EN_MSN:
++                              case SETFEATURES_EN_RETRY:
++                              case SETFEATURES_EN_RLA:
++                              case SETFEATURES_PREFETCH:
++                              case SETFEATURES_4B_RW_LONG:
++                              case SETFEATURES_DIS_AAM:
++                              case SETFEATURES_EN_RPOD:
++                              case SETFEATURES_DIS_RI:
++                              case SETFEATURES_DIS_SI:
++                              default:
++                                      return IDE_DRIVE_TASK_NO_DATA;
++                      }
++              case WIN_NOP:
++              case CFA_REQ_EXT_ERROR_CODE:
++              case CFA_ERASE_SECTORS:
++              case WIN_VERIFY:
++      //      case WIN_VERIFY_ONCE:
++              case WIN_VERIFY_EXT:
++              case WIN_SEEK:
++              case WIN_SPECIFY:
++              case WIN_RESTORE:
++              case WIN_DIAGNOSE:
++              case WIN_FLUSH_CACHE:
++              case WIN_FLUSH_CACHE_EXT:
++              case WIN_STANDBYNOW1:
++              case WIN_STANDBYNOW2:
++              case WIN_SLEEPNOW1:
++              case WIN_SLEEPNOW2:
++              case WIN_SETIDLE1:
++              case DISABLE_SEAGATE:
++              case WIN_CHECKPOWERMODE1:
++              case WIN_CHECKPOWERMODE2:
++              case WIN_GETMEDIASTATUS:
++              case WIN_MEDIAEJECT:
++              case WIN_SETMULT:
++              case WIN_READ_NATIVE_MAX:
++              case WIN_SET_MAX:
++              case WIN_READ_NATIVE_MAX_EXT:
++              case WIN_SET_MAX_EXT:
++              case WIN_SECURITY_ERASE_PREPARE:
++              case WIN_SECURITY_FREEZE_LOCK:
++              case EXABYTE_ENABLE_NEST:
++              case WIN_DOORLOCK:
++              case WIN_DOORUNLOCK:
++                      return IDE_DRIVE_TASK_NO_DATA;
++              case WIN_FORMAT:
++              case WIN_INIT:
++              case WIN_DEVICE_RESET:
++              case WIN_QUEUED_SERVICE:
++              case WIN_PACKETCMD:
++              default:
++                      return IDE_DRIVE_TASK_INVALID;
++      }
++}
++
++/*
++ * NOTICE: This is additions from IBM to provide a discrete interface,
++ * for selective taskregister access operations.  Nice JOB Klaus!!!
++ * Glad to be able to work and co-develop this with you and IBM.
++ */
++ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
++{
++      task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
++      hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
++      struct hd_driveid *id = drive->id;
++#if DEBUG_TASKFILE
++      byte status;
++#endif
++
++
++#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
++      void debug_taskfile(drive, task);
++#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
++
++      /*
++       * (ks) Check taskfile in/out flags.
++       * If set, then execute as it is defined.
++       * If not set, then define default settings.
++       * The default values are:
++       *      write and read all taskfile registers (except data) 
++       *      write and read the hob registers (sector,nsector,lcyl,hcyl)
++       */
++      if (task->tf_out_flags.all == 0) {
++              task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
++              if ((id->command_set_2 & 0x0400) &&
++                  (id->cfs_enable_2 & 0x0400) &&
++                  (drive->addressing == 1)) {
++                      task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
++              }
++        }
++
++      if (task->tf_in_flags.all == 0) {
++              task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
++              if ((id->command_set_2 & 0x0400) &&
++                  (id->cfs_enable_2 & 0x0400) &&
++                  (drive->addressing == 1)) {
++                      task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
++              }
++        }
++
++      /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
++      if (IDE_CONTROL_REG)
++              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
++      SELECT_MASK(HWIF(drive), drive, 0);
++
++#if DEBUG_TASKFILE
++      status = GET_STAT();
++      if (status & 0x80) {
++              printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
++              udelay(100);
++              status = GET_STAT();
++              printk("flagged_taskfile -> Status = %02x\n", status);
++      }
++#endif
++
++      if (task->tf_out_flags.b.data) {
++              unsigned short data =  taskfile->data + (hobfile->data << 8);
++              OUT_WORD(data, IDE_DATA_REG);
++      }
++
++      /* (ks) send hob registers first */
++      if (task->tf_out_flags.b.nsector_hob)
++              OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
++      if (task->tf_out_flags.b.sector_hob)
++              OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
++      if (task->tf_out_flags.b.lcyl_hob)
++              OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
++      if (task->tf_out_flags.b.hcyl_hob)
++              OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
++
++      /* (ks) Send now the standard registers */
++      if (task->tf_out_flags.b.error_feature)
++              OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
++      /* refers to number of sectors to transfer */
++      if (task->tf_out_flags.b.nsector)
++              OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
++      /* refers to sector offset or start sector */
++      if (task->tf_out_flags.b.sector)
++              OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
++      if (task->tf_out_flags.b.lcyl)
++              OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
++      if (task->tf_out_flags.b.hcyl)
++              OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
++
++        /*
++       * (ks) In the flagged taskfile approch, we will used all specified
++       * registers and the register value will not be changed. Except the
++       * select bit (master/slave) in the drive_head register. We must make
++       * sure that the desired drive is selected.
++       */
++      OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
++      switch(task->data_phase) {
++
++              case TASKFILE_OUT_DMAQ:
++              case TASKFILE_OUT_DMA:
++                      HWIF(drive)->dmaproc(ide_dma_write, drive);
++                      break;
++
++              case TASKFILE_IN_DMAQ:
++              case TASKFILE_IN_DMA:
++                      HWIF(drive)->dmaproc(ide_dma_read, drive);
++                      break;
++
++              default:
++                      if (task->handler == NULL)
++                              return ide_stopped;
++
++                      ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
++                      /* Issue the command */
++                      OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
++                      if (task->prehandler != NULL)
++                              return task->prehandler(drive, HWGROUP(drive)->rq);
++      }
++
++      return ide_started;
++}
++
++ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
++{
++      byte stat = GET_STAT();
++
++      local_irq_enable();
++
++      if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
++              if (stat & ERR_STAT) {
++                      return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
++              }
++              /*
++               * (ks) Unexpected ATA data phase detected.
++               * This should not happen. But, it can !
++               * I am not sure, which function is best to clean up
++               * this situation.  I choose: ide_error(...)
++               */
++              return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
++      }
++
++      ide_end_drive_cmd (drive, stat, GET_ERR());
++
++      return ide_stopped;
++}
++
++/*
++ * Handler for command with PIO data-in phase
++ */
++ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      int retries             = 5;
++
++      if (rq->current_nr_sectors == 0) 
++              return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
++
++      if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
++              if (stat & ERR_STAT) {
++                      return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
++              }
++              /*
++               * (ks) Unexpected ATA data phase detected.
++               * This should not happen. But, it can !
++               * I am not sure, which function is best to clean up
++               * this situation.  I choose: ide_error(...)
++               */
++              return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
++      }
++
++      pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
++      DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
++
++      taskfile_input_data(drive, pBuf, SECTOR_WORDS);
++
++      if (--rq->current_nr_sectors != 0) {
++              /*
++                 * (ks) We don't know which command was executed. 
++               * So, we wait the 'WORSTCASE' value.
++                 */
++              ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
++              return ide_started;
++      }
++      /*
++       * (ks) Last sector was transfered, wait until drive is ready. 
++       * This can take up to 10 usec. We willl wait max 50 us.
++       */
++      while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
++              udelay(10);
++      ide_end_drive_cmd (drive, stat, GET_ERR());
++
++      return ide_stopped;
++}
++
++ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      int retries             = 5;
++      unsigned int msect, nsect;
++
++      if (rq->current_nr_sectors == 0) 
++              return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
++
++      msect = drive->mult_count;
++      if (msect == 0) 
++              return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
++
++      if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
++              if (stat & ERR_STAT) {
++                      return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
++              }
++              /*
++               * (ks) Unexpected ATA data phase detected.
++               * This should not happen. But, it can !
++               * I am not sure, which function is best to clean up
++               * this situation.  I choose: ide_error(...)
++               */
++              return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
++      }
++
++      nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
++      pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
++
++      DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
++          pBuf, nsect, rq->current_nr_sectors);
++
++      taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
++
++      rq->current_nr_sectors -= nsect;
++      if (rq->current_nr_sectors != 0) {
++              /*
++                 * (ks) We don't know which command was executed. 
++               * So, we wait the 'WORSTCASE' value.
++                 */
++              ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
++              return ide_started;
++      }
++
++      /*
++       * (ks) Last sector was transfered, wait until drive is ready. 
++       * This can take up to 10 usec. We willl wait max 50 us.
++       */
++      while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
++              udelay(10);
++      ide_end_drive_cmd (drive, stat, GET_ERR());
++
++      return ide_stopped;
++}
++
++/*
++ * Pre handler for command with PIO data-out phase
++ */
++ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
++{
++      byte stat               = GET_STAT();
++      ide_startstop_t startstop;
++
++      if (!rq->current_nr_sectors) {
++              return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
++      }
++
++      if (ide_wait_stat(&startstop, drive, DATA_READY,
++                      BAD_W_STAT, WAIT_DRQ)) {
++              printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
++              return startstop;
++      }
++
++      taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
++      --rq->current_nr_sectors;
++
++      return ide_started;
++}
++
++ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++
++      if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
++              return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
++      
++      if (!rq->current_nr_sectors) { 
++              ide_end_drive_cmd (drive, stat, GET_ERR());
++              return ide_stopped;
++      }
++
++      if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
++              /*
++               * (ks) Unexpected ATA data phase detected.
++               * This should not happen. But, it can !
++               * I am not sure, which function is best to clean up
++               * this situation.  I choose: ide_error(...)
++               */
++              return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
++      }
++
++      pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
++      DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
++              (int) rq->current_nr_sectors, stat);
++
++      taskfile_output_data(drive, pBuf, SECTOR_WORDS);
++      --rq->current_nr_sectors;
++
++      /*
++       * (ks) We don't know which command was executed. 
++       * So, we wait the 'WORSTCASE' value.
++       */
++      ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
++
++      return ide_started;
++}
++
++ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
++{
++      byte stat               = GET_STAT();
++      char *pBuf              = NULL;
++      ide_startstop_t startstop;
++      unsigned int msect, nsect;
++
++      if (!rq->current_nr_sectors) 
++              return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
++
++      msect = drive->mult_count;
++      if (msect == 0)
++              return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
++
++      if (ide_wait_stat(&startstop, drive, DATA_READY,
++                      BAD_W_STAT, WAIT_DRQ)) {
++              printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
++              return startstop;
++      }
++
++      nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
++      pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
++      DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
++          pBuf, nsect, rq->current_nr_sectors);
++
++      taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
++
++      rq->current_nr_sectors -= nsect;
++
++      return ide_started;
++}
++
++ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
++{
++      byte stat               = GET_STAT();
++      struct request *rq      = HWGROUP(drive)->rq;
++      char *pBuf              = NULL;
++      unsigned int msect, nsect;
++
++      msect = drive->mult_count;
++      if (msect == 0)
++              return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
++
++      if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
++              return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
++      
++      if (!rq->current_nr_sectors) { 
++              ide_end_drive_cmd (drive, stat, GET_ERR());
++              return ide_stopped;
++      }
++
++      if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
++              /*
++               * (ks) Unexpected ATA data phase detected.
++               * This should not happen. But, it can !
++               * I am not sure, which function is best to clean up
++               * this situation.  I choose: ide_error(...)
++               */
++              return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
++      }
++
++      nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
++      pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
++      DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
++          pBuf, nsect, rq->current_nr_sectors);
++
++      taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
++      rq->current_nr_sectors -= nsect;
++
++      /*
++       * (ks) We don't know which command was executed. 
++       * So, we wait the 'WORSTCASE' value.
++       */
++      ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
++
++      return ide_started;
++}
++
++/*
++ * This function is intended to be used prior to invoking ide_do_drive_cmd().
++ */
++void ide_init_drive_taskfile (struct request *rq)
++{
++      memset(rq, 0, sizeof(*rq));
++      rq->cmd = IDE_DRIVE_TASK_NO_DATA;
++}
++
++int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, byte *buf)
++{
++      struct request rq;
++
++      ide_init_drive_taskfile(&rq);
++      rq.cmd = IDE_DRIVE_TASKFILE;
++      rq.buffer = buf;
++
++      /*
++       * (ks) We transfer currently only whole sectors.
++       * This is suffient for now.  But, it would be great,
++       * if we would find a solution to transfer any size.
++       * To support special commands like READ LONG.
++       */
++      if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
++              if (data_size == 0)
++                      rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
++              /*      rq.hard_cur_sectors     */
++              else
++                      rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
++              /*      rq.hard_cur_sectors     */
++      }
++
++      if (args->tf_out_flags.all == 0) {
++              /*
++               * clean up kernel settings for driver sanity, regardless.
++               * except for discrete diag services.
++               */
++              args->posthandler = ide_post_handler_parser(
++                              (struct hd_drive_task_hdr *) args->tfRegister,
++                              (struct hd_drive_hob_hdr *) args->hobRegister);
++
++      }
++      rq.special = args;
++      return ide_do_drive_cmd(drive, &rq, ide_wait);
++}
++
++int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
++{
++      return ide_diag_taskfile(drive, args, 0, buf);
++}
++      
++#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
++char * ide_ioctl_verbose (unsigned int cmd)
++{
++      return("unknown");
++}
++
++char * ide_task_cmd_verbose (byte task)
++{
++      return("unknown");
++}
++#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
++
++#define MAX_DMA               (256*SECTOR_WORDS)
++
++int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      ide_task_request_t      *req_task;
++      ide_task_t              args;
++      byte *outbuf            = NULL;
++      byte *inbuf             = NULL;
++      task_ioreg_t *argsptr   = args.tfRegister;
++      task_ioreg_t *hobsptr   = args.hobRegister;
++      int err                 = 0;
++      int tasksize            = sizeof(struct ide_task_request_s);
++      int taskin              = 0;
++      int taskout             = 0;
++      byte io_32bit           = drive->io_32bit;
++
++//    printk("IDE Taskfile ...\n");
++
++      req_task = kmalloc(tasksize, GFP_KERNEL);
++      if (req_task == NULL) return -ENOMEM;
++      memset(req_task, 0, tasksize);
++      if (copy_from_user(req_task, (void *) arg, tasksize)) {
++              kfree(req_task);
++              return -EFAULT;
++      }
++
++      taskout = (int) req_task->out_size;
++      taskin  = (int) req_task->in_size;
++
++      if (taskout) {
++              int outtotal = tasksize;
++              outbuf = kmalloc(taskout, GFP_KERNEL);
++              if (outbuf == NULL) {
++                      err = -ENOMEM;
++                      goto abort;
++              }
++              memset(outbuf, 0, taskout);
++              if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
++                      err = -EFAULT;
++                      goto abort;
++              }
++      }
++
++      if (taskin) {
++              int intotal = tasksize + taskout;
++              inbuf = kmalloc(taskin, GFP_KERNEL);
++              if (inbuf == NULL) {
++                      err = -ENOMEM;
++                      goto abort;
++              }
++              memset(inbuf, 0, taskin);
++              if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
++                      err = -EFAULT;
++                      goto abort;
++              }
++      }
++
++      memset (&args, 0, sizeof (ide_task_t) );
++      memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
++      memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
++
++      args.tf_in_flags  = req_task->in_flags;
++      args.tf_out_flags = req_task->out_flags;
++      args.data_phase   = req_task->data_phase;
++      args.command_type = req_task->req_cmd;
++
++#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
++      DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
++              drive->name,
++              ide_ioctl_verbose(cmd),
++              ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
++#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
++
++      drive->io_32bit = 0;
++      switch(req_task->data_phase) {
++              case TASKFILE_OUT_DMAQ:
++              case TASKFILE_OUT_DMA:
++                      err = ide_diag_taskfile(drive, &args, taskout, outbuf);
++                      break;
++              case TASKFILE_IN_DMAQ:
++              case TASKFILE_IN_DMA:
++                      err = ide_diag_taskfile(drive, &args, taskin, inbuf);
++                      break;
++              case TASKFILE_IN_OUT:
++#if 0
++                      args.prehandler = &pre_task_out_intr;
++                      args.handler = &task_out_intr;
++                      args.posthandler = NULL;
++                      err = ide_diag_taskfile(drive, &args, taskout, outbuf);
++                      args.prehandler = NULL;
++                      args.handler = &task_in_intr;
++                      args.posthandler = NULL;
++                      err = ide_diag_taskfile(drive, &args, taskin, inbuf);
++                      break;
++#else
++                      err = -EFAULT;
++                      goto abort;
++#endif
++              case TASKFILE_MULTI_OUT:
++                      if (!drive->mult_count) {
++                              /* (hs): give up if multcount is not set */
++                              printk("%s: %s Multimode Write " \
++                                      "multcount is not set\n",
++                                      drive->name, __FUNCTION__);
++                              err = -EPERM;
++                              goto abort;
++                      }
++                      if (args.tf_out_flags.all != 0) {
++                              args.prehandler = &flagged_pre_task_mulout_intr;
++                              args.handler = &flagged_task_mulout_intr;
++                      } else {
++                              args.prehandler = &pre_task_mulout_intr;
++                              args.handler = &task_mulout_intr;
++                      }
++                      err = ide_diag_taskfile(drive, &args, taskout, outbuf);
++                      break;
++              case TASKFILE_OUT:
++                      if (args.tf_out_flags.all != 0) {
++                              args.prehandler = &flagged_pre_task_out_intr;
++                              args.handler    = &flagged_task_out_intr;
++                      } else {
++                              args.prehandler = &pre_task_out_intr;
++                              args.handler = &task_out_intr;
++                      }
++                      err = ide_diag_taskfile(drive, &args, taskout, outbuf);
++                      break;
++              case TASKFILE_MULTI_IN:
++                      if (!drive->mult_count) {
++                              /* (hs): give up if multcount is not set */
++                              printk("%s: %s Multimode Read failure " \
++                                      "multcount is not set\n",
++                                      drive->name, __FUNCTION__);
++                              err = -EPERM;
++                              goto abort;
++                      }
++                      if (args.tf_out_flags.all != 0) {
++                              args.handler = &flagged_task_mulin_intr;
++                      } else {
++                              args.handler = &task_mulin_intr;
++                      }
++                      err = ide_diag_taskfile(drive, &args, taskin, inbuf);
++                      break;
++              case TASKFILE_IN:
++                      if (args.tf_out_flags.all != 0) {
++                              args.handler = &flagged_task_in_intr;
++                      } else {
++                              args.handler = &task_in_intr;
++                      }
++                      err = ide_diag_taskfile(drive, &args, taskin, inbuf);
++                      break;
++              case TASKFILE_NO_DATA:
++                      if (args.tf_out_flags.all != 0) {
++                              args.handler = &flagged_task_no_data_intr;
++                      } else {
++                              args.handler = &task_no_data_intr;
++                      }
++                      err = ide_diag_taskfile(drive, &args, 0, NULL);
++                      break;
++              default:
++                      err = -EFAULT;
++                      goto abort;
++      }
++
++      memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
++      memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
++      req_task->in_flags  = args.tf_in_flags;
++      req_task->out_flags = args.tf_out_flags;
++
++      if (copy_to_user((void *)arg, req_task, tasksize)) {
++              err = -EFAULT;
++              goto abort;
++      }
++      if (taskout) {
++              int outtotal = tasksize;
++              if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
++                      err = -EFAULT;
++                      goto abort;
++              }
++      }
++      if (taskin) {
++              int intotal = tasksize + taskout;
++              if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
++                      err = -EFAULT;
++                      goto abort;
++              }
++      }
++abort:
++      kfree(req_task);
++      if (outbuf != NULL)
++              kfree(outbuf);
++      if (inbuf != NULL)
++              kfree(inbuf);
++
++//    printk("IDE Taskfile ioctl ended. rc = %i\n", err);
++
++      drive->io_32bit = io_32bit;
++
++      return err;
++}
++
++int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
++int set_transfer(ide_drive_t *drive, ide_task_t *args);
++
++/*
++ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
++ */
++int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++#if 1
++      int err = 0;
++      byte args[4], *argbuf = args;
++      byte xfer_rate = 0;
++      int argsize = 4;
++      ide_task_t tfargs;
++
++      if (NULL == (void *) arg) {
++              struct request rq;
++              ide_init_drive_cmd(&rq);
++              return ide_do_drive_cmd(drive, &rq, ide_wait);
++      }
++
++      if (copy_from_user(args, (void *)arg, 4))
++              return -EFAULT;
++
++      memset(&tfargs, 0, sizeof(ide_task_t));
++      tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
++      tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
++      tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
++      tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
++      tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
++      tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
++      tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
++
++      if (args[3]) {
++              argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
++              argbuf = kmalloc(argsize, GFP_KERNEL);
++              if (argbuf == NULL)
++                      return -ENOMEM;
++              memcpy(argbuf, args, 4);
++      }
++      if (set_transfer(drive, &tfargs)) {
++              xfer_rate = args[1];
++              if (ide_ata66_check(drive, &tfargs))
++                      goto abort;
++      }
++
++      err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
++
++      if (!err && xfer_rate) {
++              /* active-retuning-calls future */
++              if ((HWIF(drive)->speedproc) != NULL)
++                      HWIF(drive)->speedproc(drive, xfer_rate);
++              ide_driveid_update(drive);
++      }
++abort:
++      if (copy_to_user((void *)arg, argbuf, argsize))
++              err = -EFAULT;
++      if (argsize > 4)
++              kfree(argbuf);
++      return err;
++
++#else
++
++      int err = 0;
++      byte args[4], *argbuf = args;
++      byte xfer_rate = 0;
++      int argsize = 0;
++      ide_task_t tfargs;
++
++      if (NULL == (void *) arg) {
++              struct request rq;
++              ide_init_drive_cmd(&rq);
++              return ide_do_drive_cmd(drive, &rq, ide_wait);
++      }
++
++      if (copy_from_user(args, (void *)arg, 4))
++              return -EFAULT;
++
++      memset(&tfargs, 0, sizeof(ide_task_t));
++      tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
++      tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
++      tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
++      tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
++      tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
++      tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
++      tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
++
++      if (args[3]) {
++              argsize = (SECTOR_WORDS * 4 * args[3]);
++              argbuf = kmalloc(argsize, GFP_KERNEL);
++              if (argbuf == NULL)
++                      return -ENOMEM;
++      }
++
++      if (set_transfer(drive, &tfargs)) {
++              xfer_rate = args[1];
++              if (ide_ata66_check(drive, &tfargs))
++                      goto abort;
++      }
++
++      tfargs.command_type = ide_cmd_type_parser(&tfargs);
++      err = ide_raw_taskfile(drive, &tfargs, argbuf);
++
++      if (!err && xfer_rate) {
++              /* active-retuning-calls future */
++              if ((HWIF(drive)->speedproc) != NULL)
++                      HWIF(drive)->speedproc(drive, xfer_rate);
++              ide_driveid_update(drive);
++      }
++abort:
++
++      args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
++      args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
++      args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
++      args[3] = 0;
++
++      if (copy_to_user((void *)arg, argbuf, 4))
++              err = -EFAULT;
++      if (argbuf != NULL) {
++              if (copy_to_user((void *)arg, argbuf + 4, argsize))
++                      err = -EFAULT;
++              kfree(argbuf);
++      }
++      return err;
++
++#endif
++
++}
++
++/*
++ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
++ */
++int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int err = 0;
++      byte args[7], *argbuf = args;
++      int argsize = 7;
++
++      if (copy_from_user(args, (void *)arg, 7))
++              return -EFAULT;
++      err = ide_wait_cmd_task(drive, argbuf);
++      if (copy_to_user((void *)arg, argbuf, argsize))
++              err = -EFAULT;
++      return err;
++}
++
++EXPORT_SYMBOL(drive_is_ready);
++EXPORT_SYMBOL(wait_for_ready);
++
++EXPORT_SYMBOL(task_read_24);
++EXPORT_SYMBOL(ata_input_data);
++EXPORT_SYMBOL(ata_output_data);
++EXPORT_SYMBOL(atapi_input_bytes);
++EXPORT_SYMBOL(atapi_output_bytes);
++EXPORT_SYMBOL(taskfile_input_data);
++EXPORT_SYMBOL(taskfile_output_data);
++
++EXPORT_SYMBOL(ide_wait_stat);
++EXPORT_SYMBOL(do_rw_taskfile);
++EXPORT_SYMBOL(flagged_taskfile);
++EXPORT_SYMBOL(ide_end_taskfile);
++
++EXPORT_SYMBOL(set_multmode_intr);
++EXPORT_SYMBOL(set_geometry_intr);
++EXPORT_SYMBOL(recal_intr);
++
++EXPORT_SYMBOL(task_no_data_intr);
++EXPORT_SYMBOL(task_in_intr);
++EXPORT_SYMBOL(task_mulin_intr);
++EXPORT_SYMBOL(pre_task_out_intr);
++EXPORT_SYMBOL(task_out_intr);
++EXPORT_SYMBOL(pre_task_mulout_intr);
++EXPORT_SYMBOL(task_mulout_intr);
++
++EXPORT_SYMBOL(ide_init_drive_taskfile);
++EXPORT_SYMBOL(ide_raw_taskfile);
++EXPORT_SYMBOL(ide_pre_handler_parser);
++EXPORT_SYMBOL(ide_handler_parser);
++EXPORT_SYMBOL(ide_post_handler_parser);
++EXPORT_SYMBOL(ide_cmd_type_parser);
++EXPORT_SYMBOL(ide_taskfile_ioctl);
++EXPORT_SYMBOL(ide_cmd_ioctl);
++EXPORT_SYMBOL(ide_task_ioctl);
++
++/*
++ * Beginning of Taskfile OPCODE Library and feature sets.
++ */
++
++/*
++ *  All hosts that use the 80c ribbon must use!
++ *  The name is derived from upper byte of word 93 and the 80c ribbon.
++ */
++byte eighty_ninty_three (ide_drive_t *drive)
++{
++#if 0
++      if (!HWIF(drive)->udma_four)
++              return 0;
++
++      if (drive->id->major_rev_num) {
++              int hssbd = 0;
++              int i;
++              /*
++               * Determime highest Supported SPEC
++               */
++              for (i=1; i<=15; i++)
++                      if (drive->id->major_rev_num & (1<<i))
++                              hssbd++;
++
++              switch (hssbd) {
++                      case 7:
++
++                      case 6:
++                      case 5:
++              /* ATA-4 and older do not support above Ultra 33 */
++                      default:
++                              return 0;
++              }
++      }
++
++      return ((byte) (
++#ifndef CONFIG_IDEDMA_IVB
++              (drive->id->hw_config & 0x4000) &&
++#endif /* CONFIG_IDEDMA_IVB */
++               (drive->id->hw_config & 0x6000)) ? 1 : 0);
++
++#else
++
++      return ((byte) ((HWIF(drive)->udma_four) &&
++#ifndef CONFIG_IDEDMA_IVB
++                      (drive->id->hw_config & 0x4000) &&
++#endif /* CONFIG_IDEDMA_IVB */
++                      (drive->id->hw_config & 0x6000)) ? 1 : 0);
++#endif
++}
++
++int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
++{
++      if (!HWIF(drive)->udma_four) {
++              printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n",
++                      HWIF(drive)->name);
++              return 1;
++      }
++      if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
++          (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
++          (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
++#ifndef CONFIG_IDEDMA_IVB
++              if ((drive->id->hw_config & 0x6000) == 0) {
++#else /* !CONFIG_IDEDMA_IVB */
++              if (((drive->id->hw_config & 0x2000) == 0) ||
++                  ((drive->id->hw_config & 0x4000) == 0)) {
++#endif /* CONFIG_IDEDMA_IVB */
++                      printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
++                      return 1;
++              }
++      }
++      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;
++}
++
++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 taskfile_lib_get_identify (ide_drive_t *drive, byte *buf)
++{
++      ide_task_t args;
++      memset(&args, 0, sizeof(ide_task_t));
++      args.tfRegister[IDE_NSECTOR_OFFSET]     = 0x01;
++      if (drive->media == ide_disk)
++              args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_IDENTIFY;
++      else
++              args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_PIDENTIFY;
++      args.command_type                       = ide_cmd_type_parser(&args);
++      return ide_raw_taskfile(drive, &args, buf);
++}
++
++/*
++ * Update the 
++ */
++int ide_driveid_update (ide_drive_t *drive)
++{
++#if 0
++      struct hd_driveid *id;
++
++      id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
++      if (!id)
++              return 0;
++
++      taskfile_lib_get_identify(drive, (char *)&id);
++
++      ide_fix_driveid(id);
++      if (id) {
++              drive->id->dma_ultra = id->dma_ultra;
++              drive->id->dma_mword = id->dma_mword;
++              drive->id->dma_1word = id->dma_1word;
++              /* anything more ? */
++              kfree(id);
++      }
++      return 1;
++#else
++      /*
++       * Re-read drive->id for possible DMA mode
++       * change (copied from ide-probe.c)
++       */
++      struct hd_driveid *id;
++      unsigned long timeout, flags;
++
++      SELECT_MASK(HWIF(drive), drive, 1);
++      if (IDE_CONTROL_REG)
++              OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
++      ide_delay_50ms();
++      OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
++      timeout = jiffies + WAIT_WORSTCASE;
++      do {
++              if (time_after(jiffies, timeout)) {
++                      SELECT_MASK(HWIF(drive), drive, 0);
++                      return 0;       /* drive timed-out */
++              }
++              ide_delay_50ms();       /* give drive a breather */
++      } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
++      ide_delay_50ms();       /* wait for IRQ and DRQ_STAT */
++      if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
++              SELECT_MASK(HWIF(drive), drive, 0);
++              printk("%s: CHECK for good STATUS\n", drive->name);
++              return 0;
++      }
++      local_irq_save(flags);
++      SELECT_MASK(HWIF(drive), drive, 0);
++      id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
++      if (!id) {
++              local_irq_restore(flags);
++              return 0;
++      }
++      ata_input_data(drive, id, SECTOR_WORDS);
++      (void) GET_STAT();      /* clear drive IRQ */
++      local_irq_enable();
++      local_irq_restore(flags);
++      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;
++#endif
++}
++
++
++/*
++ * Similar to ide_wait_stat(), except it never calls ide_error internally.
++ * This is a kludge to handle the new ide_config_drive_speed() function,
++ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
++ * should be updated to return ide_startstop_t, in which case we can get
++ * rid of this abomination again.  :)   -ml
++ *
++ * It is gone..........
++ *
++ * const char *msg == consider adding for verbose errors.
++ */
++int ide_config_drive_speed (ide_drive_t *drive, byte speed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++      int     i, error        = 1;
++      byte stat;
++
++#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
++      hwif->dmaproc(ide_dma_host_off, drive);
++#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
++
++      /*
++       * Don't use ide_wait_cmd here - it will
++       * attempt to set_geometry and recalibrate,
++       * but for some reason these don't work at
++       * this point (lost interrupt).
++       */
++        /*
++         * Select the drive, and issue the SETFEATURES command
++         */
++      disable_irq(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;
++              local_irq_set(flags);
++              timeout = jiffies + WAIT_CMD;
++              while ((stat = GET_STAT()) & BUSY_STAT) {
++                      if (time_after(jiffies, timeout))
++                              break;
++              }
++              local_irq_restore(flags);
++      }
++
++      /*
++       * Allow status to settle, then read it again.
++       * A few rare drives vastly violate the 400ns spec here,
++       * so we'll wait up to 10usec for a "good" status
++       * rather than expensively fail things immediately.
++       * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
++       */
++      for (i = 0; i < 10; i++) {
++              udelay(1);
++              if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
++                      error = 0;
++                      break;
++              }
++      }
++
++      SELECT_MASK(HWIF(drive), drive, 0);
++
++      enable_irq(hwif->irq);
++
++      if (error) {
++              (void) ide_dump_status(drive, "set_drive_speed_status", stat);
++              return error;
++      }
++
++      drive->id->dma_ultra &= ~0xFF00;
++      drive->id->dma_mword &= ~0x0F00;
++      drive->id->dma_1word &= ~0x0F00;
++
++#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
++      if (speed >= XFER_SW_DMA_0)
++              hwif->dmaproc(ide_dma_host_on, drive);
++#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
++
++      switch(speed) {
++              case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
++              case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
++              case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
++              case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
++              case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
++              case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
++              case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
++              case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
++              case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
++              case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
++              case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
++              case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
++              case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
++              case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
++              default: break;
++      }
++      if (!drive->init_speed)
++              drive->init_speed = speed;
++      drive->current_speed = speed;
++      return error;
++}
++
++EXPORT_SYMBOL(eighty_ninty_three);
++EXPORT_SYMBOL(ide_auto_reduce_xfer);
++EXPORT_SYMBOL(set_transfer);
++EXPORT_SYMBOL(taskfile_lib_get_identify);
++EXPORT_SYMBOL(ide_driveid_update);
++EXPORT_SYMBOL(ide_config_drive_speed);
++
++#ifdef CONFIG_PKT_TASK_IOCTL
++
++#if 0
++{
++
++{ /* start cdrom */
++
++      struct cdrom_info *info = drive->driver_data;
++
++      if (info->dma) {
++              if (info->cmd == READ) {
++                      info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
++              } else if (info->cmd == WRITE) {
++                      info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
++              } else {
++                      printk("ide-cd: DMA set, but not allowed\n");
++              }
++      }
++
++      /* Set up the controller registers. */
++      OUT_BYTE (info->dma, IDE_FEATURE_REG);
++      OUT_BYTE (0, IDE_NSECTOR_REG);
++      OUT_BYTE (0, IDE_SECTOR_REG);
++
++      OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
++      OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
++      if (IDE_CONTROL_REG)
++              OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
++
++      if (info->dma)
++              (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
++
++      if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
++              ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
++              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
++              return ide_started;
++      } else {
++              OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
++              return (*handler) (drive);
++      }
++
++} /* end cdrom */
++
++{ /* start floppy */
++
++      idefloppy_floppy_t *floppy = drive->driver_data;
++      idefloppy_bcount_reg_t bcount;
++      int dma_ok = 0;
++
++      floppy->pc=pc;          /* Set the current packet command */
++
++      pc->retries++;
++      pc->actually_transferred=0; /* We haven't transferred any data yet */
++      pc->current_position=pc->buffer;
++      bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
++              (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
++      }
++      if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
++              dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++      if (IDE_CONTROL_REG)
++              OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
++      OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);        /* Use PIO/DMA */
++      OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
++      OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
++      OUT_BYTE (drive->select.all,IDE_SELECT_REG);
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (dma_ok) {   /* Begin DMA, if necessary */
++              set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
++              (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
++      }
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++} /* end floppy */
++
++{ /* start tape */
++
++      idetape_tape_t *tape = drive->driver_data;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
++              printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
++              (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
++      }
++      if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
++              dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++      if (IDE_CONTROL_REG)
++              OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
++      OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);        /* Use PIO/DMA */
++      OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
++      OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
++      OUT_BYTE (drive->select.all,IDE_SELECT_REG);
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (dma_ok) {   /* Begin DMA, if necessary */
++              set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
++              (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
++      }
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++      if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
++              ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
++              return ide_started;
++      } else {
++              OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
++              return idetape_transfer_pc(drive);
++      }
++
++} /* end tape */
++
++}
++#endif
++
++int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++#if 0
++      switch(req_task->data_phase) {
++              case TASKFILE_P_OUT_DMAQ:
++              case TASKFILE_P_IN_DMAQ:
++              case TASKFILE_P_OUT_DMA:
++              case TASKFILE_P_IN_DMA:
++              case TASKFILE_P_OUT:
++              case TASKFILE_P_IN:
++      }
++#endif
++      return -ENOMSG;
++}
++
++EXPORT_SYMBOL(pkt_taskfile_ioctl);
++
++#endif /* CONFIG_PKT_TASK_IOCTL */
+diff -Nur linux.org/drivers/ide/ide-timing.h linux/drivers/ide/ide-timing.h
+--- linux.org/drivers/ide/ide-timing.h Sat Feb  3 20:27:43 2001
++++ linux/drivers/ide/ide-timing.h     Thu Jul 18 14:23:01 2002
+@@ -2,11 +2,9 @@
+ #define _IDE_TIMING_H
+ /*
+- * $Id$
++ * $Id$
+  *
+- *  Copyright (c) 1999-2000 Vojtech Pavlik
+- *
+- *  Sponsored by SuSE
++ *  Copyright (c) 1999-2001 Vojtech Pavlik
+  */
+ /*
+@@ -25,16 +23,14 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  *
+  * Should you need to contact me, the author, you can do so either by
+- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
++ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+  */
+ #include <linux/hdreg.h>
+-#ifndef XFER_PIO_5
+ #define XFER_PIO_5            0x0d
+ #define XFER_UDMA_SLOW                0x4f
+-#endif
+ struct ide_timing {
+       short mode;
+@@ -49,13 +45,15 @@
+ };
+ /*
+- * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds).
++ * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+  * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+- * for PIO 5, which is a nonstandard extension.
++ * for PIO 5, which is a nonstandard extension and UDMA6, which
++ * is currently supported only by Maxtor drives. 
+  */
+ static struct ide_timing ide_timing[] = {
++      { XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
+       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
+       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
+       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+@@ -105,6 +103,7 @@
+ #define EZ(v,unit)    ((v)?ENOUGH(v,unit):0)
+ #define XFER_MODE     0xf0
++#define XFER_UDMA_133 0x48
+ #define XFER_UDMA_100 0x44
+ #define XFER_UDMA_66  0x42
+ #define XFER_UDMA     0x40
+@@ -123,6 +122,9 @@
+       if ((map & XFER_UDMA) && (id->field_valid & 4)) {       /* Want UDMA and UDMA bitmap valid */
++              if ((map & XFER_UDMA_133) == XFER_UDMA_133)
++                      if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
++
+               if ((map & XFER_UDMA_100) == XFER_UDMA_100)
+                       if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
+@@ -174,14 +176,14 @@
+ static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
+ {
+-      q->setup   = EZ(t->setup,   T);
+-      q->act8b   = EZ(t->act8b,   T);
+-      q->rec8b   = EZ(t->rec8b,   T);
+-      q->cyc8b   = EZ(t->cyc8b,   T);
+-      q->active  = EZ(t->active,  T);
+-      q->recover = EZ(t->recover, T);
+-      q->cycle   = EZ(t->cycle,   T);
+-      q->udma    = EZ(t->udma,   UT);
++      q->setup   = EZ(t->setup   * 1000,  T);
++      q->act8b   = EZ(t->act8b   * 1000,  T);
++      q->rec8b   = EZ(t->rec8b   * 1000,  T);
++      q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
++      q->active  = EZ(t->active  * 1000,  T);
++      q->recover = EZ(t->recover * 1000,  T);
++      q->cycle   = EZ(t->cycle   * 1000,  T);
++      q->udma    = EZ(t->udma    * 1000, UT);
+ }
+ static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what)
+diff -Nur linux.org/drivers/ide/ide.c linux/drivers/ide/ide.c
+--- linux.org/drivers/ide/ide.c        Mon Feb 25 20:37:57 2002
++++ linux/drivers/ide/ide.c    Thu Jul 18 14:24:33 2002
+@@ -149,6 +149,7 @@
+ #include <linux/ide.h>
+ #include <linux/devfs_fs_kernel.h>
+ #include <linux/completion.h>
++#include <linux/reboot.h>
+ #include <asm/byteorder.h>
+ #include <asm/irq.h>
+@@ -206,13 +207,12 @@
+       unsigned long t, flags;
+       int i;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       t = jiffies * 11932;
+       outb_p(0, 0x43);
+       i = inb_p(0x40);
+-      i |= inb(0x40) << 8;
+-      __restore_flags(flags); /* local CPU only */
++      i |= IN_BYTE(0x40) << 8;
++      local_irq_restore(flags);
+       return (t - i);
+ }
+ #endif /* DISK_RECOVERY_TIME */
+@@ -362,197 +362,17 @@
+       return system_bus_speed;
+ }
+-#if SUPPORT_VLB_SYNC
+-/*
+- * Some localbus EIDE interfaces require a special access sequence
+- * when using 32-bit I/O instructions to transfer data.  We call this
+- * the "vlb_sync" sequence, which consists of three successive reads
+- * of the sector count register location, with interrupts disabled
+- * to ensure that the reads all happen together.
+- */
+-static inline void do_vlb_sync (ide_ioreg_t port) {
+-      (void) inb (port);
+-      (void) inb (port);
+-      (void) inb (port);
+-}
+-#endif /* SUPPORT_VLB_SYNC */
+-
+-/*
+- * This is used for most PIO data transfers *from* the IDE interface
+- */
+-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+-{
+-      byte io_32bit;
+-
+-      /* first check if this controller has defined a special function
+-       * for handling polled ide transfers
+-       */
+-
+-      if(HWIF(drive)->ideproc) {
+-              HWIF(drive)->ideproc(ideproc_ide_input_data,
+-                                   drive, buffer, wcount);
+-              return;
+-      }
+-
+-      io_32bit = drive->io_32bit;
+-
+-      if (io_32bit) {
+-#if SUPPORT_VLB_SYNC
+-              if (io_32bit & 2) {
+-                      unsigned long flags;
+-                      __save_flags(flags);    /* local CPU only */
+-                      __cli();                /* local CPU only */
+-                      do_vlb_sync(IDE_NSECTOR_REG);
+-                      insl(IDE_DATA_REG, buffer, wcount);
+-                      __restore_flags(flags); /* local CPU only */
+-              } else
+-#endif /* SUPPORT_VLB_SYNC */
+-                      insl(IDE_DATA_REG, buffer, wcount);
+-      } else {
+-#if SUPPORT_SLOW_DATA_PORTS
+-              if (drive->slow) {
+-                      unsigned short *ptr = (unsigned short *) buffer;
+-                      while (wcount--) {
+-                              *ptr++ = inw_p(IDE_DATA_REG);
+-                              *ptr++ = inw_p(IDE_DATA_REG);
+-                      }
+-              } else
+-#endif /* SUPPORT_SLOW_DATA_PORTS */
+-                      insw(IDE_DATA_REG, buffer, wcount<<1);
+-      }
+-}
+-
+-/*
+- * This is used for most PIO data transfers *to* the IDE interface
+- */
+-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+-{
+-      byte io_32bit;
+-
+-      if(HWIF(drive)->ideproc) {
+-              HWIF(drive)->ideproc(ideproc_ide_output_data,
+-                                   drive, buffer, wcount);
+-              return;
+-      }
+-
+-      io_32bit = drive->io_32bit;
+-
+-      if (io_32bit) {
+-#if SUPPORT_VLB_SYNC
+-              if (io_32bit & 2) {
+-                      unsigned long flags;
+-                      __save_flags(flags);    /* local CPU only */
+-                      __cli();                /* local CPU only */
+-                      do_vlb_sync(IDE_NSECTOR_REG);
+-                      outsl(IDE_DATA_REG, buffer, wcount);
+-                      __restore_flags(flags); /* local CPU only */
+-              } else
+-#endif /* SUPPORT_VLB_SYNC */
+-                      outsl(IDE_DATA_REG, buffer, wcount);
+-      } else {
+-#if SUPPORT_SLOW_DATA_PORTS
+-              if (drive->slow) {
+-                      unsigned short *ptr = (unsigned short *) buffer;
+-                      while (wcount--) {
+-                              outw_p(*ptr++, IDE_DATA_REG);
+-                              outw_p(*ptr++, IDE_DATA_REG);
+-                      }
+-              } else
+-#endif /* SUPPORT_SLOW_DATA_PORTS */
+-                      outsw(IDE_DATA_REG, buffer, wcount<<1);
+-      }
+-}
+-
+-/*
+- * The following routines are mainly used by the ATAPI drivers.
+- *
+- * These routines will round up any request for an odd number of bytes,
+- * so if an odd bytecount is specified, be sure that there's at least one
+- * extra byte allocated for the buffer.
+- */
+-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+-{
+-      if(HWIF(drive)->ideproc) {
+-              HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
+-                                   drive, buffer, bytecount);
+-              return;
+-      }
+-
+-      ++bytecount;
+-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+-      if (MACH_IS_ATARI || MACH_IS_Q40) {
+-              /* Atari has a byte-swapped IDE interface */
+-              insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+-              return;
+-      }
+-#endif /* CONFIG_ATARI */
+-      ide_input_data (drive, buffer, bytecount / 4);
+-      if ((bytecount & 0x03) >= 2)
+-              insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+-}
+-
+-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+-{
+-      if(HWIF(drive)->ideproc) {
+-              HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
+-                                   drive, buffer, bytecount);
+-              return;
+-      }
+-
+-      ++bytecount;
+-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+-      if (MACH_IS_ATARI || MACH_IS_Q40) {
+-              /* Atari has a byte-swapped IDE interface */
+-              outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+-              return;
+-      }
+-#endif /* CONFIG_ATARI */
+-      ide_output_data (drive, buffer, bytecount / 4);
+-      if ((bytecount & 0x03) >= 2)
+-              outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+-}
+-
+-/*
+- * Needed for PCI irq sharing
+- */
+-static inline int drive_is_ready (ide_drive_t *drive)
+-{
+-      byte stat = 0;
+-      if (drive->waiting_for_dma)
+-              return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+-#if 0
+-      udelay(1);      /* need to guarantee 400ns since last command was issued */
+-#endif
+-
+-#ifdef CONFIG_IDEPCI_SHARE_IRQ
+-      /*
+-       * We do a passive status test under shared PCI interrupts on
+-       * cards that truly share the ATA side interrupt, but may also share
+-       * an interrupt with another pci card/device.  We make no assumptions
+-       * about possible isa-pnp and pci-pnp issues yet.
+-       */
+-      if (IDE_CONTROL_REG)
+-              stat = GET_ALTSTAT();
+-      else
+-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+-      stat = GET_STAT();      /* Note: this may clear a pending IRQ!! */
+-
+-      if (stat & BUSY_STAT)
+-              return 0;       /* drive busy:  definitely not interrupting */
+-      return 1;               /* drive ready: *might* be interrupting */
+-}
+-
+ /*
+  * This is our end_request replacement function.
+  */
+-void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
++int ide_end_request (ide_drive_t *drive, int uptodate)
+ {
+       struct request *rq;
+       unsigned long flags;
+-      ide_drive_t *drive = hwgroup->drive;
++      int ret = 1;
+       spin_lock_irqsave(&io_request_lock, flags);
+-      rq = hwgroup->rq;
++      rq = HWGROUP(drive)->rq;
+       /*
+        * decide whether to reenable DMA -- 3 is a random magic for now,
+@@ -560,16 +380,18 @@
+        */
+       if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+               drive->state = 0;
+-              hwgroup->hwif->dmaproc(ide_dma_on, drive);
++              HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+       }
+-      if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
++      if (!end_that_request_first(rq, uptodate, drive->name)) {
+               add_blkdev_randomness(MAJOR(rq->rq_dev));
+               blkdev_dequeue_request(rq);
+-              hwgroup->rq = NULL;
++              HWGROUP(drive)->rq = NULL;
+               end_that_request_last(rq);
++              ret = 0;
+       }
+       spin_unlock_irqrestore(&io_request_lock, flags);
++      return ret;
+ }
+ /*
+@@ -654,7 +476,9 @@
+       if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
+               printk("%s: ATAPI reset complete\n", drive->name);
+       } else {
+-              if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
++              if (time_before(jiffies, hwgroup->poll_timeout)) {
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
+                       return ide_started;     /* continue polling */
+               }
+@@ -679,7 +503,9 @@
+       byte tmp;
+       if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
+-              if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
++              if (time_before(jiffies, hwgroup->poll_timeout)) {
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+                       return ide_started;     /* continue polling */
+               }
+@@ -772,8 +598,7 @@
+       ide_hwif_t *hwif = HWIF(drive);
+       ide_hwgroup_t *hwgroup = HWGROUP(drive);
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       /* For an ATAPI device, first try an ATAPI SRST. */
+       if (drive->media != ide_disk && !do_not_try_atapi) {
+@@ -782,8 +607,10 @@
+               udelay (20);
+               OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+               hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
+-              __restore_flags (flags);        /* local CPU only */
++              local_irq_restore(flags);
+               return ide_started;
+       }
+@@ -796,7 +623,7 @@
+ #if OK_TO_RESET_CONTROLLER
+       if (!IDE_CONTROL_REG) {
+-              __restore_flags(flags);
++              local_irq_restore(flags);
+               return ide_stopped;
+       }
+       /*
+@@ -809,9 +636,15 @@
+        */
+       OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
+       udelay(10);                     /* more than enough time */
+-      OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
++      if (drive->quirk_list == 2) {
++              OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* clear SRST and nIEN */
++      } else {
++              OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
++      }
+       udelay(10);                     /* more than enough time */
+       hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
+       ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+       /*
+@@ -824,7 +657,7 @@
+ #endif        /* OK_TO_RESET_CONTROLLER */
+-      __restore_flags (flags);        /* local CPU only */
++      local_irq_restore(flags);
+       return ide_started;
+ }
+@@ -836,6 +669,13 @@
+       return do_reset1 (drive, 0);
+ }
++static inline u32 read_24 (ide_drive_t *drive)
++{
++      return  (IN_BYTE(IDE_HCYL_REG)<<16) |
++              (IN_BYTE(IDE_LCYL_REG)<<8) |
++               IN_BYTE(IDE_SECTOR_REG);
++}
++
+ /*
+  * Clean up after success/failure of an explicit drive cmd
+  */
+@@ -848,26 +688,72 @@
+       rq = HWGROUP(drive)->rq;
+       spin_unlock_irqrestore(&io_request_lock, flags);
+-      if (rq->cmd == IDE_DRIVE_CMD) {
+-              byte *args = (byte *) rq->buffer;
+-              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+-              if (args) {
+-                      args[0] = stat;
+-                      args[1] = err;
+-                      args[2] = IN_BYTE(IDE_NSECTOR_REG);
+-              }
+-      } else if (rq->cmd == IDE_DRIVE_TASK) {
+-              byte *args = (byte *) rq->buffer;
+-              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+-              if (args) {
+-                      args[0] = stat;
+-                      args[1] = err;
+-                      args[2] = IN_BYTE(IDE_NSECTOR_REG);
+-                      args[3] = IN_BYTE(IDE_SECTOR_REG);
+-                      args[4] = IN_BYTE(IDE_LCYL_REG);
+-                      args[5] = IN_BYTE(IDE_HCYL_REG);
+-                      args[6] = IN_BYTE(IDE_SELECT_REG);
++      switch(rq->cmd) {
++              case IDE_DRIVE_CMD:
++              {
++                      byte *args = (byte *) rq->buffer;
++                      if (rq->errors == 0)
++                              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
++
++                      if (args) {
++                              args[0] = stat;
++                              args[1] = err;
++                              args[2] = IN_BYTE(IDE_NSECTOR_REG);
++                      }
++                      break;
+               }
++              case IDE_DRIVE_TASK:
++              {
++                      byte *args = (byte *) rq->buffer;
++                      if (rq->errors == 0)
++                              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
++
++                      if (args) {
++                              args[0] = stat;
++                              args[1] = err;
++                              args[2] = IN_BYTE(IDE_NSECTOR_REG);
++                              args[3] = IN_BYTE(IDE_SECTOR_REG);
++                              args[4] = IN_BYTE(IDE_LCYL_REG);
++                              args[5] = IN_BYTE(IDE_HCYL_REG);
++                              args[6] = IN_BYTE(IDE_SELECT_REG);
++                      }
++                      break;
++              }
++              case IDE_DRIVE_TASKFILE:
++              {
++                      ide_task_t *args = (ide_task_t *) rq->special;
++                      if (rq->errors == 0)
++                              rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
++                              
++                      if (args) {
++                              if (args->tf_in_flags.b.data) {
++                                      unsigned short data                     = IN_WORD(IDE_DATA_REG);
++                                      args->tfRegister[IDE_DATA_OFFSET]       = (data) & 0xFF;
++                                      args->hobRegister[IDE_DATA_OFFSET_HOB]  = (data >> 8) & 0xFF;
++                              }
++                              args->tfRegister[IDE_ERROR_OFFSET]   = err;
++                              args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
++                              args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
++                              args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
++                              args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
++                              args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
++                              args->tfRegister[IDE_STATUS_OFFSET]  = stat;
++
++                              if ((drive->id->command_set_2 & 0x0400) &&
++                                  (drive->id->cfs_enable_2 & 0x0400) &&
++                                  (drive->addressing == 1)) {
++                                      OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
++                                      args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
++                                      args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
++                                      args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
++                                      args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
++                                      args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
++                              }
++                      }
++                      break;
++              }
++              default:
++                      break;
+       }
+       spin_lock_irqsave(&io_request_lock, flags);
+       blkdev_dequeue_request(rq);
+@@ -884,8 +770,7 @@
+       unsigned long flags;
+       byte err = 0;
+-      __save_flags (flags);   /* local CPU only */
+-      ide__sti();             /* local CPU only */
++      local_irq_set(flags);
+       printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+ #if FANCY_STATUS_DUMPS
+       printk(" { ");
+@@ -917,19 +802,34 @@
+                       if (err & MARK_ERR)     printk("AddrMarkNotFound ");
+                       printk("}");
+                       if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+-                              byte cur = IN_BYTE(IDE_SELECT_REG);
+-                              if (cur & 0x40) {       /* using LBA? */
+-                                      printk(", LBAsect=%ld", (unsigned long)
+-                                       ((cur&0xf)<<24)
+-                                       |(IN_BYTE(IDE_HCYL_REG)<<16)
+-                                       |(IN_BYTE(IDE_LCYL_REG)<<8)
+-                                       | IN_BYTE(IDE_SECTOR_REG));
++                              if ((drive->id->command_set_2 & 0x0400) &&
++                                  (drive->id->cfs_enable_2 & 0x0400) &&
++                                  (drive->addressing == 1)) {
++                                      __u64 sectors = 0;
++                                      u32 low = 0, high = 0;
++                                      low = read_24(drive);
++                                      OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
++                                      high = read_24(drive);
++
++                                      sectors = ((__u64)high << 24) | low;
++                                      printk(", LBAsect=%llu, high=%d, low=%d",
++                                             (unsigned long long) sectors,
++                                             high, low);
+                               } else {
+-                                      printk(", CHS=%d/%d/%d",
+-                                       (IN_BYTE(IDE_HCYL_REG)<<8) +
+-                                        IN_BYTE(IDE_LCYL_REG),
+-                                        cur & 0xf,
+-                                        IN_BYTE(IDE_SECTOR_REG));
++                                      byte cur = IN_BYTE(IDE_SELECT_REG);
++                                      if (cur & 0x40) {       /* using LBA? */
++                                              printk(", LBAsect=%ld", (unsigned long)
++                                               ((cur&0xf)<<24)
++                                               |(IN_BYTE(IDE_HCYL_REG)<<16)
++                                               |(IN_BYTE(IDE_LCYL_REG)<<8)
++                                               | IN_BYTE(IDE_SECTOR_REG));
++                                      } else {
++                                              printk(", CHS=%d/%d/%d",
++                                               (IN_BYTE(IDE_HCYL_REG)<<8) +
++                                                IN_BYTE(IDE_LCYL_REG),
++                                                cur & 0xf,
++                                                IN_BYTE(IDE_SECTOR_REG));
++                                      }
+                               }
+                               if (HWGROUP(drive) && HWGROUP(drive)->rq)
+                                       printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+@@ -938,7 +838,7 @@
+ #endif        /* FANCY_STATUS_DUMPS */
+               printk("\n");
+       }
+-      __restore_flags (flags);        /* local CPU only */
++      local_irq_restore(flags);
+       return err;
+ }
+@@ -959,11 +859,15 @@
+               u32 buffer[16];
+               unsigned int wcount = (i > 16) ? 16 : i;
+               i -= wcount;
+-              ide_input_data (drive, buffer, wcount);
++              ata_input_data (drive, buffer, wcount);
+       }
+ }
+ /*
++ * FIXME Add an ATAPI error
++ */
++
++/*
+  * ide_error() takes action based on the error returned by the drive.
+  */
+ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
+@@ -980,9 +884,18 @@
+               ide_end_drive_cmd(drive, stat, err);
+               return ide_stopped;
+       }
++      if (rq->cmd == IDE_DRIVE_TASKFILE) {
++              rq->errors = 1;
++              ide_end_drive_cmd(drive, stat, err);
++//            ide_end_taskfile(drive, stat, err);
++              return ide_stopped;
++      }
++
+       if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+               rq->errors |= ERROR_RESET;
+       } else {
++
++/* ide_disk */
+               if (drive->media == ide_disk && (stat & ERR_STAT)) {
+                       /* err has different meaning on cdrom and tape */
+                       if (err == ABRT_ERR) {
+@@ -995,17 +908,19 @@
+                       else if (err & TRK0_ERR)        /* help it find track zero */
+                               rq->errors |= ERROR_RECAL;
+               }
++/* !ide_disk */
+               if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+                       try_to_flush_leftover_data(drive);
++/* !ide_disk */
+       }
+       if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+               OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);    /* force an abort */
+       if (rq->errors >= ERROR_MAX) {
+               if (drive->driver != NULL)
+-                      DRIVER(drive)->end_request(0, HWGROUP(drive));
++                      DRIVER(drive)->end_request(drive, 0);
+               else
+-                      ide_end_request(0, HWGROUP(drive));
++                      ide_end_request(drive, 0);
+       } else {
+               if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+                       ++rq->errors;
+@@ -1024,6 +939,8 @@
+  */
+ void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+ {
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
+       ide_set_handler (drive, handler, WAIT_CMD, NULL);
+       if (IDE_CONTROL_REG)
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* clear nIEN */
+@@ -1042,18 +959,18 @@
+       byte stat = GET_STAT();
+       int retries = 10;
+-      ide__sti();     /* local CPU only */
++      local_irq_enable();
+       if ((stat & DRQ_STAT) && args && args[3]) {
+               byte io_32bit = drive->io_32bit;
+               drive->io_32bit = 0;
+-              ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
++              ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+               drive->io_32bit = io_32bit;
+               while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+                       udelay(100);
+       }
+       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+-              return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
++              return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+       ide_end_drive_cmd (drive, stat, GET_ERR());
+       return ide_stopped;
+ }
+@@ -1070,10 +987,9 @@
+       printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+ #endif
+       if (s->b.set_tune) {
+-              ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+               s->b.set_tune = 0;
+-              if (tuneproc != NULL)
+-                      tuneproc(drive, drive->tune_req);
++              if (HWIF(drive)->tuneproc != NULL)
++                      HWIF(drive)->tuneproc(drive, drive->tune_req);
+       } else if (drive->driver != NULL) {
+               return DRIVER(drive)->special(drive);
+       } else if (s->all) {
+@@ -1084,132 +1000,120 @@
+ }
+ /*
+- * This routine busy-waits for the drive status to be not "busy".
+- * It then checks the status for all of the "good" bits and none
+- * of the "bad" bits, and if all is okay it returns 0.  All other
+- * cases return 1 after invoking ide_error() -- caller should just return.
+- *
+- * This routine should get fixed to not hog the cpu during extra long waits..
+- * That could be done by busy-waiting for the first jiffy or two, and then
+- * setting a timer to wake up at half second intervals thereafter,
+- * until timeout is achieved, before timing out.
+- */
+-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
+-      byte stat;
+-      int i;
+-      unsigned long flags;
+- 
+-      /* bail early if we've exceeded max_failures */
+-      if (drive->max_failures && (drive->failures > drive->max_failures)) {
+-              *startstop = ide_stopped;
+-              return 1;
+-      }
+-
+-      udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
+-      if ((stat = GET_STAT()) & BUSY_STAT) {
+-              __save_flags(flags);    /* local CPU only */
+-              ide__sti();             /* local CPU only */
+-              timeout += jiffies;
+-              while ((stat = GET_STAT()) & BUSY_STAT) {
+-                      if (0 < (signed long)(jiffies - timeout)) {
+-                              __restore_flags(flags); /* local CPU only */
+-                              *startstop = ide_error(drive, "status timeout", stat);
+-                              return 1;
+-                      }
+-              }
+-              __restore_flags(flags); /* local CPU only */
+-      }
+-      /*
+-       * Allow status to settle, then read it again.
+-       * A few rare drives vastly violate the 400ns spec here,
+-       * so we'll wait up to 10usec for a "good" status
+-       * rather than expensively fail things immediately.
+-       * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+-       */
+-      for (i = 0; i < 10; i++) {
+-              udelay(1);
+-              if (OK_STAT((stat = GET_STAT()), good, bad))
+-                      return 0;
+-      }
+-      *startstop = ide_error(drive, "status error", stat);
+-      return 1;
+-}
+-
+-/*
+  * execute_drive_cmd() issues a special drive command,
+  * usually initiated by ioctl() from the external hdparm program.
+  */
+ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+ {
+-      byte *args = rq->buffer;
+-      if (args && rq->cmd == IDE_DRIVE_TASK) {
+-              byte sel;
++      switch(rq->cmd) {
++              case IDE_DRIVE_TASKFILE:
++              {
++                      ide_task_t *args = rq->special;
++ 
++                      if (!(args)) break;
++ 
++                      if (args->tf_out_flags.all != 0) 
++                              return flagged_taskfile(drive, args);
++                      return do_rw_taskfile(drive, args);
++              }
++              case IDE_DRIVE_TASK:
++              {
++                      byte *args = rq->buffer;
++                      byte sel;
++ 
++                      if (!(args)) break;
+ #ifdef DEBUG
+-              printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
+-                      drive->name,
+-                      args[0], args[1], args[2], args[3],
+-                      args[4], args[5], args[6], args[7]);
++                      printk("%s: DRIVE_TASK_CMD ", drive->name);
++                      printk("cmd=0x%02x ", args[0]);
++                      printk("fr=0x%02x ", args[1]);
++                      printk("ns=0x%02x ", args[2]);
++                      printk("sc=0x%02x ", args[3]);
++                      printk("lcyl=0x%02x ", args[4]);
++                      printk("hcyl=0x%02x ", args[5]);
++                      printk("sel=0x%02x\n", args[6]);
+ #endif
+-              OUT_BYTE(args[1], IDE_FEATURE_REG);
+-              OUT_BYTE(args[3], IDE_SECTOR_REG);
+-              OUT_BYTE(args[4], IDE_LCYL_REG);
+-              OUT_BYTE(args[5], IDE_HCYL_REG);
+-              sel = (args[6] & ~0x10);
+-              if (drive->select.b.unit)
+-                      sel |= 0x10;
+-              OUT_BYTE(sel, IDE_SELECT_REG);
+-              ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+-              return ide_started;
+-      } else if (args) {
++                      OUT_BYTE(args[1], IDE_FEATURE_REG);
++                      OUT_BYTE(args[3], IDE_SECTOR_REG);
++                      OUT_BYTE(args[4], IDE_LCYL_REG);
++                      OUT_BYTE(args[5], IDE_HCYL_REG);
++                      sel = (args[6] & ~0x10);
++                      if (drive->select.b.unit)
++                              sel |= 0x10;
++                      OUT_BYTE(sel, IDE_SELECT_REG);
++                      ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
++                      return ide_started;
++              }
++              case IDE_DRIVE_CMD:
++              {
++                      byte *args = rq->buffer;
++ 
++                      if (!(args)) break;
+ #ifdef DEBUG
+-              printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
+-               drive->name, args[0], args[1], args[2], args[3]);
++                      printk("%s: DRIVE_CMD ", drive->name);
++                      printk("cmd=0x%02x ", args[0]);
++                      printk("sc=0x%02x ", args[1]);
++                      printk("fr=0x%02x ", args[2]);
++                      printk("xx=0x%02x\n", args[3]);
+ #endif
+-              if (args[0] == WIN_SMART) {
+-                      OUT_BYTE(0x4f, IDE_LCYL_REG);
+-                      OUT_BYTE(0xc2, IDE_HCYL_REG);
+-                      OUT_BYTE(args[2],IDE_FEATURE_REG);
+-                      OUT_BYTE(args[1],IDE_SECTOR_REG);
+-                      ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+-                      return ide_started;
+-              }
+-              OUT_BYTE(args[2],IDE_FEATURE_REG);
+-              ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+-              return ide_started;
+-      } else {
+-              /*
+-               * NULL is actually a valid way of waiting for
+-               * all current requests to be flushed from the queue.
+-               */
++                      if (args[0] == WIN_SMART) {
++                              OUT_BYTE(0x4f, IDE_LCYL_REG);
++                              OUT_BYTE(0xc2, IDE_HCYL_REG);
++                              OUT_BYTE(args[2],IDE_FEATURE_REG);
++                              OUT_BYTE(args[1],IDE_SECTOR_REG);
++                              ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
++                              return ide_started;
++                      }
++                      OUT_BYTE(args[2],IDE_FEATURE_REG);
++                      ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
++                      return ide_started;
++              }
++              default:
++                      break;
++      }
++      /*
++       * NULL is actually a valid way of waiting for
++       * all current requests to be flushed from the queue.
++       */
+ #ifdef DEBUG
+-              printk("%s: DRIVE_CMD (null)\n", drive->name);
++      printk("%s: DRIVE_CMD (null)\n", drive->name);
+ #endif
+-              ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+-              return ide_stopped;
+-      }
++      ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
++      return ide_stopped;
+ }
+ /*
+  * start_request() initiates handling of a new I/O request
++ * needed to reverse the perverted changes anonymously made back
++ * 2.3.99-pre6
+  */
+-static ide_startstop_t start_request (ide_drive_t *drive)
++static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+ {
+       ide_startstop_t startstop;
+       unsigned long block, blockend;
+-      struct request *rq = blkdev_entry_next_request(&drive->queue.queue_head);
+       unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+       ide_hwif_t *hwif = HWIF(drive);
+ #ifdef DEBUG
+-      printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
++      printk("%s: start_request: current=0x%08lx\n",
++              hwif->name, (unsigned long) rq);
+ #endif
++
+       /* bail early if we've exceeded max_failures */
+       if (drive->max_failures && (drive->failures > drive->max_failures)) {
+               goto kill_rq;
+       }
++      /*
++       * bail early if we've sent a device to sleep, however how to wake
++       * this needs to be a masked flag.  FIXME for proper operations.
++       */
++      if (drive->suspend_reset) {
++              goto kill_rq;
++      }
++
+       if (unit >= MAX_DRIVES) {
+-              printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
++              printk("%s: bad device number: %s\n",
++                      hwif->name, kdevname(rq->rq_dev));
+               goto kill_rq;
+       }
+ #ifdef DEBUG
+@@ -1245,8 +1149,14 @@
+               return startstop;
+       }
+       if (!drive->special.all) {
+-              if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+-                      return execute_drive_cmd(drive, rq);
++              switch(rq->cmd) {
++                      case IDE_DRIVE_CMD:
++                      case IDE_DRIVE_TASK:
++                              return execute_drive_cmd(drive, rq);
++                      case IDE_DRIVE_TASKFILE:
++                              return execute_drive_cmd(drive, rq);
++                      default:
++                              break;
+               }
+               if (drive->driver != NULL) {
+                       return (DRIVER(drive)->do_request(drive, rq, block));
+@@ -1257,23 +1167,16 @@
+       return do_special(drive);
+ kill_rq:
+       if (drive->driver != NULL)
+-              DRIVER(drive)->end_request(0, HWGROUP(drive));
++              DRIVER(drive)->end_request(drive, 0);
+       else
+-              ide_end_request(0, HWGROUP(drive));
++              ide_end_request(drive, 0);
+       return ide_stopped;
+ }
+-ide_startstop_t restart_request (ide_drive_t *drive)
++int restart_request (ide_drive_t *drive, struct request *rq)
+ {
+-      ide_hwgroup_t *hwgroup = HWGROUP(drive);
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&io_request_lock, flags);
+-      hwgroup->handler = NULL;
+-      del_timer(&hwgroup->timer);
+-      spin_unlock_irqrestore(&io_request_lock, flags);
+-
+-      return start_request(drive);
++      (void) start_request(drive, rq);
++      return 0;
+ }
+ /*
+@@ -1300,7 +1203,7 @@
+       best = NULL;
+       drive = hwgroup->drive;
+       do {
+-              if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
++              if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
+                       if (!best
+                        || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
+                        || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+@@ -1313,10 +1216,10 @@
+       if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+               long t = (signed long)(WAKEUP(best) - jiffies);
+               if (t >= WAIT_MIN_SLEEP) {
+-                      /*
+-                       * We *may* have some time to spare, but first let's see if
+-                       * someone can potentially benefit from our nice mood today..
+-                       */
++              /*
++               * We *may* have some time to spare, but first let's see if
++               * someone can potentially benefit from our nice mood today..
++               */
+                       drive = best->next;
+                       do {
+                               if (!drive->sleep
+@@ -1370,15 +1273,17 @@
+ /* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
+  *         into life on wakeup from machine sleep.
+  */ 
+-void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
++void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+ {
+       ide_drive_t     *drive;
+       ide_hwif_t      *hwif;
++      struct request  *rq;
+       ide_startstop_t startstop;
+       ide_get_lock(&ide_lock, ide_intr, hwgroup);     /* for atari only: POSSIBLY BROKEN HERE(?) */
+-      __cli();        /* necessary paranoia: ensure IRQs are masked on local CPU */
++      local_irq_disable();
++              /* necessary paranoia: ensure IRQs are masked on local CPU */
+       while (!hwgroup->busy) {
+               hwgroup->busy = 1;
+@@ -1392,13 +1297,13 @@
+                                       sleep = drive->sleep;
+                       } while ((drive = drive->next) != hwgroup->drive);
+                       if (sleep) {
+-                              /*
+-                               * Take a short snooze, and then wake up this hwgroup again.
+-                               * This gives other hwgroups on the same a chance to
+-                               * play fairly with us, just in case there are big differences
+-                               * in relative throughputs.. don't want to hog the cpu too much.
+-                               */
+-                              if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
++              /*
++               * Take a short snooze, and then wake up this hwgroup again.
++               * This gives other hwgroups on the same a chance to
++               * play fairly with us, just in case there are big differences
++               * in relative throughputs.. don't want to hog the cpu too much.
++               */
++                              if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+                                       sleep = jiffies + WAIT_MIN_SLEEP;
+ #if 1
+                               if (timer_pending(&hwgroup->timer))
+@@ -1426,7 +1331,8 @@
+               if ( drive->queue.plugged )     /* paranoia */
+                       printk("%s: Huh? nuking plugged queue\n", drive->name);
+-              hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
++
++              rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
+               /*
+                * Some systems have trouble with IDE IRQs arriving while
+                * the driver is still setting things up.  So, here we disable
+@@ -1438,8 +1344,9 @@
+               if (masked_irq && hwif->irq != masked_irq)
+                       disable_irq_nosync(hwif->irq);
+               spin_unlock(&io_request_lock);
+-              ide__sti();     /* allow other IRQs while we start this request */
+-              startstop = start_request(drive);
++              local_irq_enable();
++                      /* allow other IRQs while we start this request */
++              startstop = start_request(drive, rq);
+               spin_lock_irq(&io_request_lock);
+               if (masked_irq && hwif->irq != masked_irq)
+                       enable_irq(hwif->irq);
+@@ -1466,6 +1373,7 @@
+       ide_do_request(q->queuedata, 0);
+ }
++#ifndef __IDEDMA_TIMEOUT
+ /*
+  * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+  * retry the current request in pio mode instead of risking tossing it
+@@ -1506,8 +1414,17 @@
+       rq->errors = 0;
+       rq->sector = rq->bh->b_rsector;
+       rq->current_nr_sectors = rq->bh->b_size >> 9;
++      rq->hard_cur_sectors = rq->current_nr_sectors;
+       rq->buffer = rq->bh->b_data;
++
++      /*
++       * FIXME or DELETE ME
++       *
++       * so what do we do if the device is left in an invalid state
++       * and will not accept commands. SOFT RESET is the only chance.
++       */
+ }
++#endif
+ /*
+  * ide_timer_expiry() is our timeout function for all drive operations.
+@@ -1543,7 +1460,7 @@
+                       hwgroup->handler = NULL;
+               } else {
+                       ide_hwif_t *hwif;
+-                      ide_startstop_t startstop;
++                      ide_startstop_t startstop = ide_stopped;
+                       if (!hwgroup->busy) {
+                               hwgroup->busy = 1;      /* paranoia */
+                               printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+@@ -1571,7 +1488,8 @@
+ #else
+                       disable_irq(hwif->irq); /* disable_irq_nosync ?? */
+ #endif /* DISABLE_IRQ_NOSYNC */
+-                      __cli();        /* local CPU only, as if we were handling an interrupt */
++                      local_irq_disable();
++                              /* local CPU only, as if we were handling an interrupt */
+                       if (hwgroup->poll_timeout != 0) {
+                               startstop = handler(drive);
+                       } else if (drive_is_ready(drive)) {
+@@ -1582,10 +1500,16 @@
+                               startstop = handler(drive);
+                       } else {
+                               if (drive->waiting_for_dma) {
++#ifndef __IDEDMA_TIMEOUT
+                                       startstop = ide_stopped;
+                                       ide_dma_timeout_retry(drive);
++#else /* __IDEDMA_TIMEOUT */
++                                      (void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
++                                      printk("%s: timeout waiting for DMA\n", drive->name);
++                                      (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
++#endif /* __IDEDMA_TIMEOUT */
+                               } else
+-                                      startstop = ide_error(drive, "irq timeout", GET_STAT());
++                                      startstop = DRIVER(drive)->error(drive, "irq timeout", GET_STAT());
+                       }
+                       set_recovery_timer(hwif);
+                       drive->service_time = jiffies - drive->service_start;
+@@ -1619,7 +1543,7 @@
+  * drive is ready to accept one, in which case we know the drive is not
+  * trying to interrupt us.  And ide_set_handler() is always invoked before
+  * completing the issuance of any new drive command, so we will not be
+- * accidently invoked as a result of any valid command completion interrupt.
++ * accidentally invoked as a result of any valid command completion interrupt.
+  *
+  */
+ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+@@ -1637,7 +1561,7 @@
+                               /* Try to not flood the console with msgs */
+                               static unsigned long last_msgtime, count;
+                               ++count;
+-                              if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
++                              if (time_after(jiffies, last_msgtime + HZ)) {
+                                       last_msgtime = jiffies;
+                                       printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
+                                        hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
+@@ -1692,7 +1616,8 @@
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+               } else {
+                       /*
+-                       * Whack the status register, just in case we have a leftover pending IRQ.
++                       * Whack the status register, just in case
++                       * we have a leftover pending IRQ.
+                        */
+                       (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+ #endif /* CONFIG_BLK_DEV_IDEPCI */
+@@ -1703,16 +1628,18 @@
+       drive = hwgroup->drive;
+       if (!drive) {
+               /*
+-               * This should NEVER happen, and there isn't much we could do about it here.
++               * This should NEVER happen, and there isn't much
++               * we could do about it here.
+                */
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if (!drive_is_ready(drive)) {
+               /*
+-               * This happens regularly when we share a PCI IRQ with another device.
+-               * Unfortunately, it can also happen with some buggy drives that trigger
+-               * the IRQ before their status register is up to date.  Hopefully we have
++               * This happens regularly when we share a PCI IRQ with
++               * another device.  Unfortunately, it can also happen
++               * with some buggy drives that trigger the IRQ before
++               * their status register is up to date.  Hopefully we have
+                * enough advance overhead that the latter isn't a problem.
+                */
+               spin_unlock_irqrestore(&io_request_lock, flags);
+@@ -1727,7 +1654,7 @@
+       spin_unlock(&io_request_lock);
+       if (drive->unmask)
+-              ide__sti();     /* local CPU only */
++              local_irq_enable();
+       startstop = handler(drive);             /* service this interrupt, may set handler for next interrupt */
+       spin_lock_irq(&io_request_lock);
+@@ -1867,7 +1794,7 @@
+       ide_drive_t *drive;
+       ide_hwgroup_t *hwgroup;
+       unsigned int p, major, minor;
+-      long flags;
++      unsigned long flags;
+       if ((drive = get_info_ptr(i_rdev)) == NULL)
+               return -ENODEV;
+@@ -1967,6 +1894,10 @@
+                       (void) request_module("ide-tape");
+               if (drive->media == ide_floppy)
+                       (void) request_module("ide-floppy");
++#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
++              if (drive->media == ide_scsi)
++                      (void) request_module("ide-scsi");
++#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+       }
+ #endif /* CONFIG_KMOD */
+       while (drive->busy)
+@@ -2067,8 +1998,7 @@
+       if (index >= MAX_HWIFS)
+               return;
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       hwif = &ide_hwifs[index];
+       if (!hwif->present)
+               goto abort;
+@@ -2086,7 +2016,7 @@
+       /*
+        * All clear?  Then blow away the buffer cache
+        */
+-      sti();
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+               drive = &hwif->drives[unit];
+               if (!drive->present)
+@@ -2102,7 +2032,7 @@
+               destroy_proc_ide_drives(hwif);
+ #endif
+       }
+-      cli();
++      spin_lock_irqsave(&io_request_lock, flags);
+       hwgroup = hwif->hwgroup;
+       /*
+@@ -2115,7 +2045,7 @@
+               g = g->next;
+       } while (g != hwgroup->hwif);
+       if (irq_count == 1)
+-              free_irq(hwif->irq, hwgroup);
++              ide_free_irq(hwif->irq, hwgroup);
+       /*
+        * Note that we only release the standard ports,
+@@ -2222,7 +2152,7 @@
+       hwif->straight8         = old_hwif.straight8;
+       hwif->hwif_data         = old_hwif.hwif_data;
+ abort:
+-      restore_flags(flags);   /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ /*
+@@ -2295,6 +2225,7 @@
+       memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+       hwif->irq = hw->irq;
+       hwif->noprobe = 0;
++      hwif->chipset = hw->chipset;
+       if (!initializing) {
+               ide_probe_module();
+@@ -2433,14 +2364,13 @@
+       while (hwgroup->busy) {
+               unsigned long lflags;
+               spin_unlock_irq(&io_request_lock);
+-              __save_flags(lflags);   /* local CPU only */
+-              __sti();                /* local CPU only; needed for jiffies */
+-              if (0 < (signed long)(jiffies - timeout)) {
+-                      __restore_flags(lflags);        /* local CPU only */
++              local_irq_set(lflags);
++              if (time_after(jiffies, timeout)) {
++                      local_irq_restore(lflags);
+                       printk("%s: channel busy\n", drive->name);
+                       return -EBUSY;
+               }
+-              __restore_flags(lflags);        /* local CPU only */
++              local_irq_restore(lflags);
+               spin_lock_irq(&io_request_lock);
+       }
+       return 0;
+@@ -2535,8 +2465,8 @@
+       ide_add_setting(drive,  "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   HDIO_GET_UNMASKINTR,    HDIO_SET_UNMASKINTR,    TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL);
+       ide_add_setting(drive,  "using_dma",            SETTING_RW,                                     HDIO_GET_DMA,           HDIO_SET_DMA,           TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma);
+       ide_add_setting(drive,  "ide_scsi",             SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->scsi,                   NULL);
+-      ide_add_setting(drive,  "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      69,                             1,              1,              &drive->init_speed,             NULL);
+-      ide_add_setting(drive,  "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      69,                             1,              1,              &drive->current_speed,          NULL);
++      ide_add_setting(drive,  "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL);
++      ide_add_setting(drive,  "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          NULL);
+       ide_add_setting(drive,  "number",               SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL);
+ }
+@@ -2590,6 +2520,61 @@
+       return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
+ }
++int ide_reinit_drive (ide_drive_t *drive)
++{
++      switch (drive->media) {
++#ifdef CONFIG_BLK_DEV_IDECD
++              case ide_cdrom:
++              {
++                      extern int ide_cdrom_reinit(ide_drive_t *drive);
++                      if (ide_cdrom_reinit(drive))
++                              return 1;
++                      break;
++              }
++#endif /* CONFIG_BLK_DEV_IDECD */
++#ifdef CONFIG_BLK_DEV_IDEDISK
++              case ide_disk:
++              {
++                      extern int idedisk_reinit(ide_drive_t *drive);
++                      if (idedisk_reinit(drive))
++                              return 1;
++                      break;
++              }
++#endif /* CONFIG_BLK_DEV_IDEDISK */
++#ifdef CONFIG_BLK_DEV_IDEFLOPPY
++              case ide_floppy:
++              {
++                      extern int idefloppy_reinit(ide_drive_t *drive);
++                      if (idefloppy_reinit(drive))
++                              return 1;
++                      break;
++              }
++#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
++#ifdef CONFIG_BLK_DEV_IDETAPE
++              case ide_tape:
++              {
++                      extern int idetape_reinit(ide_drive_t *drive);
++                      if (idetape_reinit(drive))
++                              return 1;
++                      break;
++              }
++#endif /* CONFIG_BLK_DEV_IDETAPE */
++#ifdef CONFIG_BLK_DEV_IDESCSI
++/*
++ *              {
++ *                      extern int idescsi_reinit(ide_drive_t *drive);
++ *                      if (idescsi_reinit(drive))
++ *                              return 1;
++ *                      break;
++ * }
++ */
++#endif /* CONFIG_BLK_DEV_IDESCSI */
++              default:
++                      return 1;
++      }
++      return 0;
++}
++
+ static int ide_ioctl (struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+ {
+@@ -2681,57 +2666,35 @@
+                                       drive->nice1            <<      IDE_NICE_1              |
+                                       drive->nice2            <<      IDE_NICE_2,
+                                       (long *) arg);
++
++#ifdef CONFIG_IDE_TASK_IOCTL
++              case HDIO_DRIVE_TASKFILE:
++                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++                              return -EACCES;
++                      switch(drive->media) {
++                              case ide_disk:
++                                      return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
++#ifdef CONFIG_PKT_TASK_IOCTL
++                              case ide_cdrom:
++                              case ide_tape:
++                              case ide_floppy:
++                                      return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
++#endif /* CONFIG_PKT_TASK_IOCTL */
++                              default:
++                                      return -ENOMSG;
++                      }
++#endif /* CONFIG_IDE_TASK_IOCTL */
++
+               case HDIO_DRIVE_CMD:
+-              {
+-                      byte args[4], *argbuf = args;
+-                      byte xfer_rate = 0;
+-                      int argsize = 4;
+-                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
+-                      if (NULL == (void *) arg)
+-                              return ide_do_drive_cmd(drive, &rq, ide_wait);
+-                      if (copy_from_user(args, (void *)arg, 4))
+-                              return -EFAULT;
+-                      if (args[3]) {
+-                              argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+-                              argbuf = kmalloc(argsize, GFP_KERNEL);
+-                              if (argbuf == NULL)
+-                                      return -ENOMEM;
+-                              memcpy(argbuf, args, 4);
+-                      }
+-
+-                      if (set_transfer(drive, args[0], args[1], args[2])) {
+-                              xfer_rate = args[1];
+-                              if (ide_ata66_check(drive, args[0], args[1], args[2]))
+-                                      goto abort;
+-                      }
+-
+-                      err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+-
+-                      if (!err && xfer_rate) {
+-                              /* active-retuning-calls future */
+-                              if ((HWIF(drive)->speedproc) != NULL)
+-                                      HWIF(drive)->speedproc(drive, xfer_rate);
+-                              ide_driveid_update(drive);
+-                      }
+-              abort:
+-                      if (copy_to_user((void *)arg, argbuf, argsize))
+-                              err = -EFAULT;
+-                      if (argsize > 4)
+-                              kfree(argbuf);
+-                      return err;
+-              }
++                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++                              return -EACCES;
++                      return ide_cmd_ioctl(drive, inode, file, cmd, arg);
++
+               case HDIO_DRIVE_TASK:
+-              {
+-                      byte args[7], *argbuf = args;
+-                      int argsize = 7;
+-                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
+-                      if (copy_from_user(args, (void *)arg, 7))
+-                              return -EFAULT;
+-                      err = ide_wait_cmd_task(drive, argbuf);
+-                      if (copy_to_user((void *)arg, argbuf, argsize))
+-                              err = -EFAULT;
+-                      return err;
+-              }
++                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++                              return -EACCES;
++                      return ide_task_ioctl(drive, inode, file, cmd, arg);
++
+               case HDIO_SCAN_HWIF:
+               {
+                       int args[3];
+@@ -2761,7 +2724,21 @@
+                       drive->nice1 = (arg >> IDE_NICE_1) & 1;
+                       return 0;
+               case HDIO_DRIVE_RESET:
++              {
++                      unsigned long flags;
+                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
++#if 1
++                      spin_lock_irqsave(&io_request_lock, flags);
++                      if ( HWGROUP(drive)->handler != NULL) {
++                              printk("%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
++                              (void) HWGROUP(drive)->handler(drive);
++//                            HWGROUP(drive)->handler = NULL;
++                              HWGROUP(drive)->expiry  = NULL;
++                              del_timer(&HWGROUP(drive)->timer);
++                      }
++                      spin_unlock_irqrestore(&io_request_lock, flags);
++
++#endif
+                       (void) ide_do_reset(drive);
+                       if (drive->suspend_reset) {
+ /*
+@@ -2776,7 +2753,7 @@
+                               return ide_revalidate_disk(inode->i_rdev);
+                       }
+                       return 0;
+-
++              }
+               case BLKROSET:
+               case BLKROGET:
+               case BLKFLSBUF:
+@@ -2799,7 +2776,7 @@
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EACCES;
+                       if (HWIF(drive)->busproc)
+-                              HWIF(drive)->busproc(HWIF(drive), arg);
++                              HWIF(drive)->busproc(drive, (int)arg);
+                       return 0;
+               default:
+@@ -3316,13 +3293,6 @@
+       {
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+               ide_scan_pcibus(ide_scan_direction);
+-#else
+-#ifdef CONFIG_BLK_DEV_RZ1000
+-              {
+-                      extern void ide_probe_for_rz100x(void);
+-                      ide_probe_for_rz100x();
+-              }
+-#endif /* CONFIG_BLK_DEV_RZ1000 */
+ #endif /* CONFIG_BLK_DEV_IDEPCI */
+       }
+ #endif /* CONFIG_PCI */
+@@ -3351,6 +3321,12 @@
+               pmac_ide_probe();
+       }
+ #endif /* CONFIG_BLK_DEV_IDE_PMAC */
++#ifdef CONFIG_BLK_DEV_IDE_SWARM
++      {
++              extern void swarm_ide_probe(void);
++              swarm_ide_probe();
++      }
++#endif /* CONFIG_BLK_DEV_IDE_SWARM */
+ #ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+       {
+               extern void icside_init(void);
+@@ -3460,17 +3436,47 @@
+       return ide_unregister_subdriver(drive);
+ }
+-static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
++static int default_standby (ide_drive_t *drive)
+ {
+-      ide_end_request(0, HWGROUP(drive));
++      return 0;
++}
++
++static int default_suspend (ide_drive_t *drive)
++{
++      return 0;
++}
++
++static int default_resume (ide_drive_t *drive)
++{
++      return 0;
++}
++
++static int default_flushcache (ide_drive_t *drive)
++{
++      return 0;
++}
++
++static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
++{
++      ide_end_request(drive, 0);
+       return ide_stopped;
+ }
+- 
+-static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
++
++static int default_end_request (ide_drive_t *drive, int uptodate)
++{
++      return ide_end_request(drive, uptodate);
++}
++
++static byte default_sense (ide_drive_t *drive, const char *msg, byte stat)
++{
++      return ide_dump_status(drive, msg, stat);
++}
++
++static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, byte stat)
+ {
+-      ide_end_request(uptodate, hwgroup);
++      return ide_error(drive, msg, stat);
+ }
+-  
++
+ static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+ {
+@@ -3510,7 +3516,12 @@
+       return ide_stopped;
+ }
+-static int default_driver_reinit (ide_drive_t *drive)
++static int default_init (void)
++{
++      return 0;
++}
++
++static int default_reinit (ide_drive_t *drive)
+ {
+       printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
+@@ -3522,8 +3533,14 @@
+       ide_driver_t *d = drive->driver;
+       if (d->cleanup == NULL)         d->cleanup = default_cleanup;
++      if (d->standby == NULL)         d->standby = default_standby;
++      if (d->suspend == NULL)         d->suspend = default_suspend;
++      if (d->resume == NULL)          d->resume = default_resume;
++      if (d->flushcache == NULL)      d->flushcache = default_flushcache;
+       if (d->do_request == NULL)      d->do_request = default_do_request;
+       if (d->end_request == NULL)     d->end_request = default_end_request;
++      if (d->sense == NULL)           d->sense = default_sense;
++      if (d->error == NULL)           d->error = default_error;
+       if (d->ioctl == NULL)           d->ioctl = default_ioctl;
+       if (d->open == NULL)            d->open = default_open;
+       if (d->release == NULL)         d->release = default_release;
+@@ -3531,7 +3548,8 @@
+       if (d->pre_reset == NULL)       d->pre_reset = default_pre_reset;
+       if (d->capacity == NULL)        d->capacity = default_capacity;
+       if (d->special == NULL)         d->special = default_special;
+-      if (d->driver_reinit == NULL)   d->driver_reinit = default_driver_reinit;
++      if (d->init == NULL)            d->init = default_init;
++      if (d->reinit == NULL)          d->reinit = default_reinit;
+ }
+ ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+@@ -3558,15 +3576,15 @@
+ {
+       unsigned long flags;
+       
+-      save_flags(flags);              /* all CPUs */
+-      cli();                          /* all CPUs */
+-      if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) {
+-              restore_flags(flags);   /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
++      if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
++          drive->driver != NULL || drive->busy || drive->usage) {
++              spin_unlock_irqrestore(&io_request_lock, flags);
+               return 1;
+       }
+       drive->driver = driver;
+       setup_driver_defaults(drive);
+-      restore_flags(flags);           /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       if (drive->autotune != 2) {
+               if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
+                       /*
+@@ -3594,10 +3612,10 @@
+ {
+       unsigned long flags;
+       
+-      save_flags(flags);              /* all CPUs */
+-      cli();                          /* all CPUs */
+-      if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
+-              restore_flags(flags);   /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
++      if (drive->usage || drive->busy ||
++          drive->driver == NULL || DRIVER(drive)->busy) {
++              spin_unlock_irqrestore(&io_request_lock, flags);
+               return 1;
+       }
+ #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
+@@ -3609,7 +3627,7 @@
+ #endif
+       auto_remove_settings(drive);
+       drive->driver = NULL;
+-      restore_flags(flags);           /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return 0;
+ }
+@@ -3672,15 +3690,10 @@
+ EXPORT_SYMBOL(ide_register_subdriver);
+ EXPORT_SYMBOL(ide_unregister_subdriver);
+ EXPORT_SYMBOL(ide_replace_subdriver);
+-EXPORT_SYMBOL(ide_input_data);
+-EXPORT_SYMBOL(ide_output_data);
+-EXPORT_SYMBOL(atapi_input_bytes);
+-EXPORT_SYMBOL(atapi_output_bytes);
+ EXPORT_SYMBOL(ide_set_handler);
+ EXPORT_SYMBOL(ide_dump_status);
+ EXPORT_SYMBOL(ide_error);
+ EXPORT_SYMBOL(ide_fixstring);
+-EXPORT_SYMBOL(ide_wait_stat);
+ EXPORT_SYMBOL(ide_do_reset);
+ EXPORT_SYMBOL(restart_request);
+ EXPORT_SYMBOL(ide_init_drive_cmd);
+@@ -3698,6 +3711,8 @@
+ EXPORT_SYMBOL(ide_remove_proc_entries);
+ EXPORT_SYMBOL(proc_ide_read_geometry);
+ EXPORT_SYMBOL(create_proc_ide_interfaces);
++EXPORT_SYMBOL(recreate_proc_ide_device);
++EXPORT_SYMBOL(destroy_proc_ide_device);
+ #endif
+ EXPORT_SYMBOL(ide_add_setting);
+ EXPORT_SYMBOL(ide_remove_setting);
+@@ -3712,6 +3727,54 @@
+ EXPORT_SYMBOL(system_bus_clock);
++EXPORT_SYMBOL(ide_reinit_drive);
++
++static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
++{
++      ide_hwif_t *hwif;
++      ide_drive_t *drive;
++      int i, unit;
++
++      switch (event) {
++              case SYS_HALT:
++              case SYS_POWER_OFF:
++              case SYS_RESTART:
++                      break;
++              default:
++                      return NOTIFY_DONE;
++      }
++
++      printk("flushing ide devices: ");
++
++      for (i = 0; i < MAX_HWIFS; i++) {
++              hwif = &ide_hwifs[i];
++              if (!hwif->present)
++                      continue;
++              for (unit = 0; unit < MAX_DRIVES; ++unit) {
++                      drive = &hwif->drives[unit];
++                      if (!drive->present)
++                              continue;
++
++                      /* set the drive to standby */
++                      printk("%s ", drive->name);
++                      if (event != SYS_RESTART)
++                              if (drive->driver != NULL && DRIVER(drive)->standby(drive))
++                              continue;
++
++                      if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
++                              continue;
++              }
++      }
++      printk("\n");
++      return NOTIFY_DONE;
++}
++
++static struct notifier_block ide_notifier = {
++      ide_notify_reboot,
++      NULL,
++      5
++};
++
+ /*
+  * This is gets invoked once during initialization, to set *everything* up
+  */
+@@ -3739,6 +3802,7 @@
+                       ide_geninit(hwif);
+       }
++      register_reboot_notifier(&ide_notifier);
+       return 0;
+ }
+@@ -3771,6 +3835,7 @@
+ {
+       int index;
++      unregister_reboot_notifier(&ide_notifier);
+       for (index = 0; index < MAX_HWIFS; ++index) {
+               ide_unregister(index);
+ #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+diff -Nur linux.org/drivers/ide/it8172.c linux/drivers/ide/it8172.c
+--- linux.org/drivers/ide/it8172.c     Fri Sep  7 18:28:38 2001
++++ linux/drivers/ide/it8172.c Thu Jul 18 14:24:33 2002
+@@ -46,100 +46,134 @@
+ /*
+  * Prototypes
+  */
++static byte it8172_ratemask (ide_drive_t *drive);
++static byte it8172_ratefilter (ide_drive_t *drive, byte speed);
+ static void it8172_tune_drive (ide_drive_t *drive, byte pio);
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
+ static byte it8172_dma_2_pio (byte xfer_rate);
+-static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
+-static int it8172_config_drive_for_dma (ide_drive_t *drive);
++static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed);
++#ifdef CONFIG_BLK_DEV_IDEDMA
++static int it8172_config_chipset_for_dma (ide_drive_t *drive);
+ static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
+ #endif
+ unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
+ void __init ide_init_it8172 (ide_hwif_t *hwif);
++static byte it8172_ratemask (ide_drive_t *drive)
++{
++      byte mode       = 0x00;
++#if 1
++      mode |= 0x01;
++#endif
++      return (mode &= ~0xF8);
++}
++
++static byte it8172_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = it8172_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      // while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      // while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
+ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
+ {
+-    unsigned long flags;
+-    u16 master_data;
+-    u32 slave_data;
+-    int is_slave      = (&HWIF(drive)->drives[1] == drive);
+-    int master_port   = 0x40;
+-    int slave_port      = 0x44;
+-    
+-    pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+-    pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
+-    pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data);
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      int is_slave            = (hwif->drives[1] == drive);
++      unsigned long flags;
++      u16 drive_enables;
++      u32 drive_timing;
++
++      pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
++      spin_lock_irqsave(&io_request_lock, flags);
++      pci_read_config_word(dev, 0x40, &drive_enables);
++      pci_read_config_dword(dev, 0x44, &drive_timing);
++
++      /*
++       * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
++       * are being left at the default values of 8 PCI clocks (242 nsec
++       * for a 33 MHz clock). These can be safely shortened at higher
++       * PIO modes. The DIOR/DIOW pulse width and recovery times only
++       * apply to PIO modes, not to the DMA modes.
++       */
++
++      /*
++       * Enable port 0x44. The IT8172G spec is confused; it calls
++       * this register the "Slave IDE Timing Register", but in fact,
++       * it controls timing for both master and slave drives.
++       */
++      drive_enables |= 0x4000;
++
++      if (is_slave) {
++              drive_enables &= 0xc006;
++              if (pio > 1)
++                      /* enable prefetch and IORDY sample-point */
++                      drive_enables |= 0x0060;
++      } else {
++              drive_enables &= 0xc060;
++              if (pio > 1)
++                      /* enable prefetch and IORDY sample-point */
++                      drive_enables |= 0x0006;
++      }
+-    /*
+-     * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+-     * are being left at the default values of 8 PCI clocks (242 nsec
+-     * for a 33 MHz clock). These can be safely shortened at higher
+-     * PIO modes.
+-     */
+-    
+-    if (is_slave) {
+-      master_data |= 0x4000;
+-      if (pio > 1)
+-          /* enable PPE and IE */
+-          master_data |= 0x0060;
+-    } else {
+-      master_data &= 0xc060;
+-      if (pio > 1)
+-          /* enable PPE and IE */
+-          master_data |= 0x0006;
+-    }
+-
+-    save_flags(flags);
+-    cli();
+-    pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
+-    restore_flags(flags);
++      pci_write_config_word(dev, 0x40, drive_enables);
++      spin_unlock_irqrestore(&io_request_lock, flags)
+ }
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
+-/*
+- *
+- */
+ static byte it8172_dma_2_pio (byte xfer_rate)
+ {
+-    switch(xfer_rate) {
+-    case XFER_UDMA_5:
+-    case XFER_UDMA_4:
+-    case XFER_UDMA_3:
+-    case XFER_UDMA_2:
+-    case XFER_UDMA_1:
+-    case XFER_UDMA_0:
+-    case XFER_MW_DMA_2:
+-    case XFER_PIO_4:
+-      return 4;
+-    case XFER_MW_DMA_1:
+-    case XFER_PIO_3:
+-      return 3;
+-    case XFER_SW_DMA_2:
+-    case XFER_PIO_2:
+-      return 2;
+-    case XFER_MW_DMA_0:
+-    case XFER_SW_DMA_1:
+-    case XFER_SW_DMA_0:
+-    case XFER_PIO_1:
+-    case XFER_PIO_0:
+-    case XFER_PIO_SLOW:
+-    default:
+-      return 0;
+-    }
+-}
+-
+-static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
+-{
+-    ide_hwif_t *hwif  = HWIF(drive);
+-    struct pci_dev *dev       = hwif->pci_dev;
+-    int a_speed               = 3 << (drive->dn * 4);
+-    int u_flag                = 1 << drive->dn;
+-    int u_speed               = 0;
+-    int err           = 0;
+-    byte reg48, reg4a;
++      switch(xfer_rate) {
++              case XFER_UDMA_5:
++              case XFER_UDMA_4:
++              case XFER_UDMA_3:
++              case XFER_UDMA_2:
++              case XFER_UDMA_1:
++              case XFER_UDMA_0:
++              case XFER_MW_DMA_2:
++              case XFER_PIO_4:
++                      return 4;
++              case XFER_MW_DMA_1:
++              case XFER_PIO_3:
++                      return 3;
++              case XFER_SW_DMA_2:
++              case XFER_PIO_2:
++                      return 2;
++              case XFER_MW_DMA_0:
++              case XFER_SW_DMA_1:
++              case XFER_SW_DMA_0:
++              case XFER_PIO_1:
++              case XFER_PIO_0:
++              case XFER_PIO_SLOW:
++              default:
++                      return 0;
++      }
++}
+-    pci_read_config_byte(dev, 0x48, &reg48);
+-    pci_read_config_byte(dev, 0x4a, &reg4a);
++static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      byte speed              = it8172_ratefilter(drive, xferspeed);
++      int a_speed             = 3 << (drive->dn * 4);
++      int u_flag              = 1 << drive->dn;
++      int u_speed             = 0;
++      byte reg48, reg4a;
++
++      pci_read_config_byte(dev, 0x48, &reg48);
++      pci_read_config_byte(dev, 0x4a, &reg4a);
+     /*
+      * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+@@ -151,127 +185,205 @@
+      * performance.
+      */
+     
+-    switch(speed) {
+-    case XFER_UDMA_4:
+-    case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break;
+-    case XFER_UDMA_5:
+-    case XFER_UDMA_3:
+-    case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break;
+-    case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+-    case XFER_MW_DMA_2:
+-    case XFER_MW_DMA_1:
+-    case XFER_SW_DMA_2:       break;
+-    default:          return -1;
+-    }
+-
+-    if (speed >= XFER_UDMA_0) {
+-      pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+-      reg4a &= ~a_speed;
+-      pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+-    } else {
+-      pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+-      pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+-    }
+-
+-    it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+-
+-    if (!drive->init_speed)
+-      drive->init_speed = speed;
+-    err = ide_config_drive_speed(drive, speed);
+-    drive->current_speed = speed;
+-    return err;
+-}
+-
+-static int it8172_config_drive_for_dma (ide_drive_t *drive)
+-{
+-    struct hd_driveid *id = drive->id;
+-    byte speed;
+-
+-    if (id->dma_ultra & 0x0010) {
+-      speed = XFER_UDMA_2;
+-    } else if (id->dma_ultra & 0x0008) {
+-      speed = XFER_UDMA_1;
+-    } else if (id->dma_ultra & 0x0004) {
+-      speed = XFER_UDMA_2;
+-    } else if (id->dma_ultra & 0x0002) {
+-      speed = XFER_UDMA_1;
+-    } else if (id->dma_ultra & 0x0001) {
+-      speed = XFER_UDMA_0;
+-    } else if (id->dma_mword & 0x0004) {
+-      speed = XFER_MW_DMA_2;
+-    } else if (id->dma_mword & 0x0002) {
+-      speed = XFER_MW_DMA_1;
+-    } else if (id->dma_1word & 0x0004) {
+-      speed = XFER_SW_DMA_2;
+-    } else {
+-      speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+-    }
+-
+-    (void) it8172_tune_chipset(drive, speed);
+-
+-    return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+-          ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+-          ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+-          ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+-          ide_dma_off_quietly);
++      switch(speed) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
++              case XFER_UDMA_4:
++              case XFER_UDMA_2:       //u_speed = 2 << (drive->dn * 4); break;
++              case XFER_UDMA_5:
++              case XFER_UDMA_3:
++              case XFER_UDMA_1:       //u_speed = 1 << (drive->dn * 4); break;
++              case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
++              case XFER_MW_DMA_2:
++              case XFER_MW_DMA_1:
++              case XFER_MW_DMA_0:
++              case XFER_SW_DMA_2:     break;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++              case XFER_PIO_4:
++              case XFER_PIO_3:
++              case XFER_PIO_2:
++              case XFER_PIO_0:        break;
++              default:                return -1;
++      }
++
++      if (speed >= XFER_UDMA_0) {
++              pci_write_config_byte(dev, 0x48, reg48 | u_flag);
++              reg4a &= ~a_speed;
++              pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
++      } else {
++              pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
++              pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
++      }
++
++      it8172_tune_drive(drive, it8172_dma_2_pio(speed));
++      return (ide_config_drive_speed(drive, speed));
+ }
+-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
++#ifdef CONFIG_BLK_DEV_IDEDMA
++static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+ {
+-    switch (func) {
+-    case ide_dma_check:
+-      return ide_dmaproc((ide_dma_action_t)it8172_config_drive_for_dma(drive),
+-                         drive);
+-    default :
+-      break;
+-    }
+-    /* Other cases are done by generic IDE-DMA code. */
+-    return ide_dmaproc(func, drive);
++      struct hd_driveid *id   = drive->id;
++      byte mode               = it8172_ratemask(drive);
++      byte speed, tspeed, dma = 1;
++
++      switch(mode) {
++              case 0x01:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++              default:
++                      tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
++                      speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
++                      dma = 0;
++                      break;
++      }
++
++      (void) it8172_tune_chipset(drive, speed);
++
++//    return ((int)(dma) ? ide_dma_on : ide_dma_off_quietly);
++      return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
++                  ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
++                  ((id->dma_mword >> 8) & 7) ? ide_dma_on :
++                  ((id->dma_1word >> 8) & 7) ? ide_dma_on :
++                  ide_dma_off_quietly);
+ }
+-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
++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;
++
++      drive->init_speed = 0;
++
++      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 & 0x007F) {
++                              /* Force if Capable UltraDMA */
++                              dma_func = it8172_config_chipset_for_dma(drive);
++                              if ((id->field_valid & 2) &&
++                                  (dma_func != ide_dma_on))
++                                      goto try_dma_modes;
++                      }
++              } else if (id->field_valid & 2) {
++try_dma_modes:
++                      if ((id->dma_mword & 0x0007) ||
++                          (id->dma_1word & 0x007)) {
++                              /* Force if Capable regular DMA modes */
++                              dma_func = it8172_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 = it8172_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:
++              it8172_tune_drive(drive, 5);
++      }
++      return HWIF(drive)->dmaproc(dma_func, drive);
++}
++
++static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
++{
++      switch (func) {
++              case ide_dma_check:
++                      return config_drive_xfer_rate(drive);
++              default :
++                      break;
++      }
++      /* Other cases are done by generic IDE-DMA code. */
++      return ide_dmaproc(func, drive);
++}
++#endif /* CONFIG_BLK_DEV_IDEDMA */
+ unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
+ {
+-    unsigned char progif;
++      unsigned char progif;
+     
+-    /*
+-     * Place both IDE interfaces into PCI "native" mode
+-     */
+-    (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+-    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
++      /*
++       * Place both IDE interfaces into PCI "native" mode
++       */
++      pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
++      pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+-    return IT8172_IDE_IRQ;
++      return IT8172_IDE_IRQ;
+ }
+ void __init ide_init_it8172 (ide_hwif_t *hwif)
+ {
+-    struct pci_dev* dev = hwif->pci_dev;
+-    unsigned long cmdBase, ctrlBase;
++      struct pci_dev* dev = hwif->pci_dev;
++      unsigned long cmdBase, ctrlBase;
+     
+-    hwif->tuneproc = &it8172_tune_drive;
+-    hwif->drives[0].autotune = 1;
+-    hwif->drives[1].autotune = 1;
+-
+-    if (!hwif->dma_base)
+-      return;
+-
+-#ifndef CONFIG_BLK_DEV_IDEDMA
+-    hwif->autodma = 0;
+-#else /* CONFIG_BLK_DEV_IDEDMA */
+-#ifdef CONFIG_IT8172_TUNING
+-    hwif->autodma = 1;
+-    hwif->dmaproc = &it8172_dmaproc;
+-    hwif->speedproc = &it8172_tune_chipset;
+-#endif /* CONFIG_IT8172_TUNING */
+-#endif /* !CONFIG_BLK_DEV_IDEDMA */
++      hwif->autodma = 0;
++      hwif->tuneproc = &it8172_tune_drive;
++      hwif->speedproc = &it8172_tune_chipset;
++      hwif->drives[0].autotune = 1;
++      hwif->drives[1].autotune = 1;
+-    cmdBase = dev->resource[0].start;
+-    ctrlBase = dev->resource[1].start;
++      cmdBase = dev->resource[0].start;
++      ctrlBase = dev->resource[1].start;
+     
+-    ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+-    memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+-    hwif->noprobe = 0;
++      ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
++      memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
++      hwif->noprobe = 0;
++
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &it8172_dmaproc;
++# ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++# endif /* CONFIG_IDEDMA_AUTO */
++#endif /* !CONFIG_BLK_DEV_IDEDMA */
++}
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_it8172 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++        if ((!(PCI_FUNC(dev->devfn) & 1) ||
++            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
++                return; /* IT8172 is more than only a IDE controller */
++
++      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 -Nur linux.org/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c
+--- linux.org/drivers/ide/ns87415.c    Tue Jun 20 16:52:36 2000
++++ linux/drivers/ide/ns87415.c        Thu Jul 18 14:24:33 2002
+@@ -24,6 +24,10 @@
+ #include <asm/io.h>
++#if defined(__hppa__) && defined(CONFIG_SUPERIO)
++#include <asm/superio.h>
++#endif
++
+ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+ /*
+@@ -38,8 +42,7 @@
+       struct pci_dev *dev = hwif->pci_dev;
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       new = *old;
+       /* Adjust IRQ enable bit */
+@@ -73,7 +76,7 @@
+               udelay(10);
+       }
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+ }
+ static void ns87415_selectproc (ide_drive_t *drive)
+@@ -90,17 +93,24 @@
+       switch (func) {
+               case ide_dma_end: /* returns 1 on error, 0 otherwise */
+                       drive->waiting_for_dma = 0;
+-                      dma_stat = inb(hwif->dma_base+2);
+-                      outb(inb(hwif->dma_base)&~1, hwif->dma_base);   /* stop DMA */
+-                      outb(inb(hwif->dma_base)|6, hwif->dma_base);    /* from ERRATA: clear the INTR & ERROR bits */
+-                      ide_destroy_dmatable(drive);                    /* and free any DMA resources */
+-                      return (dma_stat & 7) != 4;             /* verify good DMA status */
++                      dma_stat = IN_BYTE(hwif->dma_base+2);
++                      /* stop DMA */
++                      OUT_BYTE(IN_BYTE(hwif->dma_base)&~1, hwif->dma_base);
++                      /* from ERRATA: clear the INTR & ERROR bits */
++                      OUT_BYTE(IN_BYTE(hwif->dma_base)|6, hwif->dma_base);
++                      /* and free any DMA resources */
++                      ide_destroy_dmatable(drive);
++                      /* verify good DMA status */
++                      return (dma_stat & 7) != 4;
+               case ide_dma_write:
+               case ide_dma_read:
+-                      ns87415_prepare_drive(drive, 1);        /* select DMA xfer */
+-                      if (!ide_dmaproc(func, drive))          /* use standard DMA stuff */
++                      /* select DMA xfer */
++                      ns87415_prepare_drive(drive, 1);
++                      /* use standard DMA stuff */
++                      if (!ide_dmaproc(func, drive))
+                               return 0;
+-                      ns87415_prepare_drive(drive, 0);        /* DMA failed: select PIO xfer */
++                      /* DMA failed: select PIO xfer */
++                      ns87415_prepare_drive(drive, 0);
+                       return 1;
+               case ide_dma_check:
+                       if (drive->media != ide_disk)
+@@ -122,6 +132,9 @@
+       byte stat;
+ #endif
++      hwif->autodma = 0;
++      hwif->selectproc = &ns87415_selectproc;
++
+       /* Set a good latency timer and cache line size value. */
+       (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ #ifdef __sparc_v9__
+@@ -164,30 +177,36 @@
+                *      to SELECT_DRIVE() properly during first probe_hwif().
+                */
+               timeout = 10000;
+-              outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
++              OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+               udelay(10);
+-              outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
++              OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+               do {
+                       udelay(50);
+-                      stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
++                      stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+                       if (stat == 0xff)
+                               break;
+               } while ((stat & BUSY_STAT) && --timeout);
+ #endif
+       }
+-      if (hwif->dma_base)
+-              outb(0x60, hwif->dma_base + 2);
+-
+       if (!using_inta)
++#if defined(__hppa__) && defined(CONFIG_SUPERIO)
++              hwif->irq = superio_get_ide_irq();      /* legacy mode */
++#else
+               hwif->irq = hwif->channel ? 15 : 14;    /* legacy mode */
++#endif
+       else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+               hwif->irq = hwif->mate->irq;    /* share IRQ with mate */
++      if (!hwif->dma_base)
++              return;
++
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (hwif->dma_base)
+-              hwif->dmaproc = &ns87415_dmaproc;
++      OUT_BYTE(0x60, hwif->dma_base + 2);
++      hwif->dmaproc = &ns87415_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-
+-      hwif->selectproc = &ns87415_selectproc;
+ }
+diff -Nur linux.org/drivers/ide/opti621.c linux/drivers/ide/opti621.c
+--- linux.org/drivers/ide/opti621.c    Wed May  2 01:05:00 2001
++++ linux/drivers/ide/opti621.c        Thu Jul 18 14:24:34 2002
+@@ -97,6 +97,7 @@
+ #include <linux/mm.h>
+ #include <linux/ioport.h>
+ #include <linux/blkdev.h>
++#include <linux/pci.h>
+ #include <linux/hdreg.h>
+ #include <linux/ide.h>
+@@ -183,11 +184,11 @@
+  * This is from setupvic.exe program.
+  */
+ {
+-      inw(reg_base+1);
+-      inw(reg_base+1);
+-      outb(3, reg_base+2);
+-      outb(value, reg_base+reg);
+-      outb(0x83, reg_base+2);
++      IN_WORD(reg_base+1);
++      IN_WORD(reg_base+1);
++      OUT_BYTE(3, reg_base+2);
++      OUT_BYTE(value, reg_base+reg);
++      OUT_BYTE(0x83, reg_base+2);
+ }
+ static byte read_reg(int reg)
+@@ -198,11 +199,11 @@
+  */
+ {
+       byte ret;
+-      inw(reg_base+1);
+-      inw(reg_base+1);
+-      outb(3, reg_base+2);
+-      ret=inb(reg_base+reg);
+-      outb(0x83, reg_base+2);
++      IN_WORD(reg_base+1);
++      IN_WORD(reg_base+1);
++      OUT_BYTE(3, reg_base+2);
++      ret=IN_BYTE(reg_base+reg);
++      OUT_BYTE(0x83, reg_base+2);
+       return ret;
+ }
+@@ -276,13 +277,12 @@
+               hwif->name, ax, second.data_time, second.recovery_time, drdy);
+ #endif
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+-      outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */
+-      outb(0xff, reg_base+5);         /* hmm, setupvic.exe does this ;-) */
+-      inb(reg_base+CNTRL_REG);        /* if reads 0xff, adapter not exist? */
++      OUT_BYTE(0xc0, reg_base+CNTRL_REG);     /* allow Register-B */
++      OUT_BYTE(0xff, reg_base+5);     /* hmm, setupvic.exe does this ;-) */
++      IN_BYTE(reg_base+CNTRL_REG);    /* if reads 0xff, adapter not exist? */
+       read_reg(CNTRL_REG);            /* if reads 0xc0, no interface exist? */
+       read_reg(STRAP_REG);            /* read version, probably 0 */
+@@ -302,7 +302,7 @@
+       write_reg(misc, MISC_REG);      /* set address setup, DRDY timings,   */
+                                       /*  and read prefetch for both drives */
+-      restore_flags(flags);   /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ /*
+@@ -310,7 +310,30 @@
+  */
+ void __init ide_init_opti621 (ide_hwif_t *hwif)
+ {
++      hwif->autodma = 0;
+       hwif->drives[0].drive_data = PIO_DONT_KNOW;
+       hwif->drives[1].drive_data = PIO_DONT_KNOW;
+       hwif->tuneproc = &opti621_tune_drive;
++
++      /* safety call for Anton A */
++      hwif->dma_base = 0;
++}
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++#if 0
++      if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) &&
++          !(PCI_FUNC(dev->devfn) & 1))
++#else
++      if ((dev->device == PCI_DEVICE_ID_OPTI_82C558) &&
++          (!(PCI_FUNC(dev->devfn) & 1)))
++#endif
++              return; /* OPTI621 is more than only a IDE controller */
++
++      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 -Nur linux.org/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
+--- linux.org/drivers/ide/pdc202xx.c   Wed Nov 14 20:44:03 2001
++++ linux/drivers/ide/pdc202xx.c       Thu Jul 18 14:24:34 2002
+@@ -1,8 +1,7 @@
+ /*
+- *  linux/drivers/ide/pdc202xx.c      Version 0.30    Mar. 18, 2000
++ *  linux/drivers/ide/pdc202xx.c      Version 0.35    Mar. 30, 2002
+  *
+- *  Copyright (C) 1998-2000   Andre Hedrick <andre@linux-ide.org>
+- *  May be copied or modified under the terms of the GNU General Public License
++ *  Copyright (C) 1998-2002           Andre Hedrick <andre@linux-ide.org>
+  *
+  *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+  *  compiled into the kernel if you have more than one card installed.
+@@ -63,8 +62,25 @@
+ static int pdc202xx_get_info(char *, char **, off_t, int);
+ extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+-static struct pci_dev *bmide_dev;
++
++byte pdc202xx_proc = 0;
++
++#define PDC202_MAX_DEVS               5
++
++static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
++static int n_pdc202_devs;
++
++const char *pdc_quirk_drives[] = {
++      "QUANTUM FIREBALLlct08 08",
++      "QUANTUM FIREBALLP KA6.4",
++      "QUANTUM FIREBALLP KA9.1",
++      "QUANTUM FIREBALLP LM20.4",
++      "QUANTUM FIREBALLP KX13.6",
++      "QUANTUM FIREBALLP KX20.5",
++      "QUANTUM FIREBALLP KX27.3",
++      "QUANTUM FIREBALLP LM20.5",
++      NULL
++};
+ char *pdc202xx_pio_verbose (u32 drive_pci)
+ {
+@@ -108,7 +124,7 @@
+       u32 bibma  = pci_resource_start(dev, 4);
+       u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+       u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+-      u8 hi = 0, lo = 0, invalid_data_set = 0;
++      u8 hi = 0, lo = 0;
+         /*
+          * at that point bibma+0x2 et bibma+0xa are byte registers
+@@ -131,33 +147,31 @@
+       pci_read_config_dword(dev, 0x68, &reg68h);
+       pci_read_config_dword(dev, 0x6c, &reg6ch);
++      p += sprintf(p, "\n                                ");
+       switch(dev->device) {
+-              case PCI_DEVICE_ID_PROMISE_20268:
+-              case PCI_DEVICE_ID_PROMISE_20268R:
+-                      p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
+-                      invalid_data_set = 1;
+-                      break;
+               case PCI_DEVICE_ID_PROMISE_20267:
+-                      p += sprintf(p, "\n                                PDC20267 Chipset.\n");
+-                      break;
++                      p += sprintf(p, "Ultra100"); break;
+               case PCI_DEVICE_ID_PROMISE_20265:
+-                      p += sprintf(p, "\n                                PDC20265 Chipset.\n");
+-                      break;
++                      p += sprintf(p, "Ultra100 on M/B"); break;
++              case PCI_DEVICE_ID_PROMISE_20263:
++                      p += sprintf(p, "FastTrak 66"); break;
+               case PCI_DEVICE_ID_PROMISE_20262:
+-                      p += sprintf(p, "\n                                PDC20262 Chipset.\n");
+-                      break;
++                      p += sprintf(p, "Ultra66"); break;
+               case PCI_DEVICE_ID_PROMISE_20246:
+-                      p += sprintf(p, "\n                                PDC20246 Chipset.\n");
++                      p += sprintf(p, "Ultra33");
+                       reg50h |= 0x0c00;
+                       break;
+               default:
+-                      p += sprintf(p, "\n                                PDC202XX Chipset.\n");
+-                      break;
++                      p += sprintf(p, "Ultra Series"); break;
+       }
++      p += sprintf(p, " Chipset.\n");
+-      p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
+-      p += sprintf(p, "Burst Mode                           : %sabled\n", (sc1f & 0x01) ? "en" : "dis");
+-      p += sprintf(p, "Host Mode                            : %s\n", (sc1f & 0x08) ? "Tri-Stated" : "Normal");
++      p += sprintf(p, "------------------------------- General Status "
++                      "---------------------------------\n");
++      p += sprintf(p, "Burst Mode                           : %sabled\n",
++              (sc1f & 0x01) ? "en" : "dis");
++      p += sprintf(p, "Host Mode                            : %s\n",
++              (sc1f & 0x08) ? "Tri-Stated" : "Normal");
+       p += sprintf(p, "Bus Clocking                         : %s\n",
+               ((sc1f & 0xC0) == 0xC0) ? "100 External" :
+               ((sc1f & 0x80) == 0x80) ? "66 External" :
+@@ -170,7 +184,9 @@
+       SPLIT_BYTE(sc1e, hi, lo);
+       p += sprintf(p, "Status Polling Period                : %d\n", hi);
+       p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
++      p += sprintf(p, "--------------- Primary Channel "
++                      "---------------- Secondary Channel "
++                      "-------------\n");
+       p += sprintf(p, "                %s                         %s\n",
+               (c0&0x80)?"disabled":"enabled ",
+               (c1&0x80)?"disabled":"enabled ");
+@@ -180,63 +196,101 @@
+       p += sprintf(p, "           Mode %s                      Mode %s\n",
+               (sc1a & 0x01) ? "MASTER" : "PCI   ",
+               (sc1b & 0x01) ? "MASTER" : "PCI   ");
+-      if (!(invalid_data_set))
+-              p += sprintf(p, "                %s                     %s\n",
+-                      (sc1d & 0x08) ? "Error       " :
+-                      ((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+-                      (sc1d & 0x04) ? "Interrupting" :
+-                      (sc1d & 0x02) ? "FIFO Full   " :
+-                      (sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+-                      (sc1d & 0x80) ? "Error       " :
+-                      ((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+-                      (sc1d & 0x40) ? "Interrupting" :
+-                      (sc1d & 0x20) ? "FIFO Full   " :
+-                      (sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+-      p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+-      p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
+-              (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+-      if (!(invalid_data_set))
+-              p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
+-                      pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+-                      pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+-                      pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+-                      pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+-      if (!(invalid_data_set))
+-              p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
+-                      pdc202xx_pio_verbose(reg60h),
+-                      pdc202xx_pio_verbose(reg64h),
+-                      pdc202xx_pio_verbose(reg68h),
+-                      pdc202xx_pio_verbose(reg6ch));
++      p += sprintf(p, "                %s                     %s\n",
++              (sc1d & 0x08) ? "Error       " :
++              ((sc1d & 0x05) == 0x05) ? "Not My INTR " :
++              (sc1d & 0x04) ? "Interrupting" :
++              (sc1d & 0x02) ? "FIFO Full   " :
++              (sc1d & 0x01) ? "FIFO Empty  " : "????????????",
++              (sc1d & 0x80) ? "Error       " :
++              ((sc1d & 0x50) == 0x50) ? "Not My INTR " :
++              (sc1d & 0x40) ? "Interrupting" :
++              (sc1d & 0x20) ? "FIFO Full   " :
++              (sc1d & 0x10) ? "FIFO Empty  " : "????????????");
++      p += sprintf(p, "--------------- drive0 --------- drive1 "
++                      "-------- drive0 ---------- drive1 ------\n");
++      p += sprintf(p, "DMA enabled:    %s              %s "
++                      "            %s               %s\n",
++              (c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
++              (c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
++      p += sprintf(p, "DMA Mode:       %s           %s "
++                      "         %s            %s\n",
++              pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
++              pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
++              pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
++              pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
++      p += sprintf(p, "PIO Mode:       %s            %s "
++                      "          %s            %s\n",
++              pdc202xx_pio_verbose(reg60h),
++              pdc202xx_pio_verbose(reg64h),
++              pdc202xx_pio_verbose(reg68h),
++              pdc202xx_pio_verbose(reg6ch));
+ #if 0
+       p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+ #endif
+-      if (invalid_data_set)
+-              p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n");
++      return (char *)p;
++}
++
++static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
++{
++      char *p = buf;
++//    u32 bibma = pci_resource_start(dev, 4);
++
++//    u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
++//    u16 reg50h = 0, word88 = 0;
++//    int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
++
++      p += sprintf(p, "\n                                ");
++      switch(dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++                      p += sprintf(p, "SBFastTrak 133 Lite"); break;
++              case PCI_DEVICE_ID_PROMISE_20276:
++                      p += sprintf(p, "MBFastTrak 133 Lite"); break;
++              case PCI_DEVICE_ID_PROMISE_20275:
++                      p += sprintf(p, "MBUltra133"); break;
++              case PCI_DEVICE_ID_PROMISE_20271:
++                      p += sprintf(p, "FastTrak TX2000"); break;
++              case PCI_DEVICE_ID_PROMISE_20270:
++                      p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
++              case PCI_DEVICE_ID_PROMISE_20269:
++                      p += sprintf(p, "Ultra133 TX2"); break;
++              case PCI_DEVICE_ID_PROMISE_20268:
++                      p += sprintf(p, "Ultra100 TX2"); break;
++              default:
++                      p += sprintf(p, "Ultra series"); break;
++                      break;
++      }
++      p += sprintf(p, " Chipset.\n");
+       return (char *)p;
+ }
+ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+       char *p = buffer;
+-      p = pdc202xx_info(buffer, bmide_dev);
++      int i;
++
++      for (i = 0; i < n_pdc202_devs; i++) {
++              struct pci_dev *dev     = pdc202_devs[i];
++
++              switch(dev->device) {
++                      case PCI_DEVICE_ID_PROMISE_20277:
++                      case PCI_DEVICE_ID_PROMISE_20276:
++                      case PCI_DEVICE_ID_PROMISE_20275:
++                      case PCI_DEVICE_ID_PROMISE_20271:
++                      case PCI_DEVICE_ID_PROMISE_20269:
++                      case PCI_DEVICE_ID_PROMISE_20268:
++                      case PCI_DEVICE_ID_PROMISE_20270:
++                              p = pdc202xx_info_new(buffer, dev);
++                              break;
++                      default:
++                              p = pdc202xx_info(buffer, dev);
++                              break;
++              }
++      }
+       return p-buffer;        /* => must be less than 4k! */
+ }
+ #endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+-byte pdc202xx_proc = 0;
+-
+-const char *pdc_quirk_drives[] = {
+-      "QUANTUM FIREBALLlct08 08",
+-      "QUANTUM FIREBALLP KA6.4",
+-      "QUANTUM FIREBALLP LM20.4",
+-      "QUANTUM FIREBALLP KX20.5",
+-      "QUANTUM FIREBALLP KX27.3",
+-      "QUANTUM FIREBALLP LM20.5",
+-      NULL
+-};
+-
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-
+ /* A Register */
+ #define       SYNC_ERRDY_EN   0xC0
+@@ -347,6 +401,69 @@
+ #endif /* PDC202XX_DECODE_REGISTER_INFO */
++#if 0
++static byte pdc202xx_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev = HWIF(drive)->pci_dev;
++      byte mode = 0x00;
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20269:
++                      { mode |= 0x04; break; }
++              case PCI_DEVICE_ID_PROMISE_20270:
++              case PCI_DEVICE_ID_PROMISE_20268:
++                      { mode |= 0x03; break; }
++              case PCI_DEVICE_ID_PROMISE_20267:
++              case PCI_DEVICE_ID_PROMISE_20265:
++                      { mode |= 0x03; break; }
++              case PCI_DEVICE_ID_PROMISE_20263:
++              case PCI_DEVICE_ID_PROMISE_20262:
++                      { mode |= 0x02; break; }
++              case PCI_DEVICE_ID_PROMISE_20246:
++                      { mode |= 0x01; break; }
++              default:
++                      return (mode &= ~0xF8);
++      }
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = pdc202xx_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
++#else
++static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
++{
++      return speed;
++}
++#endif
++
+ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+ {
+       struct hd_driveid *id = drive->id;
+@@ -367,13 +484,13 @@
+       return 0;
+ }
+-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
++static int pdc202xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
++      byte speed              = pdc202xx_ratefilter(drive, xferspeed);
+       unsigned int            drive_conf;
+-      int                     err;
+       byte                    drive_pci, AP, BP, CP, DP;
+       byte                    TA = 0, TB = 0, TC = 0;
+@@ -385,10 +502,8 @@
+               default: return -1;
+       }
+-      if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))      return -1;
+-
+-      if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
+-              goto skip_register_hell;
++      if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
++              return -1;
+       pci_read_config_dword(dev, drive_pci, &drive_conf);
+       pci_read_config_byte(dev, (drive_pci), &AP);
+@@ -396,34 +511,32 @@
+       pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+       pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (speed >= XFER_SW_DMA_0) {
+-              if ((BP & 0xF0) && (CP & 0x0F)) {
+-                      /* clear DMA modes of upper 842 bits of B Register */
+-                      /* clear PIO forced mode upper 1 bit of B Register */
+-                      pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
+-                      pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+-
+-                      /* clear DMA modes of lower 8421 bits of C Register */
+-                      pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
+-                      pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+-              }
+-      } else {
+-#else
+-      {
+-#endif /* CONFIG_BLK_DEV_IDEDMA */
++      if (speed < XFER_SW_DMA_0) {
+               if ((AP & 0x0F) || (BP & 0x07)) {
+                       /* clear PIO modes of lower 8421 bits of A Register */
+-                      pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
++                      pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+                       pci_read_config_byte(dev, (drive_pci), &AP);
+                       /* clear PIO modes of lower 421 bits of B Register */
+-                      pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
++                      pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+                       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+                       pci_read_config_byte(dev, (drive_pci), &AP);
+                       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+               }
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      } else {
++              if ((BP & 0xF0) && (CP & 0x0F)) {
++                      /* clear DMA modes of upper 842 bits of B Register */
++                      /* clear PIO forced mode upper 1 bit of B Register */
++                      pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
++                      pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
++
++                      /* clear DMA modes of lower 8421 bits of C Register */
++                      pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
++                      pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
++              }
++#endif /* CONFIG_BLK_DEV_IDEDMA */
+       }
+       pci_read_config_byte(dev, (drive_pci), &AP);
+@@ -432,18 +545,19 @@
+       switch(speed) {
+ #ifdef CONFIG_BLK_DEV_IDEDMA
++              /* case XFER_UDMA_6: */
+               case XFER_UDMA_5:
+-              case XFER_UDMA_4:       TB = 0x20; TC = 0x01; break;    /* speed 8 == UDMA mode 4 */
+-              case XFER_UDMA_3:       TB = 0x40; TC = 0x02; break;    /* speed 7 == UDMA mode 3 */
+-              case XFER_UDMA_2:       TB = 0x20; TC = 0x01; break;    /* speed 6 == UDMA mode 2 */
+-              case XFER_UDMA_1:       TB = 0x40; TC = 0x02; break;    /* speed 5 == UDMA mode 1 */
+-              case XFER_UDMA_0:       TB = 0x60; TC = 0x03; break;    /* speed 4 == UDMA mode 0 */
+-              case XFER_MW_DMA_2:     TB = 0x60; TC = 0x03; break;    /* speed 4 == MDMA mode 2 */
+-              case XFER_MW_DMA_1:     TB = 0x60; TC = 0x04; break;    /* speed 3 == MDMA mode 1 */
+-              case XFER_MW_DMA_0:     TB = 0x60; TC = 0x05; break;    /* speed 2 == MDMA mode 0 */
+-              case XFER_SW_DMA_2:     TB = 0x60; TC = 0x05; break;    /* speed 0 == SDMA mode 2 */
+-              case XFER_SW_DMA_1:     TB = 0x80; TC = 0x06; break;    /* speed 1 == SDMA mode 1 */
+-              case XFER_SW_DMA_0:     TB = 0xC0; TC = 0x0B; break;    /* speed 0 == SDMA mode 0 */
++              case XFER_UDMA_4:       TB = 0x20; TC = 0x01; break;
++              case XFER_UDMA_3:       TB = 0x40; TC = 0x02; break;
++              case XFER_UDMA_2:       TB = 0x20; TC = 0x01; break;
++              case XFER_UDMA_1:       TB = 0x40; TC = 0x02; break;
++              case XFER_UDMA_0:       TB = 0x60; TC = 0x03; break;
++              case XFER_MW_DMA_2:     TB = 0x60; TC = 0x03; break;
++              case XFER_MW_DMA_1:     TB = 0x60; TC = 0x04; break;
++              case XFER_MW_DMA_0:     TB = 0x60; TC = 0x05; break;
++              case XFER_SW_DMA_2:     TB = 0x60; TC = 0x05; break;
++              case XFER_SW_DMA_1:     TB = 0x80; TC = 0x06; break;
++              case XFER_SW_DMA_0:     TB = 0xC0; TC = 0x0B; break;
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+               case XFER_PIO_4:        TA = 0x01; TB = 0x04; break;
+               case XFER_PIO_3:        TA = 0x02; TB = 0x06; break;
+@@ -453,16 +567,14 @@
+               default:                TA = 0x09; TB = 0x13; break;
+       }
++      if (speed < XFER_SW_DMA_0) {
++              pci_write_config_byte(dev, (drive_pci), AP|TA);
++              pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-        if (speed >= XFER_SW_DMA_0) {
++      } else {
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+-      } else {
+-#else
+-      {
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-              pci_write_config_byte(dev, (drive_pci), AP|TA);
+-              pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+       }
+ #if PDC202XX_DECODE_REGISTER_INFO
+@@ -476,14 +588,6 @@
+       decode_registers(REG_C, CP);
+       decode_registers(REG_D, DP);
+ #endif /* PDC202XX_DECODE_REGISTER_INFO */
+-
+-skip_register_hell:
+-
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
+-      err = ide_config_drive_speed(drive, speed);
+-      drive->current_speed = speed;
+-
+ #if PDC202XX_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d 0x%08x ",
+               drive->name, ide_xfer_verbose(speed),
+@@ -491,7 +595,156 @@
+               pci_read_config_dword(dev, drive_pci, &drive_conf);
+       printk("0x%08x\n", drive_conf);
+ #endif /* PDC202XX_DEBUG_DRIVE_INFO */
+-      return err;
++
++      return (ide_config_drive_speed(drive, speed));
++}
++
++static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte xferspeed)
++{
++      ide_hwif_t *hwif        = HWIF(drive);
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      unsigned long indexreg  = (hwif->dma_base + 1);
++      unsigned long datareg   = (hwif->dma_base + 3);
++#else
++      struct pci_dev *dev     = hwif->pci_dev;
++      unsigned long high_16   = pci_resource_start(dev, 4);
++      unsigned long indexreg  = high_16 + (hwif->channel ? 0x09 : 0x01);
++      unsigned long datareg   = (indexreg + 2);
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++      byte thold              = 0x10;
++      byte adj                = (drive->dn%2) ? 0x08 : 0x00;
++      byte speed              = pdc202xx_ratefilter(drive, xferspeed);
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      if (speed == XFER_UDMA_2) {
++              OUT_BYTE((thold + adj), indexreg);
++              OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
++      }
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++      switch (speed) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
++              case XFER_UDMA_7:
++                      speed = XFER_UDMA_6;
++              case XFER_UDMA_6:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x1a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x01, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xcb, datareg);
++                      break;
++              case XFER_UDMA_5:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x1a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x02, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xcb, datareg);
++                      break;
++              case XFER_UDMA_4:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x1a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x03, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xcd, datareg);
++                      break;
++              case XFER_UDMA_3:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x1a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x05, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xcd, datareg);
++                      break;
++              case XFER_UDMA_2:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x2a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x07, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xcd, datareg);
++                      break;
++              case XFER_UDMA_1:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x3a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x0a, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xd0, datareg);
++                      break;
++              case XFER_UDMA_0:
++                      OUT_BYTE((0x10 + adj), indexreg);
++                      OUT_BYTE(0x4a, datareg);
++                      OUT_BYTE((0x11 + adj), indexreg);
++                      OUT_BYTE(0x0f, datareg);
++                      OUT_BYTE((0x12 + adj), indexreg);
++                      OUT_BYTE(0xd5, datareg);
++                      break;
++              case XFER_MW_DMA_2:
++                      OUT_BYTE((0x0e + adj), indexreg);
++                      OUT_BYTE(0x69, datareg);
++                      OUT_BYTE((0x0f + adj), indexreg);
++                      OUT_BYTE(0x25, datareg);
++                      break;
++              case XFER_MW_DMA_1:
++                      OUT_BYTE((0x0e + adj), indexreg);
++                      OUT_BYTE(0x6b, datareg);
++                      OUT_BYTE((0x0f+ adj), indexreg);
++                      OUT_BYTE(0x27, datareg);
++                      break;
++              case XFER_MW_DMA_0:
++                      OUT_BYTE((0x0e + adj), indexreg);
++                      OUT_BYTE(0xdf, datareg);
++                      OUT_BYTE((0x0f + adj), indexreg);
++                      OUT_BYTE(0x5f, datareg);
++                      break;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++              case XFER_PIO_4:
++                      OUT_BYTE((0x0c + adj), indexreg);
++                      OUT_BYTE(0x23, datareg);
++                      OUT_BYTE((0x0d + adj), indexreg);
++                      OUT_BYTE(0x09, datareg);
++                      OUT_BYTE((0x13 + adj), indexreg);
++                      OUT_BYTE(0x25, datareg);
++                      break;
++              case XFER_PIO_3:
++                      OUT_BYTE((0x0c + adj), indexreg);
++                      OUT_BYTE(0x27, datareg);
++                      OUT_BYTE((0x0d + adj), indexreg);
++                      OUT_BYTE(0x0d, datareg);
++                      OUT_BYTE((0x13 + adj), indexreg);
++                      OUT_BYTE(0x35, datareg);
++                      break;
++              case XFER_PIO_2:
++                      OUT_BYTE((0x0c + adj), indexreg);
++                      OUT_BYTE(0x23, datareg);
++                      OUT_BYTE((0x0d + adj), indexreg);
++                      OUT_BYTE(0x26, datareg);
++                      OUT_BYTE((0x13 + adj), indexreg);
++                      OUT_BYTE(0x64, datareg);
++                      break;
++              case XFER_PIO_1:
++                      OUT_BYTE((0x0c + adj), indexreg);
++                      OUT_BYTE(0x46, datareg);
++                      OUT_BYTE((0x0d + adj), indexreg);
++                      OUT_BYTE(0x29, datareg);
++                      OUT_BYTE((0x13 + adj), indexreg);
++                      OUT_BYTE(0xa4, datareg);
++                      break;
++              case XFER_PIO_0:
++                      OUT_BYTE((0x0c + adj), indexreg);
++                      OUT_BYTE(0xfb, datareg);
++                      OUT_BYTE((0x0d + adj), indexreg);
++                      OUT_BYTE(0x2b, datareg);
++                      OUT_BYTE((0x13 + adj), indexreg);
++                      OUT_BYTE(0xac, datareg);
++                      break;
++              default:
++      }
++
++      return (ide_config_drive_speed(drive, speed));
+ }
+ /*   0    1    2    3    4    5    6   7   8
+@@ -517,25 +770,81 @@
+ }
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
++static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
++//    byte mode               = pdc202xx_ratemask(drive);
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       unsigned long high_16   = pci_resource_start(dev, 4);
+       unsigned long dma_base  = hwif->dma_base;
+-      byte unit               = (drive->select.b.unit & 0x01);
+-
++      unsigned long indexreg  = dma_base + 1;
++      unsigned long datareg   = dma_base + 3;
++      byte iordy              = 0x13;
++      byte adj                = (drive->dn%2) ? 0x08 : 0x00;
++      byte cable              = 0;
++      byte jumpbit            = 0;
+       unsigned int            drive_conf;
+-      byte                    drive_pci;
++      byte                    drive_pci = 0;
+       byte                    test1, test2, speed = -1;
+       byte                    AP;
+       unsigned short          EP;
+-      byte CLKSPD             = IN_BYTE(high_16 + 0x11);
+-      byte udma_33            = ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+-      byte udma_66            = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
+-      byte udma_100           = (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0;
++      byte CLKSPD             = 0;
++      byte udma_33            = 1;
++      byte udma_66            = (eighty_ninty_three(drive)) ? 1 : 0;
++      byte udma_100           = 0;
++      byte udma_133           = 0;
++      byte mask               = hwif->channel ? 0x08 : 0x02;
++      unsigned short c_mask   = hwif->channel ? (1<<11) : (1<<10);
++
++      byte ultra_66           = ((id->dma_ultra & 0x0010) ||
++                                 (id->dma_ultra & 0x0008)) ? 1 : 0;
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20269:
++                      udma_133 = (udma_66) ? 1 : 0;
++                      udma_100 = (udma_66) ? 1 : 0;
++                      OUT_BYTE(0x0b, (hwif->dma_base + 1));
++                      cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
++                      jumpbit = 1;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20270:
++                      udma_100 = 1;
++                      udma_66 = 1;
++                      OUT_BYTE(0x0b, (hwif->dma_base + 1));
++                      cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
++                      jumpbit = 1;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20268:
++                      udma_100 = (udma_66) ? 1 : 0;
++                      OUT_BYTE(0x0b, (hwif->dma_base + 1));
++                      cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
++                      jumpbit = 1;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20267:
++              case PCI_DEVICE_ID_PROMISE_20265:
++                      udma_100 = (udma_66) ? 1 : 0;
++                      pci_read_config_word(dev, 0x50, &EP);
++                      cable = (EP & c_mask);
++                      jumpbit = 0;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20263:
++              case PCI_DEVICE_ID_PROMISE_20262:
++                      pci_read_config_word(dev, 0x50, &EP);
++                      cable = (EP & c_mask);
++                      jumpbit = 0;
++                      break;
++              default:
++                      udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
++                      break;
++      }
++      if (!jumpbit)
++              CLKSPD = IN_BYTE(high_16 + 0x11);
+       /*
+        * Set the control register to use the 66Mhz system
+        * clock for UDMA 3/4 mode operation. If one drive on
+@@ -549,47 +858,51 @@
+        * parameters.
+        */
+-      byte mask               = hwif->channel ? 0x08 : 0x02;
+-      unsigned short c_mask   = hwif->channel ? (1<<11) : (1<<10);
+-      byte ultra_66           = ((id->dma_ultra & 0x0010) ||
+-                                 (id->dma_ultra & 0x0008)) ? 1 : 0;
+-      byte ultra_100          = ((id->dma_ultra & 0x0020) ||
+-                                 (id->dma_ultra & 0x0010) ||
+-                                 (id->dma_ultra & 0x0008)) ? 1 : 0;
+-
+-      if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
+-              goto jump_pci_mucking;
+-
+-      pci_read_config_word(dev, 0x50, &EP);
+-
+-      if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {
+-#ifdef DEBUG
+-              printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
++      if ((ultra_66) && (cable)) {
++//#ifdef DEBUG
++#if 1
++              printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
++                      "requires an 80-pin cable for Ultra66 operation.\n",
++                      hwif->channel ? "Secondary" : "Primary");
+               printk("         Switching to Ultra33 mode.\n");
+ #endif /* DEBUG */
+               /* Primary   : zero out second bit */
+               /* Secondary : zero out fourth bit */
+-              OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
++              if (!jumpbit)
++                      OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
++              printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
++              printk("%s reduced to Ultra33 mode.\n", drive->name);
++              udma_66 = 0;
+       } else {
+-              if ((ultra_66) || (ultra_100)) {
++              if (ultra_66) {
+                       /*
+                        * check to make sure drive on same channel
+                        * is u66 capable
+                        */
+                       if (hwif->drives[!(drive->dn%2)].id) {
+-                              if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) ||
+-                                  (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
+-                                  (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
+-                                      OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
++                              if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
++                                      if (!jumpbit)
++                                              OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+                               } else {
+-                                      OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
++                                      if (!jumpbit)
++                                              OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+                               }
+                       } else { /* udma4 drive by itself */
+-                              OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
++                              if (!jumpbit)
++                                      OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+                       }
+               }
+       }
++      if (jumpbit) {
++              if (drive->media != ide_disk)   return ide_dma_off_quietly;
++              if (id->capability & 4) {       /* IORDY_EN & PREFETCH_EN */
++                      OUT_BYTE((iordy + adj), indexreg);
++                      OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
++              }
++              goto jumpbit_is_set;
++      }
++
+       switch(drive->dn) {
+               case 0: drive_pci = 0x60;
+                       pci_read_config_dword(dev, drive_pci, &drive_conf);
+@@ -631,7 +944,10 @@
+ chipset_is_set:
+-      if (drive->media != ide_disk)   return ide_dma_off_quietly;
++      if (drive->media != ide_disk) {
++              hwif->tuneproc(drive, 5);
++              return ide_dma_off_quietly;
++      }
+       pci_read_config_byte(dev, (drive_pci), &AP);
+       if (id->capability & 4) /* IORDY_EN */
+@@ -640,31 +956,33 @@
+       if (drive->media == ide_disk)   /* PREFETCH_EN */
+               pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+-jump_pci_mucking:
++jumpbit_is_set:
+-      if ((id->dma_ultra & 0x0020) && (udma_100))     speed = XFER_UDMA_5;
+-      else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4;
+-      else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3;
+-      else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2;
+-      else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1;
+-      else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0;
++      if ((id->dma_ultra & 0x0040)&&(udma_133))       speed = XFER_UDMA_6;
++      else if ((id->dma_ultra & 0x0020)&&(udma_100))  speed = XFER_UDMA_5;
++      else if ((id->dma_ultra & 0x0010)&&(udma_66))   speed = XFER_UDMA_4;
++      else if ((id->dma_ultra & 0x0008)&&(udma_66))   speed = XFER_UDMA_3;
++      else if ((id->dma_ultra & 0x0004)&&(udma_33))   speed = XFER_UDMA_2;
++      else if ((id->dma_ultra & 0x0002)&&(udma_33))   speed = XFER_UDMA_1;
++      else if ((id->dma_ultra & 0x0001)&&(udma_33))   speed = XFER_UDMA_0;
+       else if (id->dma_mword & 0x0004)                speed = XFER_MW_DMA_2;
+       else if (id->dma_mword & 0x0002)                speed = XFER_MW_DMA_1;
+       else if (id->dma_mword & 0x0001)                speed = XFER_MW_DMA_0;
+-      else if (id->dma_1word & 0x0004)                speed = XFER_SW_DMA_2;
+-      else if (id->dma_1word & 0x0002)                speed = XFER_SW_DMA_1;
+-      else if (id->dma_1word & 0x0001)                speed = XFER_SW_DMA_0;
++      else if ((id->dma_1word & 0x0004)&&(!jumpbit))  speed = XFER_SW_DMA_2;
++      else if ((id->dma_1word & 0x0002)&&(!jumpbit))  speed = XFER_SW_DMA_1;
++      else if ((id->dma_1word & 0x0001)&&(!jumpbit))  speed = XFER_SW_DMA_0;
+       else {
+               /* restore original pci-config space */
+-              if (dev->device != PCI_DEVICE_ID_PROMISE_20268)
++              if (!jumpbit)
+                       pci_write_config_dword(dev, drive_pci, drive_conf);
++              hwif->tuneproc(drive, 5);
+               return ide_dma_off_quietly;
+       }
+-      outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+-      (void) pdc202xx_tune_chipset(drive, speed);
++      (void) hwif->speedproc(drive, speed);
+-      return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
++      return ((int)   ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
++                      ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on : 
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+@@ -673,9 +991,11 @@
+ static int config_drive_xfer_rate (ide_drive_t *drive)
+ {
+-      struct hd_driveid *id = drive->id;
+-      ide_hwif_t *hwif = HWIF(drive);
+-      ide_dma_action_t dma_func = ide_dma_off_quietly;
++      struct hd_driveid *id           = drive->id;
++      ide_hwif_t *hwif                = HWIF(drive);
++      ide_dma_action_t dma_func       = ide_dma_off_quietly;
++
++      drive->init_speed = 0;
+       if (id && (id->capability & 1) && hwif->autodma) {
+               /* Consult the list of known "bad" drives */
+@@ -685,9 +1005,9 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x007F) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, 1);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -697,7 +1017,7 @@
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+-                              dma_func = config_chipset_for_dma(drive, 0);
++                              dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+@@ -706,7 +1026,7 @@
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, 0);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -716,10 +1036,10 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              (void) config_chipset_for_pio(drive, 5);
++              hwif->tuneproc(drive, 5);
+       }
+-      return HWIF(drive)->dmaproc(dma_func, drive);
++      return hwif->dmaproc(dma_func, drive);
+ }
+ int pdc202xx_quirkproc (ide_drive_t *drive)
+@@ -732,17 +1052,68 @@
+  */
+ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
+-      byte dma_stat = 0, sc1d = 0;
+-      unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
+-      unsigned long dma_base  = HWIF(drive)->dma_base;
++      byte dma_stat           = 0;
++      byte sc1d               = 0;
++      byte newchip            = 0;
++      byte clock              = 0;
++      byte hardware48fix      = 0;
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      unsigned long high_16   = pci_resource_start(dev, 4);
++      unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
++      unsigned long dma_base  = hwif->dma_base;
++
++      switch (dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20270:
++              case PCI_DEVICE_ID_PROMISE_20269:
++              case PCI_DEVICE_ID_PROMISE_20268:
++                      newchip = 1;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20267:
++              case PCI_DEVICE_ID_PROMISE_20265:
++                      hardware48fix = 1;
++                      clock = IN_BYTE(high_16 + 0x11);
++              default:
++                      break;
++      }
+       switch (func) {
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
++              case ide_dma_begin:
++                      /* Note that this is done *after* the cmd has
++                       * been issued to the drive, as per the BM-IDE spec.
++                       * The Promise Ultra33 doesn't work correctly when
++                       * we do this part before issuing the drive cmd.
++                       */
++                      if ((drive->addressing == 1) && (hardware48fix)) {
++                              struct request *rq = HWGROUP(drive)->rq;
++                              unsigned long word_count = 0;
++
++                              OUT_BYTE(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
++                              word_count = (rq->nr_sectors << 8);
++                              word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
++                              outl(word_count, atapi_reg);
++                      }
++                      break;
++              case ide_dma_end:
++                      if ((drive->addressing == 1) && (hardware48fix)) {
++                              outl(0, atapi_reg);     /* zero out extra */
++                              clock = IN_BYTE(high_16 + 0x11);
++                              OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
++                      }
++                      break;
+               case ide_dma_test_irq:  /* returns 1 if dma irq issued, 0 otherwise */
+-                      dma_stat = inb(dma_base+2);
+-                      sc1d = inb(high_16 + 0x001d);
+-                      if (HWIF(drive)->channel) {
++                      dma_stat = IN_BYTE(dma_base+2);
++                      if (newchip)
++                              return (dma_stat & 4) == 4;
++
++                      sc1d = IN_BYTE(high_16 + 0x001d);
++                      if (hwif->channel) {
+                               if ((sc1d & 0x50) == 0x50) goto somebody_else;
+                               else if ((sc1d & 0x40) == 0x40)
+                                       return (dma_stat & 4) == 4;
+@@ -755,8 +1126,8 @@
+                       return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
+               case ide_dma_lostirq:
+               case ide_dma_timeout:
+-                      if (HWIF(drive)->resetproc != NULL)
+-                              HWIF(drive)->resetproc(drive);
++                      if (hwif->resetproc != NULL)
++                              hwif->resetproc(drive);
+               default:
+                       break;
+       }
+@@ -764,10 +1135,19 @@
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-void pdc202xx_reset (ide_drive_t *drive)
++void pdc202xx_new_reset (ide_drive_t *drive)
++{
++      /*
++       * Deleted this because it is redundant from the caller.
++       */
++      printk("PDC202XX: %s channel reset.\n",
++              HWIF(drive)->channel ? "Secondary" : "Primary");
++}
++
++void pdc202xx_reset_pci (struct pci_dev *dev)
+ {
+-      unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
+-      byte udma_speed_flag    = inb(high_16 + 0x001f);
++      unsigned long high_16   = pci_resource_start(dev, 4);
++      byte udma_speed_flag    = IN_BYTE(high_16 + 0x001f);
+       OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+       mdelay(100);
+@@ -775,50 +1155,102 @@
+       mdelay(2000);           /* 2 seconds ?! */
+ }
+-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
++void pdc202xx_reset_host (ide_hwif_t *hwif)
++{
++      pdc202xx_reset_pci(hwif->pci_dev);
++      printk("PDC202XX: %s channel reset.\n",
++              hwif->channel ? "Secondary" : "Primary");
++}
++
++void pdc202xx_reset (ide_drive_t *drive)
++{
++      pdc202xx_reset_host(HWIF(drive));
++}
++
++/*
++ * Since SUN Cobalt is attempting to do this operation, I should disclose
++ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
++ * HOTSWAP ATA Infrastructure.
++ */
++static int pdc202xx_tristate (ide_drive_t * drive, int state)
+ {
+-      unsigned long high_16 = pci_resource_start(dev, 4);
+-      byte udma_speed_flag    = inb(high_16 + 0x001f);
+-      byte primary_mode       = inb(high_16 + 0x001a);
+-      byte secondary_mode     = inb(high_16 + 0x001b);
+-
+-      if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
+-          (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+-          (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
+-              /*
+-               * software reset -  this is required because the bios
+-               * will set UDMA timing on if the hdd supports it. The
+-               * user may want to turn udma off. A bug in the pdc20262
+-               * is that it cannot handle a downgrade in timing from UDMA
+-               * to DMA. Disk accesses after issuing a set feature command
+-               * will result in errors. A software reset leaves the timing
+-               * registers intact, but resets the drives.
+-               */
+-
+-              OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+-              mdelay(100);
+-              OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+-              mdelay(2000);   /* 2 seconds ?! */
++#if 0
++      ide_hwif_t *hwif        = HWIF(drive);
++      unsigned long high_16   = pci_resource_start(hwif->pci_dev, 4);
++      byte sc1f               = IN_BYTE(high_16 + 0x001f);
++
++      if (!hwif)
++              return -EINVAL;
++
++//    hwif->bus_state = state;
++
++      if (state) {
++              OUT_BYTE(sc1f | 0x08, high_16 + 0x001f);
++      } else {
++              OUT_BYTE(sc1f & ~0x08, high_16 + 0x001f);
+       }
++#endif
++      return 0;
++}
++
++unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
++{
++      unsigned long high_16   = pci_resource_start(dev, 4);
++      byte udma_speed_flag    = IN_BYTE(high_16 + 0x001f);
++      byte primary_mode       = IN_BYTE(high_16 + 0x001a);
++      byte secondary_mode     = IN_BYTE(high_16 + 0x001b);
++      byte newchip            = 0;
+       if (dev->resource[PCI_ROM_RESOURCE].start) {
+-              pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+-              printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
++              pci_write_config_dword(dev, PCI_ROM_ADDRESS,
++                      dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
++              printk("%s: ROM enabled at 0x%08lx\n",
++                      name, dev->resource[PCI_ROM_RESOURCE].start);
+       }
+-      if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+-              byte irq = 0, irq2 = 0;
+-              pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+-              pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);    /* 0xbc */
+-              if ((irq != irq2) &&
+-                  (dev->device != PCI_DEVICE_ID_PROMISE_20265) &&
+-                  (dev->device != PCI_DEVICE_ID_PROMISE_20267) &&
+-                  (dev->device != PCI_DEVICE_ID_PROMISE_20268)) {
+-                      pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+-                      printk("%s: pci-config space interrupt mirror fixed.\n", name);
+-              }
++      switch (dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20269:
++              case PCI_DEVICE_ID_PROMISE_20270:
++              case PCI_DEVICE_ID_PROMISE_20268:
++                      newchip = 1;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20267:
++              case PCI_DEVICE_ID_PROMISE_20265:
++                      pdc202xx_reset_pci(dev);
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20263:
++              case PCI_DEVICE_ID_PROMISE_20262:
++                      /*
++                       * software reset -  this is required because the bios
++                       * will set UDMA timing on if the hdd supports it. The
++                       * user may want to turn udma off. A bug in the pdc20262
++                       * is that it cannot handle a downgrade in timing from
++                       * UDMA to DMA. Disk accesses after issuing a set
++                       * feature command will result in errors. A software
++                       * reset leaves the timing registers intact,
++                       * but resets the drives.
++                       */
++                      pdc202xx_reset_pci(dev);
++              default:
++                      if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
++                              byte irq = 0, irq2 = 0;
++                              pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
++                              pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);    /* 0xbc */
++                              if (irq != irq2) {
++                                      pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
++                                      printk("%s: pci-config space interrupt mirror fixed.\n", name);
++                              }
++                      }
++                      break;
+       }
++      if (newchip)
++              goto fttk_tx_series;
++
+       printk("%s: (U)DMA Burst Bit %sABLED " \
+               "Primary %s Mode " \
+               "Secondary %s Mode.\n",
+@@ -830,8 +1262,8 @@
+ #ifdef CONFIG_PDC202XX_BURST
+       if (!(udma_speed_flag & 1)) {
+               printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
+-              outb(udma_speed_flag|1, high_16 + 0x001f);
+-              printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
++              OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
++              printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
+       }
+ #endif /* CONFIG_PDC202XX_BURST */
+@@ -839,25 +1271,29 @@
+       if (!(primary_mode & 1)) {
+               printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
+                       name, primary_mode, (primary_mode|1));
+-              outb(primary_mode|1, high_16 + 0x001a);
+-              printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
++              OUT_BYTE(primary_mode|1, high_16 + 0x001a);
++              printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+       }
+       if (!(secondary_mode & 1)) {
+               printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
+                       name, secondary_mode, (secondary_mode|1));
+-              outb(secondary_mode|1, high_16 + 0x001b);
+-              printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
++              OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
++              printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+       }
+ #endif /* CONFIG_PDC202XX_MASTER */
++fttk_tx_series:
++
++      pdc202_devs[n_pdc202_devs++] = dev;
++
+ #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+       if (!pdc202xx_proc) {
+               pdc202xx_proc = 1;
+-              bmide_dev = dev;
+               pdc202xx_display_info = &pdc202xx_get_info;
+       }
+ #endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
++
+       return dev->irq;
+ }
+@@ -866,21 +1302,32 @@
+       unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+       unsigned short CIS;
+-      pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+-      return ((CIS & mask) ? 0 : 1);
++        switch(hwif->pci_dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20269:
++              case PCI_DEVICE_ID_PROMISE_20268:
++              case PCI_DEVICE_ID_PROMISE_20270:
++                      OUT_BYTE(0x0b, (hwif->dma_base + 1));
++                      return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
++              case PCI_DEVICE_ID_PROMISE_20267:
++                      hwif->addressing = (hwif->channel) ? 0 : 1;
++              default:
++                      pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
++                      return (!(CIS & mask));
++      }
+ }
+ void __init ide_init_pdc202xx (ide_hwif_t *hwif)
+ {
+-      hwif->tuneproc  = &pdc202xx_tune_drive;
+-      hwif->speedproc = &pdc202xx_tune_chipset;
+-      hwif->quirkproc = &pdc202xx_quirkproc;
+-
+-      if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
+-          (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+-          (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
+-              hwif->resetproc = &pdc202xx_reset;
+-      }
++      hwif->tuneproc  = &pdc202xx_tune_drive;
++      hwif->quirkproc = &pdc202xx_quirkproc;
++
++      hwif->drives[0].autotune = 1;
++      hwif->drives[1].autotune = 1;
++      hwif->autodma = 0;
+ #undef CONFIG_PDC202XX_32_UNMASK
+ #ifdef CONFIG_PDC202XX_32_UNMASK
+@@ -890,19 +1337,85 @@
+       hwif->drives[1].unmask = 1;
+ #endif /* CONFIG_PDC202XX_32_UNMASK */
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-      if (hwif->dma_base) {
+-              hwif->dmaproc = &pdc202xx_dmaproc;
+-              if (!noautodma)
+-                      hwif->autodma = 1;
+-      } else {
+-              hwif->drives[0].autotune = 1;
+-              hwif->drives[1].autotune = 1;
+-              hwif->autodma = 0;
++        switch(hwif->pci_dev->device) {
++              case PCI_DEVICE_ID_PROMISE_20277:
++              case PCI_DEVICE_ID_PROMISE_20276:
++              case PCI_DEVICE_ID_PROMISE_20275:
++              case PCI_DEVICE_ID_PROMISE_20271:
++              case PCI_DEVICE_ID_PROMISE_20269:
++              case PCI_DEVICE_ID_PROMISE_20268:
++              case PCI_DEVICE_ID_PROMISE_20270:
++                      hwif->speedproc = &pdc202xx_new_tune_chipset;
++                      hwif->resetproc = &pdc202xx_new_reset;
++                      break;
++              case PCI_DEVICE_ID_PROMISE_20267:
++              case PCI_DEVICE_ID_PROMISE_20265:
++              case PCI_DEVICE_ID_PROMISE_20263:
++              case PCI_DEVICE_ID_PROMISE_20262:
++                      hwif->busproc   = &pdc202xx_tristate;
++                      hwif->resetproc = &pdc202xx_reset;
++              case PCI_DEVICE_ID_PROMISE_20246:
++                      hwif->speedproc = &pdc202xx_tune_chipset;
++              default:
++                      break;
+       }
+-#else /* !CONFIG_BLK_DEV_IDEDMA */
+-      hwif->drives[0].autotune = 1;
+-      hwif->drives[1].autotune = 1;
+-      hwif->autodma = 0;
++
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &pdc202xx_dmaproc;
++# ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++# endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      printk("%s: IDE controller on PCI bus %02x dev %02x\n",
++              d->name, dev->bus->number, dev->devfn);
++      ide_setup_pci_device(dev, d);
++}
++
++void __init fixup_device_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      struct pci_dev *dev2 = NULL, *findev;
++      ide_pci_device_t *d2;
++
++      if ((dev->bus->self &&
++           dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
++          (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
++              if (PCI_SLOT(dev->devfn) & 2) {
++                      return;
++              }
++              d->extra = 0;
++              pci_for_each_dev(findev) {
++                      if ((findev->vendor == dev->vendor) &&
++                          (findev->device == dev->device) &&
++                          (PCI_SLOT(findev->devfn) & 2)) {
++                              byte irq = 0, irq2 = 0;
++                              dev2 = findev;
++                              pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
++                              pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
++                              if (irq != irq2) {
++                                      dev2->irq = dev->irq;
++                                      pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
++                              }
++                      }
++              }
++      }
++
++      printk("%s: IDE controller on PCI bus %02x dev %02x\n",
++              d->name, dev->bus->number, dev->devfn);
++      ide_setup_pci_device(dev, d);
++      if (!dev2)
++              return;
++      d2 = d;
++      printk("%s: IDE controller on PCI bus %02x dev %02x\n",
++              d2->name, dev2->bus->number, dev2->devfn);
++      ide_setup_pci_device(dev2, d2);
++}
+diff -Nur linux.org/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
+--- linux.org/drivers/ide/pdc4030.c    Wed Jul 18 03:53:55 2001
++++ linux/drivers/ide/pdc4030.c        Thu Jul 18 14:24:34 2002
+@@ -168,7 +168,8 @@
+       if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+               return 1;
+-      if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
++      if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF ||
++          IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
+               return 0;
+       }
+       if (IDE_CONTROL_REG)
+@@ -181,7 +182,7 @@
+                       "%s: Failed Promise read config!\n",hwif->name);
+               return 0;
+       }
+-      ide_input_data(drive,&ident,SECTOR_WORDS);
++      ata_input_data(drive, &ident, SECTOR_WORDS);
+       if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+               return 0;
+       }
+@@ -234,7 +235,7 @@
+ #ifdef DEBUG
+               printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
+-#endif
++#endif /* DEBUG */
+               ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+               memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
+               h->noprobe = (h-1)->noprobe;
+@@ -298,8 +299,6 @@
+       }
+ }
+-
+-
+ /*
+  * promise_read_intr() is the handler for disk read/multread interrupts
+  */
+@@ -309,10 +308,13 @@
+       int total_remaining;
+       unsigned int sectors_left, sectors_avail, nsect;
+       struct request *rq;
++#ifdef CONFIG_IDE_TASKFILE_IO
++      unsigned long flags;
++      char *to;
++#endif /* CONFIG_IDE_TASKFILE_IO */
+-      if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+-              return ide_error(drive, "promise_read_intr", stat);
+-      }
++      if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT))
++              return DRIVER(drive)->error(drive, "promise_read_intr", stat);
+ read_again:
+       do {
+@@ -330,20 +332,36 @@
+       if (nsect > sectors_avail)
+               nsect = sectors_avail;
+       sectors_avail -= nsect;
+-      ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
++#ifdef CONFIG_IDE_TASKFILE_IO
++      to = ide_map_buffer(rq, &flags);
++      ata_input_data(drive, to, nsect * SECTOR_WORDS);
++#else /* !CONFIG_IDE_TASKFILE_IO */
++      ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
++#endif /* CONFIG_IDE_TASKFILE_IO */
++
+ #ifdef DEBUG_READ
+       printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+              "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+-             rq->sector+nsect-1, (unsigned long) rq->buffer,
++             rq->sector+nsect-1,
++#ifdef CONFIG_IDE_TASKFILE_IO
++              (unsigned long) to,
++#else /* !CONFIG_IDE_TASKFILE_IO */
++              (unsigned long) rq->buffer,
++#endif /* CONFIG_IDE_TASKFILE_IO */
+              rq->nr_sectors-nsect);
+-#endif
+-      rq->sector += nsect;
++#endif /* DEBUG_READ */
++
++#ifdef CONFIG_IDE_TASKFILE_IO
++      ide_unmap_buffer(to, &flags);
++#else /* !CONFIG_IDE_TASKFILE_IO */
+       rq->buffer += nsect<<9;
++#endif /* CONFIG_IDE_TASKFILE_IO */
++      rq->sector += nsect;
+       rq->errors = 0;
+       rq->nr_sectors -= nsect;
+       total_remaining = rq->nr_sectors;
+       if ((rq->current_nr_sectors -= nsect) <= 0) {
+-              ide_end_request(1, HWGROUP(drive));
++              DRIVER(drive)->end_request(drive, 1);
+       }
+ /*
+  * Now the data has been read in, do the following:
+@@ -363,16 +381,18 @@
+               if (stat & DRQ_STAT)
+                       goto read_again;
+               if (stat & BUSY_STAT) {
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
+ #ifdef DEBUG_READ
+                       printk(KERN_DEBUG "%s: promise_read: waiting for"
+                              "interrupt\n", drive->name);
+-#endif
++#endif /* DEBUG_READ */
+                       return ide_started;
+               }
+               printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+                      "!DRQ !BUSY\n", drive->name);
+-              return ide_error(drive, "promise read intr", stat);
++              return DRIVER(drive)->error(drive, "promise read intr", stat);
+       }
+       return ide_stopped;
+ }
+@@ -393,27 +413,95 @@
+       if (GET_STAT() & BUSY_STAT) {
+               if (time_before(jiffies, hwgroup->poll_timeout)) {
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+                       return ide_started; /* continue polling... */
+               }
+               hwgroup->poll_timeout = 0;
+               printk(KERN_ERR "%s: completion timeout - still busy!\n",
+                      drive->name);
+-              return ide_error(drive, "busy timeout", GET_STAT());
++              return DRIVER(drive)->error(drive, "busy timeout", GET_STAT());
+       }
+       hwgroup->poll_timeout = 0;
+ #ifdef DEBUG_WRITE
+       printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+-#endif
++#endif /* DEBUG_WRITE */
+       for (i = rq->nr_sectors; i > 0; ) {
+               i -= rq->current_nr_sectors;
+-              ide_end_request(1, hwgroup);
++              DRIVER(drive)->end_request(drive, 1);
+       }
+       return ide_stopped;
+ }
+ /*
++ * promise_multwrite() transfers a block of up to mcount sectors of data
++ * to a drive as part of a disk multiple-sector write operation.
++ *
++ * Returns 0 on success.
++ *
++ * Note that we may be called from two contexts - the do_rw_disk context
++ * and IRQ context. The IRQ can happen any time after we've output the
++ * full "mcount" number of sectors, so we must make sure we update the
++ * state _before_ we output the final part of the data!
++ */
++int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
++{
++      ide_hwgroup_t *hwgroup  = HWGROUP(drive);
++      struct request *rq      = &hwgroup->wrq;
++
++      do {
++              char *buffer;
++              int nsect = rq->current_nr_sectors;
++#ifdef CONFIG_IDE_TASKFILE_IO
++              unsigned long flags;
++#endif /* CONFIG_IDE_TASKFILE_IO */
++
++              if (nsect > mcount)
++                      nsect = mcount;
++              mcount -= nsect;
++#ifdef CONFIG_IDE_TASKFILE_IO
++              buffer = ide_map_buffer(rq, &flags);
++              rq->sector += nsect;
++#else /* !CONFIG_IDE_TASKFILE_IO */
++              buffer = rq->buffer;
++
++              rq->sector += nsect;
++              rq->buffer += nsect << 9;
++#endif /* CONFIG_IDE_TASKFILE_IO */
++              rq->nr_sectors -= nsect;
++              rq->current_nr_sectors -= nsect;
++
++              /* Do we move to the next bh after this? */
++              if (!rq->current_nr_sectors) {
++                      struct buffer_head *bh = rq->bh->b_reqnext;
++
++                      /* end early early we ran out of requests */
++                      if (!bh) {
++                              mcount = 0;
++                      } else {
++                              rq->bh                  = bh;
++                              rq->current_nr_sectors  = bh->b_size >> 9;
++                              rq->hard_cur_sectors = rq->current_nr_sectors;
++                              rq->buffer              = bh->b_data;
++                      }
++              }
++
++              /*
++               * Ok, we're all setup for the interrupt
++               * re-entering us on the last transfer.
++               */
++              taskfile_output_data(drive, buffer, nsect<<7);
++#ifdef CONFIG_IDE_TASKFILE_IO
++              ide_unmap_buffer(buffer, &flags);
++#endif /* CONFIG_IDE_TASKFILE_IO */
++      } while (mcount);
++
++      return 0;
++}
++
++/*
+  * promise_write_pollfunc() is the handler for disk write completion polling.
+  */
+ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
+@@ -422,24 +510,28 @@
+       if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
+               if (time_before(jiffies, hwgroup->poll_timeout)) {
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+                       return ide_started; /* continue polling... */
+               }
+               hwgroup->poll_timeout = 0;
+               printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+-              return ide_error (drive, "write timeout", GET_STAT());
++              return DRIVER(drive)->error(drive, "write timeout", GET_STAT());
+       }
+       /*
+        * Now write out last 4 sectors and poll for not BUSY
+        */
+-      ide_multwrite(drive, 4);
++      promise_multwrite(drive, 4);
+       hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
++      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++              BUG();
+       ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+ #ifdef DEBUG_WRITE
+       printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
+               drive->name, GET_STAT());
+-#endif
++#endif /* DEBUG_WRITE */
+       return ide_started;
+ }
+@@ -459,16 +551,18 @@
+       printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+              "buffer=%p\n", drive->name, rq->sector,
+              rq->sector + rq->nr_sectors - 1, rq->buffer);
+-#endif
++#endif /* DEBUG_WRITE */
+       /*
+        * If there are more than 4 sectors to transfer, do n-4 then go into
+        * the polling strategy as defined above.
+        */
+       if (rq->nr_sectors > 4) {
+-              if (ide_multwrite(drive, rq->nr_sectors - 4))
++              if (promise_multwrite(drive, rq->nr_sectors - 4))
+                       return ide_stopped;
+               hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+               return ide_started;
+       } else {
+@@ -476,14 +570,16 @@
+        * There are 4 or fewer sectors to transfer, do them all in one go
+        * and wait for NOT BUSY.
+        */
+-              if (ide_multwrite(drive, rq->nr_sectors))
++              if (promise_multwrite(drive, rq->nr_sectors))
+                       return ide_stopped;
+               hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
++              if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                      BUG();
+               ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+ #ifdef DEBUG_WRITE
+               printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
+                       "status = %02x\n", drive->name, GET_STAT());
+-#endif
++#endif /* DEBUG_WRITE */
+               return ide_started;
+       }
+ }
+@@ -493,13 +589,40 @@
+  * already set up. It issues a READ or WRITE command to the Promise
+  * controller, assuming LBA has been used to set up the block number.
+  */
++#ifndef CONFIG_IDE_TASKFILE_IO
+ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ {
++#else /* CONFIG_IDE_TASKFILE_IO */
++ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
++{
++      struct request *rq      = HWGROUP(drive)->rq;
++      task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
++#endif /* CONFIG_IDE_TASKFILE_IO */
++      ide_startstop_t startstop;
+       unsigned long timeout;
+       byte stat;
+-      if (rq->cmd == READ) {
++#ifdef CONFIG_IDE_TASKFILE_IO
++      if (IDE_CONTROL_REG)
++              OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
++      SELECT_MASK(HWIF(drive), drive, 0);
++
++      OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
++      OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
++      /* refers to number of sectors to transfer */
++      OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
++      /* refers to sector offset or start sector */
++      OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
++      OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
++      OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
++      OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
++#endif /* CONFIG_IDE_TASKFILE_IO */
++
++      switch(rq->cmd) {
++      case READ:
++#ifndef CONFIG_IDE_TASKFILE_IO
+               OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
++#endif /* CONFIG_IDE_TASKFILE_IO */
+ /*
+  * The card's behaviour is odd at this point. If the data is
+  * available, DRQ will be true, and no interrupt will be
+@@ -520,34 +643,66 @@
+                       if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
+ #ifdef DEBUG_READ
+                               printk(KERN_DEBUG "%s: read: waiting for "
+-                                                "interrupt\n", drive->name);
+-#endif
++                                              "interrupt\n", drive->name);
++#endif /* DEBUG_READ */
+                               ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
+                               return ide_started;
+                       }
+                       udelay(1);
+               } while (time_before(jiffies, timeout));
+-              printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
+-                      drive->name);
++              printk(KERN_ERR "%s: reading: No DRQ and not "
++                              "waiting - Odd!\n", drive->name);
+               return ide_stopped;
+-      } else if (rq->cmd == WRITE) {
+-              ide_startstop_t startstop;
++      case WRITE:
++#ifndef CONFIG_IDE_TASKFILE_IO
+               OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+-              if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
++#endif /* CONFIG_IDE_TASKFILE_IO */
++              if (ide_wait_stat(&startstop, drive, DATA_READY,
++                              drive->bad_wstat, WAIT_DRQ)) {
+                       printk(KERN_ERR "%s: no DRQ after issuing "
+-                             "PROMISE_WRITE\n", drive->name);
++                              "PROMISE_WRITE\n", drive->name);
+                       return startstop;
+               }
+               if (!drive->unmask)
+-                      __cli();        /* local CPU only */
++                      local_irq_disable();
+               HWGROUP(drive)->wrq = *rq; /* scratchpad */
+               return promise_write(drive);
+-
+-      } else {
++      default:
+               printk("KERN_WARNING %s: bad command: %d\n",
+-                     drive->name, rq->cmd);
+-              ide_end_request(0, HWGROUP(drive));
++                      drive->name, rq->cmd);
++              DRIVER(drive)->end_request(drive, 0);
+               return ide_stopped;
+       }
+ }
++
++#ifdef CONFIG_IDE_TASKFILE_IO
++
++ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
++{
++      struct hd_drive_task_hdr        taskfile;
++      ide_task_t                      args;
++
++      memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
++
++      taskfile.sector_count   = rq->nr_sectors;
++      taskfile.sector_number  = block;
++      taskfile.low_cylinder   = (block>>=8);
++      taskfile.high_cylinder  = (block>>=8);
++      taskfile.device_head    = ((block>>8)&0x0f)|drive->select.all;
++      taskfile.command        = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
++
++      memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
++      memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
++      args.command_type       = ide_cmd_type_parser(&args);
++      args.prehandler         = NULL;
++      args.handler            = NULL;
++      args.posthandler        = NULL;
++      args.rq                 = (struct request *) rq;
++      rq->special             = NULL;
++      rq->special             = (ide_task_t *)&args;
++
++      return do_pdc4030_io(drive, &args);
++}
++#endif /* CONFIG_IDE_TASKFILE_IO */
++
+diff -Nur linux.org/drivers/ide/pdcadma.c linux/drivers/ide/pdcadma.c
+--- linux.org/drivers/ide/pdcadma.c    Thu Jan  1 01:00:00 1970
++++ linux/drivers/ide/pdcadma.c        Thu Jul 18 14:24:34 2002
+@@ -0,0 +1,106 @@
++/*
++ * linux/drivers/ide/pdcadma.c                Version 0.01    June 21, 2001
++ *
++ * Copyright (C) 1999-2000            Andre Hedrick <andre@linux-ide.org>
++ * May be copied or modified under the terms of the GNU General Public License
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/ioport.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/ide.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include "ide_modes.h"
++
++#undef DISPLAY_PDCADMA_TIMINGS
++
++#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
++#include <linux/stat.h>
++#include <linux/proc_fs.h>
++
++static int pdcadma_get_info(char *, char **, off_t, int);
++extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
++static struct pci_dev *bmide_dev;
++
++static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
++{
++      char *p = buffer;
++      u32 bibma = pci_resource_start(bmide_dev, 4);
++
++      p += sprintf(p, "\n                                PDC ADMA %04X Chipset.\n", bmide_dev->device);
++      p += sprintf(p, "UDMA\n");
++      p += sprintf(p, "PIO\n");
++
++      return p-buffer;        /* => must be less than 4k! */
++}
++#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
++
++byte pdcadma_proc = 0;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++/*
++ * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
++ */
++
++int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
++{
++      switch (func) {
++              case ide_dma_check:
++                      func = ide_dma_off_quietly;
++              default:
++                      break;
++      }
++      return ide_dmaproc(func, drive);        /* use standard DMA stuff */
++}
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++
++unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
++{
++#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
++      if (!pdcadma_proc) {
++              pdcadma_proc = 1;
++              bmide_dev = dev;
++              pdcadma_display_info = &pdcadma_get_info;
++      }
++#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
++      return 0;
++}
++
++unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
++{
++      return 1;
++}
++
++void __init ide_init_pdcadma (ide_hwif_t *hwif)
++{
++      hwif->autodma = 0;
++      hwif->dma_base = 0;
++
++//    hwif->tuneproc = &pdcadma_tune_drive;
++//    hwif->speedproc = &pdcadma_tune_chipset;
++
++//    if (hwif->dma_base) {
++//            hwif->dmaproc = &pdcadma_dmaproc;
++//            hwif->autodma = 1;
++//    }
++}
++
++void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
++{
++//    ide_setup_dma(hwif, dmabase, 8);
++}
++
+diff -Nur linux.org/drivers/ide/piix.c linux/drivers/ide/piix.c
+--- linux.org/drivers/ide/piix.c       Thu Oct 25 22:53:47 2001
++++ linux/drivers/ide/piix.c   Thu Jul 18 14:24:34 2002
+@@ -77,7 +77,6 @@
+ static int piix_get_info(char *, char **, off_t, int);
+ extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+ static struct pci_dev *bmide_dev;
+ static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
+@@ -88,32 +87,36 @@
+       u8  c0 = 0, c1 = 0;
+       u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
++      p += sprintf(p, "\n                                ");
+       switch(bmide_dev->device) {
+               case PCI_DEVICE_ID_INTEL_82801BA_8:
+               case PCI_DEVICE_ID_INTEL_82801BA_9:
+-              case PCI_DEVICE_ID_INTEL_82801CA_10:
+-                      p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
++              case PCI_DEVICE_ID_INTEL_82801CA_10:
++              case PCI_DEVICE_ID_INTEL_82801CA_11:
++              case PCI_DEVICE_ID_INTEL_82801DB_11:
++              case PCI_DEVICE_ID_INTEL_82801E_11:
++                      p += sprintf(p, "Intel PIIX4 Ultra 100 Chipset.\n");
+                       break;
+               case PCI_DEVICE_ID_INTEL_82372FB_1:
+               case PCI_DEVICE_ID_INTEL_82801AA_1:
+-                      p += sprintf(p, "\n                                Intel PIIX4 Ultra 66 Chipset.\n");
++                      p += sprintf(p, "Intel PIIX4 Ultra 66 Chipset.\n");
+                       break;
+               case PCI_DEVICE_ID_INTEL_82451NX:
+               case PCI_DEVICE_ID_INTEL_82801AB_1:
+               case PCI_DEVICE_ID_INTEL_82443MX_1:
+               case PCI_DEVICE_ID_INTEL_82371AB:
+-                      p += sprintf(p, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
++                      p += sprintf(p, "Intel PIIX4 Ultra 33 Chipset.\n");
+                       break;
+               case PCI_DEVICE_ID_INTEL_82371SB_1:
+-                      p += sprintf(p, "\n                                Intel PIIX3 Chipset.\n");
++                      p += sprintf(p, "Intel PIIX3 Chipset.\n");
+                       break;
+               case PCI_DEVICE_ID_INTEL_82371MX:
+-                      p += sprintf(p, "\n                                Intel MPIIX Chipset.\n");
++                      p += sprintf(p, "Intel MPIIX Chipset.\n");
+                       return p-buffer;        /* => must be less than 4k! */
+               case PCI_DEVICE_ID_INTEL_82371FB_1:
+               case PCI_DEVICE_ID_INTEL_82371FB_0:
+               default:
+-                      p += sprintf(p, "\n                                Intel PIIX Chipset.\n");
++                      p += sprintf(p, "Intel PIIX Chipset.\n");
+                       break;
+       }
+@@ -136,22 +139,29 @@
+       c0 = inb_p((unsigned short)bibma + 0x02);
+       c1 = inb_p((unsigned short)bibma + 0x0a);
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+-      p += sprintf(p, "                %sabled                         %sabled\n",
++      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",
++      p += sprintf(p, "--------------- drive0 --------- drive1 "
++                      "-------- drive0 ---------- drive1 ------\n");
++      p += sprintf(p, "DMA enabled:    %s              %s "
++                      "            %s               %s\n",
+                       (c0&0x20) ? "yes" : "no ",
+                       (c0&0x40) ? "yes" : "no ",
+                       (c1&0x20) ? "yes" : "no ",
+                       (c1&0x40) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
++      p += sprintf(p, "UDMA enabled:   %s              %s "
++                      "            %s               %s\n",
+                       (reg48&0x01) ? "yes" : "no ",
+                       (reg48&0x02) ? "yes" : "no ",
+                       (reg48&0x04) ? "yes" : "no ",
+                       (reg48&0x08) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
++      p += sprintf(p, "UDMA enabled:   %s                %s "
++                      "              %s                 %s\n",
+                       ((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
+                       ((reg54&0x11) && (reg4a&0x02)) ? "4" :
+                       ((reg54&0x11) && (reg4a&0x01)) ? "3" :
+@@ -195,12 +205,65 @@
+ byte piix_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
+-/*
+- *
+- */
++static byte piix_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0x00;
++
++      switch(dev->device) {
++              case PCI_DEVICE_ID_INTEL_82801BA_8:
++              case PCI_DEVICE_ID_INTEL_82801BA_9:
++              case PCI_DEVICE_ID_INTEL_82801CA_10:
++              case PCI_DEVICE_ID_INTEL_82801CA_11:
++              case PCI_DEVICE_ID_INTEL_82801E_11:
++              case PCI_DEVICE_ID_INTEL_82801DB_11:
++                      mode |= 0x03;
++                      break;
++              case PCI_DEVICE_ID_INTEL_82801AA_1:
++              case PCI_DEVICE_ID_INTEL_82372FB_1:
++                      mode |= 0x02;
++                      break;
++              case PCI_DEVICE_ID_INTEL_82371AB:
++              case PCI_DEVICE_ID_INTEL_82443MX_1:
++              case PCI_DEVICE_ID_INTEL_82451NX:
++              case PCI_DEVICE_ID_INTEL_82801AB_1:
++                      mode |= 0x01;
++              case PCI_DEVICE_ID_INTEL_82371SB_1:
++              case PCI_DEVICE_ID_INTEL_82371FB_1:
++              case PCI_DEVICE_ID_INTEL_82371FB_0:
++              case PCI_DEVICE_ID_INTEL_82371MX:
++              default:
++                      return (mode &= ~0xF8);
++      }
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++
++static byte piix_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = piix_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
+ static byte piix_dma_2_pio (byte xfer_rate) {
+       switch(xfer_rate) {
+               case XFER_UDMA_5:
+@@ -228,7 +291,6 @@
+                       return 0;
+       }
+ }
+-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
+ /*
+  *  Based on settings done by AMI BIOS
+@@ -236,12 +298,14 @@
+  */
+ static void piix_tune_drive (ide_drive_t *drive, byte pio)
+ {
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      int is_slave            = (&hwif->drives[1] == drive);
++      int master_port         = hwif->channel ? 0x42 : 0x40;
++      int slave_port          = 0x44;
+       unsigned long flags;
+       u16 master_data;
+       byte slave_data;
+-      int is_slave            = (&HWIF(drive)->drives[1] == drive);
+-      int master_port         = HWIF(drive)->index ? 0x42 : 0x40;
+-      int slave_port          = 0x44;
+                                /* ISP  RTC */
+       byte timings[][2]       = { { 0, 0 },
+                                   { 0, 0 },
+@@ -250,44 +314,40 @@
+                                   { 2, 3 }, };
+       pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+-      pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
++      spin_lock_irqsave(&io_request_lock, flags);
++      pci_read_config_word(dev, master_port, &master_data);
+       if (is_slave) {
+               master_data = master_data | 0x4000;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0070;
+-              pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
+-              slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
+-              slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
+-                                         << (HWIF(drive)->index ? 4 : 0)));
++              pci_read_config_byte(dev, slave_port, &slave_data);
++              slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
++              slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+       } else {
+               master_data = master_data & 0xccf8;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0007;
+-              master_data = master_data | (timings[pio][0] << 12) |
+-                            (timings[pio][1] << 8);
++              master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+       }
+-      save_flags(flags);
+-      cli();
+-      pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
++      pci_write_config_word(dev, master_port, master_data);
+       if (is_slave)
+-              pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
+-      restore_flags(flags);
++              pci_write_config_byte(dev, slave_port, slave_data);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
+-static int piix_tune_chipset (ide_drive_t *drive, byte speed)
++static int piix_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       byte maslave            = hwif->channel ? 0x42 : 0x40;
++      byte speed              = piix_ratefilter(drive, xferspeed);
+       int a_speed             = 3 << (drive->dn * 4);
+       int u_flag              = 1 << drive->dn;
+       int v_flag              = 0x01 << drive->dn;
+       int w_flag              = 0x10 << drive->dn;
+       int u_speed             = 0;
+-      int err                 = 0;
+       int                     sitre;
+       short                   reg4042, reg44, reg48, reg4a, reg54;
+       byte                    reg55;
+@@ -301,6 +361,7 @@
+       pci_read_config_byte(dev, 0x55, &reg55);
+       switch(speed) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
+               case XFER_UDMA_4:
+               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
+               case XFER_UDMA_5:
+@@ -310,6 +371,11 @@
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_SW_DMA_2:     break;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++              case XFER_PIO_4:
++              case XFER_PIO_3:
++              case XFER_PIO_2:
++              case XFER_PIO_0:        break;
+               default:                return -1;
+       }
+@@ -332,8 +398,7 @@
+               } else {
+                       pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+               }
+-      }
+-      if (speed < XFER_UDMA_0) {
++      } else {
+               if (reg48 & u_flag)
+                       pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+               if (reg4a & a_speed)
+@@ -345,61 +410,51 @@
+       }
+       piix_tune_drive(drive, piix_dma_2_pio(speed));
+-
+-#if PIIX_DEBUG_DRIVE_INFO
+-      printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
+-#endif /* PIIX_DEBUG_DRIVE_INFO */
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
+-      err = ide_config_drive_speed(drive, speed);
+-      drive->current_speed = speed;
+-      return err;
++      return (ide_config_drive_speed(drive, speed));
+ }
++#ifdef CONFIG_BLK_DEV_IDEDMA
+ static int piix_config_drive_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
+-      ide_hwif_t *hwif        = HWIF(drive);
+-      struct pci_dev *dev     = hwif->pci_dev;
+-      byte                    speed;
++      byte mode               = piix_ratemask(drive);
++      byte speed, tspeed, dma = 1;
+-      byte udma_66            = eighty_ninty_three(drive);
+-      int ultra100            = ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10)) ? 1 : 0;
+-      int ultra66             = ((ultra100) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
+-      int ultra               = ((ultra66) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82451NX) ||
+-                                 (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
+-
+-      if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
+-              speed = XFER_UDMA_5;
+-      } else if ((id->dma_ultra & 0x0010) && (ultra)) {
+-              speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
+-      } else if ((id->dma_ultra & 0x0008) && (ultra)) {
+-              speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
+-      } else if ((id->dma_ultra & 0x0004) && (ultra)) {
+-              speed = XFER_UDMA_2;
+-      } else if ((id->dma_ultra & 0x0002) && (ultra)) {
+-              speed = XFER_UDMA_1;
+-      } else if ((id->dma_ultra & 0x0001) && (ultra)) {
+-              speed = XFER_UDMA_0;
+-      } else if (id->dma_mword & 0x0004) {
+-              speed = XFER_MW_DMA_2;
+-      } else if (id->dma_mword & 0x0002) {
+-              speed = XFER_MW_DMA_1;
+-      } else if (id->dma_1word & 0x0004) {
+-              speed = XFER_SW_DMA_2;
+-        } else {
+-              speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
++      switch(mode) {
++              case 0x03:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_5; break; }
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++              default:
++                      tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
++                      speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
++                      dma = 0;
++                      break;
+       }
+       (void) piix_tune_chipset(drive, speed);
++//    return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
+       return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+@@ -407,16 +462,13 @@
+                                                    ide_dma_off_quietly);
+ }
+-static void config_chipset_for_pio (ide_drive_t *drive)
+-{
+-      piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL));
+-}
+-
+ static int config_drive_xfer_rate (ide_drive_t *drive)
+ {
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
++      drive->init_speed = 0;
++
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -425,7 +477,7 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x007F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = piix_config_drive_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+@@ -456,7 +508,7 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              config_chipset_for_pio(drive);
++              piix_tune_drive(drive, 255);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
+@@ -472,10 +524,28 @@
+       /* Other cases are done by generic IDE-DMA code. */
+       return ide_dmaproc(func, drive);
+ }
+-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
++#endif /* CONFIG_BLK_DEV_IDEDMA */
+ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
+ {
++        switch(dev->device) {
++              case PCI_DEVICE_ID_INTEL_82801AA_1:
++              case PCI_DEVICE_ID_INTEL_82801AB_1:
++              case PCI_DEVICE_ID_INTEL_82801BA_8:
++              case PCI_DEVICE_ID_INTEL_82801BA_9:
++              case PCI_DEVICE_ID_INTEL_82801CA_10:
++              case PCI_DEVICE_ID_INTEL_82801CA_11:
++              case PCI_DEVICE_ID_INTEL_82801E_11:
++              case PCI_DEVICE_ID_INTEL_82801DB_11:
++              {
++                      unsigned int extra = 0;
++                      pci_read_config_dword(dev, 0x54, &extra);
++                      pci_write_config_dword(dev, 0x54, extra|0x400);
++              }
++              default:
++                      break;
++      }
++
+ #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+       if (!piix_proc) {
+               piix_proc = 1;
+@@ -516,21 +586,32 @@
+               return;
+       }
++      hwif->autodma = 0;
+       hwif->tuneproc = &piix_tune_drive;
++      hwif->speedproc = &piix_tune_chipset;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+       if (!hwif->dma_base)
+               return;
+-#ifndef CONFIG_BLK_DEV_IDEDMA
+-      hwif->autodma = 0;
+-#else /* CONFIG_BLK_DEV_IDEDMA */
+-#ifdef CONFIG_PIIX_TUNING
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &piix_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
+       if (!noautodma)
+               hwif->autodma = 1;
+-      hwif->dmaproc = &piix_dmaproc;
+-      hwif->speedproc = &piix_tune_chipset;
+-#endif /* CONFIG_PIIX_TUNING */
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* !CONFIG_BLK_DEV_IDEDMA */
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_piix (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      if (dev->resource[0].start != 0x01F1)
++              ide_register_xp_fix(dev);
++
++      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 -Nur linux.org/drivers/ide/qd65xx.c linux/drivers/ide/qd65xx.c
+--- linux.org/drivers/ide/qd65xx.c     Fri Sep  7 18:28:38 2001
++++ linux/drivers/ide/qd65xx.c Thu Jul 18 14:24:34 2002
+@@ -1,14 +1,15 @@
+ /*
+- *  linux/drivers/ide/qd65xx.c                Version 0.06    Aug 3, 2000
++ *  linux/drivers/ide/qd65xx.c                Version 0.07    Sep 30, 2001
+  *
+- *  Copyright (C) 1996-2000  Linus Torvalds & author (see below)
++ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+  */
+ /*
+  *  Version 0.03      Cleaned auto-tune, added probe
+  *  Version 0.04      Added second channel tuning
+  *  Version 0.05      Enhanced tuning ; added qd6500 support
+- *  Version 0.06      added dos driver's list
++ *  Version 0.06      Added dos driver's list
++ *  Version 0.07      Second channel bug fix 
+  *
+  * QDI QD6500/QD6580 EIDE controller fast support
+  *
+@@ -67,6 +68,7 @@
+  *        qd6500: 1100
+  *        qd6580: either 1010 or 0101
+  *
++ *
+  * base+0x02: Timer2 (qd6580 only)
+  *
+  *
+@@ -92,10 +94,9 @@
+ {
+       unsigned long flags;
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
+-      outb(content,reg);
+-      restore_flags(flags);   /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
++      OUT_BYTE(content,reg);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ byte __init qd_read_reg (byte reg)
+@@ -103,10 +104,9 @@
+       unsigned long flags;
+       byte read;
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
+-      read = inb(reg);
+-      restore_flags(flags);   /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
++      read = IN_BYTE(reg);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       return read;
+ }
+@@ -137,12 +137,12 @@
+ {
+       byte active_cycle,recovery_cycle;
+-      if (system_bus_clock()<=33) {
+-              active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
+-              recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
++      if (ide_system_bus_speed()<=33) {
++              active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
++              recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
+       } else {
+-              active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
+-              recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
++              active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
++              recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
+       }
+       return((recovery_cycle<<4) | 0x08 | active_cycle);
+@@ -156,8 +156,8 @@
+ static byte qd6580_compute_timing (int active_time, int recovery_time)
+ {
+-      byte active_cycle   = 17-IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
+-      byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
++      byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
++      byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
+       return((recovery_cycle<<4) | active_cycle);
+ }
+@@ -311,13 +311,12 @@
+       byte readreg;
+       unsigned long flags;
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++      spin_lock_irqsave(&io_request_lock, flags);
+       savereg = inb_p(port);
+       outb_p(QD_TESTVAL,port);        /* safe value */
+       readreg = inb_p(port);
+-      outb(savereg,port);
+-      restore_flags(flags);   /* all CPUs */
++      OUT_BYTE(savereg,port);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+       if (savereg == QD_TESTVAL) {
+               printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+@@ -427,7 +426,8 @@
+                               ide_hwifs[i].tuneproc = &qd6580_tune_drive;
+                               for (j=0;j<2;j++) {
+-                                      ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA;
++                                      ide_hwifs[i].drives[j].drive_data =
++                                             i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
+                                       ide_hwifs[i].drives[j].io_32bit = 1;
+                               }
+                       }
+diff -Nur linux.org/drivers/ide/qd65xx.h linux/drivers/ide/qd65xx.h
+--- linux.org/drivers/ide/qd65xx.h     Fri Sep  7 18:28:38 2001
++++ linux/drivers/ide/qd65xx.h Thu Jul 18 14:23:01 2002
+@@ -29,7 +29,7 @@
+ #define QD_CONTR_SEC_DISABLED 0x01
+-#define QD_ID3                        (config & QD_CONFIG_ID3)
++#define QD_ID3                        ((config & QD_CONFIG_ID3)!=0)
+ #define QD_CONFIG(hwif)               ((hwif)->config_data & 0x00ff)
+ #define QD_CONTROL(hwif)      (((hwif)->config_data & 0xff00) >> 8)
+@@ -39,6 +39,7 @@
+ #define QD6500_DEF_DATA               ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
+ #define QD6580_DEF_DATA               ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
++#define QD6580_DEF_DATA2      ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+ #define QD_DEF_CONTR          (0x40 | ((control & 0x02) ? 0x9f : 0x1f))
+ #define QD_TESTVAL            0x19    /* safe value */
+diff -Nur linux.org/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c
+--- linux.org/drivers/ide/rz1000.c     Wed May  2 01:05:00 2001
++++ linux/drivers/ide/rz1000.c Thu Jul 18 14:24:34 2002
+@@ -40,15 +40,16 @@
+       struct pci_dev *dev = hwif->pci_dev;
+       hwif->chipset = ide_rz1000;
+-      if (!pci_read_config_word (dev, 0x40, &reg)
+-       && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
+-      {
+-              printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
++      if (!pci_read_config_word (dev, 0x40, &reg) &&
++          !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
++              printk("%s: disabled chipset read-ahead "
++                      "(buggy RZ1000/RZ1001)\n", hwif->name);
+       } else {
+               hwif->serialized = 1;
+               hwif->drives[0].no_unmask = 1;
+               hwif->drives[1].no_unmask = 1;
+-              printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
++              printk("%s: serialized, disabled unmasking "
++                      "(buggy RZ1000/RZ1001)\n", hwif->name);
+       }
+ }
+@@ -58,27 +59,29 @@
+ {
+       unsigned short reg, h;
+-      if (!pci_read_config_word (dev, PCI_COMMAND, &reg) && !(reg & PCI_COMMAND_IO)) {
++      if (!pci_read_config_word (dev, PCI_COMMAND, &reg) &&
++          !(reg & PCI_COMMAND_IO)) {
+               printk("%s: buggy IDE controller disabled (BIOS)\n", name);
+               return;
+       }
+-      if (!pci_read_config_word (dev, 0x40, &reg)
+-       && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
+-      {
++      if (!pci_read_config_word (dev, 0x40, &reg) &&
++          !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+               printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
+       } else {
+               for (h = 0; h < MAX_HWIFS; ++h) {
+                       ide_hwif_t *hwif = &ide_hwifs[h];
+-                      if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+-                       && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
+-                      {
++                      if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 ||
++                           hwif->io_ports[IDE_DATA_OFFSET] == 0x170)  &&
++                          (hwif->chipset == ide_unknown ||
++                           hwif->chipset == ide_generic)) {
+                               hwif->chipset = ide_rz1000;
+                               hwif->serialized = 1;
+                               hwif->drives[0].no_unmask = 1;
+                               hwif->drives[1].no_unmask = 1;
+                               if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+                                       hwif->channel = 1;
+-                              printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
++                              printk("%s: serialized, disabled unmasking "
++                                      "(buggy %s)\n", hwif->name, name);
+                       }
+               }
+       }
+diff -Nur linux.org/drivers/ide/serverworks.c linux/drivers/ide/serverworks.c
+--- linux.org/drivers/ide/serverworks.c        Sun Sep  9 19:43:02 2001
++++ linux/drivers/ide/serverworks.c    Thu Jul 18 14:24:34 2002
+@@ -1,71 +1,25 @@
+ /*
+- * linux/drivers/ide/serverworks.c            Version 0.2     17 Oct 2000
++ * linux/drivers/ide/serverworks.c            Version 0.6     05 April 2002
+  *
+- *  Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
+- *  May be copied or modified under the terms of the GNU General Public License
++ * Copyright (C) 1998-2000 Michel Aubry
++ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
++ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
++ * Portions copyright (c) 2001 Sun Microsystems
+  *
+- *  interface borrowed from alim15x3.c:
+- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+  *
+- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
++ * RCC/ServerWorks IDE driver for Linux
+  *
+- *  IDE support for the ServerWorks OSB4 IDE chipset
++ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
++ *         supports UDMA mode 2 (33 MB/s)
+  *
+- * here's the default lspci:
++ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
++ *         all revisions support UDMA mode 4 (66 MB/s)
++ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+  *
+- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP])
+- *    Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
+- *    Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
+- *    Latency: 255
+- *    Region 4: I/O ports at c200
+- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
+- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 20: 01 c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
+- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- *
+- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
+- *         Subsystem: ServerWorks: Unknown device 0212
+- *         Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
+- *         Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
+- *         Latency: 64, cache line size 08
+- *         Region 0: I/O ports at 01f0
+- *         Region 1: I/O ports at 03f4
+- *         Region 2: I/O ports at 0170
+- *         Region 3: I/O ports at 0374
+- *         Region 4: I/O ports at 08b0
+- *         Region 5: I/O ports at 1000
+- *
+- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
+- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
+- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
+- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
+- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
+- * 50: 00 00 00 00 07 00 44 02 0f 04 03 00 00 00 00 00
+- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ *         *** The CSB5 does not provide ANY register ***
++ *         *** to detect 80-conductor cable presence. ***
+  *
++ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+  *
+  */
+@@ -83,73 +37,98 @@
+ #include "ide_modes.h"
+-#define SVWKS_DEBUG_DRIVE_INFO                0
+-
+-#define DISPLAY_SVWKS_TIMINGS
++#define DISPLAY_SVWKS_TIMINGS 1
++#undef SVWKS_DEBUG_DRIVE_INFO
+ #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+ #include <linux/stat.h>
+ #include <linux/proc_fs.h>
+-static struct pci_dev *bmide_dev;
++#define SVWKS_MAX_DEVS                2
++static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
++static int n_svwks_devs;
++
++static byte svwks_revision = 0;
+ static int svwks_get_info(char *, char **, off_t, int);
+ extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+ static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+       char *p = buffer;
+-      u32 bibma = pci_resource_start(bmide_dev, 4);
+-      u32 reg40, reg44;
+-      u16 reg48, reg56;
+-      u8  c0 = 0, c1 = 0, reg54;
+-
+-      pci_read_config_dword(bmide_dev, 0x40, &reg40);
+-      pci_read_config_dword(bmide_dev, 0x44, &reg44);
+-      pci_read_config_word(bmide_dev, 0x48, &reg48);
+-      pci_read_config_byte(bmide_dev, 0x54, &reg54);
+-      pci_read_config_word(bmide_dev, 0x56, &reg56);
+-
+-        /*
+-         * at that point bibma+0x2 et bibma+0xa are byte registers
+-         * to investigate:
+-         */
+-      c0 = inb_p((unsigned short)bibma + 0x02);
+-      c1 = inb_p((unsigned short)bibma + 0x0a);
++      int i;
+-      switch(bmide_dev->device) {
+-              case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+-                      p += sprintf(p, "\n                                ServerWorks CSB5 Chipset.\n");
+-                      break;
+-              case PCI_DEVICE_ID_SERVERWORKS_OSB4:
+-                      p += sprintf(p, "\n                                ServerWorks OSB4 Chipset.\n");
+-                      break;
+-              default:
+-                      p += sprintf(p, "\n                                ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+-                      break;
+-      }
++      p += sprintf(p, "\n                             "
++                      "ServerWorks OSB4/CSB5/CSB6\n");
+-      p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
+-#if 0
+-      p += sprintf(p, "                                     : %s\n", "str");
+-#endif
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+-      p += sprintf(p, "                %sabled                         %sabled\n",
+-                      (c0&0x80) ? "dis" : " en",
+-                      (c1&0x80) ? "dis" : " en");
+-      p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+-      p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
++      for (i = 0; i < n_svwks_devs; i++) {
++              struct pci_dev *dev = svwks_devs[i];
++              u32 bibma = pci_resource_start(dev, 4);
++              u32 reg40, reg44;
++              u16 reg48, reg56;
++              u8  reg54, c0=0, c1=0;
++
++              pci_read_config_dword(dev, 0x40, &reg40);
++              pci_read_config_dword(dev, 0x44, &reg44);
++              pci_read_config_word(dev, 0x48, &reg48);
++              pci_read_config_byte(dev, 0x54, &reg54);
++              pci_read_config_word(dev, 0x56, &reg56);
++
++              /*
++               * at that point bibma+0x2 et bibma+0xa are byte registers
++               * to investigate:
++               */
++              c0 = inb_p((unsigned short)bibma + 0x02);
++              c1 = inb_p((unsigned short)bibma + 0x0a);
++
++              switch(dev->device) {
++                      case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
++                              p += sprintf(p, "\n                            "
++                                      "ServerWorks CSB6 Chipset (rev %02x)\n",
++                                      svwks_revision);
++                              break;
++                      case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
++                              p += sprintf(p, "\n                            "
++                                      "ServerWorks CSB5 Chipset (rev %02x)\n",
++                                      svwks_revision);
++                              break;
++                      case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
++                              p += sprintf(p, "\n                            "
++                                      "ServerWorks OSB4 Chipset (rev %02x)\n",
++                                      svwks_revision);
++                              break;
++                      default:
++                              p += sprintf(p, "\n                            "
++                                      "ServerWorks %04x Chipset (rev %02x)\n",
++                                      dev->device, svwks_revision);
++                              break;
++              }
++
++              p += sprintf(p, "------------------------------- "
++                              "General Status "
++                              "---------------------------------\n");
++              p += sprintf(p, "--------------- Primary Channel "
++                              "---------------- Secondary Channel "
++                              "-------------\n");
++              p += sprintf(p, "                %sabled                         %sabled\n",
++                              (c0&0x80) ? "dis" : " en",
++                              (c1&0x80) ? "dis" : " en");
++              p += sprintf(p, "--------------- drive0 --------- drive1 "
++                              "-------- drive0 ---------- drive1 ------\n");
++              p += sprintf(p, "DMA enabled:    %s              %s"
++                              "             %s               %s\n",
+                       (c0&0x20) ? "yes" : "no ",
+                       (c0&0x40) ? "yes" : "no ",
+                       (c1&0x20) ? "yes" : "no ",
+                       (c1&0x40) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
++              p += sprintf(p, "UDMA enabled:   %s              %s"
++                              "             %s               %s\n",
+                       (reg54 & 0x01) ? "yes" : "no ",
+                       (reg54 & 0x02) ? "yes" : "no ",
+                       (reg54 & 0x04) ? "yes" : "no ",
+                       (reg54 & 0x08) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
++              p += sprintf(p, "UDMA enabled:   %s                %s"
++                              "               %s                 %s\n",
+                       ((reg56&0x0005)==0x0005)?"5":
+                               ((reg56&0x0004)==0x0004)?"4":
+                               ((reg56&0x0003)==0x0003)?"3":
+@@ -174,7 +153,8 @@
+                               ((reg56&0x2000)==0x2000)?"2":
+                               ((reg56&0x1000)==0x1000)?"1":
+                               ((reg56&0xF000))?"?":"0");
+-      p += sprintf(p, "DMA enabled:    %s                %s               %s                 %s\n",
++              p += sprintf(p, "DMA enabled:    %s                %s"
++                              "               %s                 %s\n",
+                       ((reg44&0x00002000)==0x00002000)?"2":
+                               ((reg44&0x00002100)==0x00002100)?"1":
+                               ((reg44&0x00007700)==0x00007700)?"0":
+@@ -191,12 +171,9 @@
+                               ((reg44&0x00210000)==0x00210000)?"1":
+                               ((reg44&0x00770000)==0x00770000)?"0":
+                               ((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+-#if 0
+-      if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+-              p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
+-      if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
+-#endif
+-              p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
++
++              p += sprintf(p, "PIO  enabled:   %s                %s"
++                              "               %s                 %s\n",
+                       ((reg40&0x00002000)==0x00002000)?"4":
+                               ((reg40&0x00002200)==0x00002200)?"3":
+                               ((reg40&0x00003400)==0x00003400)?"2":
+@@ -217,19 +194,83 @@
+                               ((reg40&0x00340000)==0x00340000)?"2":
+                               ((reg40&0x00470000)==0x00470000)?"1":
+                               ((reg40&0x005D0000)==0x005D0000)?"0":"?");
++
++      }
++      p += sprintf(p, "\n");
++
+       return p-buffer;         /* => must be less than 4k! */
+ }
+ #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+-static byte svwks_revision = 0;
++#define SVWKS_CSB5_REVISION_NEW       0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+-byte svwks_proc = 0;
++#define SVWKS_CSB6_REVISION   0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+-extern char *ide_xfer_verbose (byte xfer_rate);
++byte svwks_proc = 0;
+ static struct pci_dev *isa_dev;
+-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
++static byte svwks_ratemask (ide_drive_t *drive)
++{
++      struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0;
++
++      if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
++              u32 reg = 0;
++              mode &= ~0x01;
++              if (isa_dev)
++                      pci_read_config_dword(isa_dev, 0x64, &reg);
++              if ((reg & 0x00004000) == 0x00004000)
++                      mode |= 0x01;
++      } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
++              mode |= 0x01;
++      } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
++              u8 btr =0;
++              pci_read_config_byte(dev, 0x5A, &btr);
++              mode |= btr;
++              if (!eighty_ninty_three(drive))
++                      mode &= ~0x02;
++      }
++      if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
++          (!(PCI_FUNC(dev->devfn) & 1)))
++              mode = 0x02;
++      mode &= ~0xFC;
++      return (mode);
++}
++
++static byte svwks_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = svwks_ratemask(drive);
++      
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
++static byte svwks_csb_check (struct pci_dev *dev)
++{
++      switch (dev->device) {
++              case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
++              case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
++                      return 1;
++              default:
++                      break;
++      }
++      return 0;
++}
++static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       byte udma_modes[]       = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+       byte dma_modes[]        = { 0x77, 0x21, 0x20 };
+@@ -238,12 +279,7 @@
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       byte unit               = (drive->select.b.unit & 0x01);
+-      byte csb5               = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+-
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-      unsigned long dma_base  = hwif->dma_base;
+-#endif /* CONFIG_BLK_DEV_IDEDMA */
+-      int err;
++      byte csb5               = svwks_csb_check(dev);
+       byte drive_pci          = 0x00;
+       byte drive_pci2         = 0x00;
+@@ -256,6 +292,7 @@
+       unsigned short csb5_pio = 0x00;
+       byte pio        = ide_get_best_pio_mode(drive, 255, 5, NULL);
++      byte speed      = svwks_ratefilter(drive, xferspeed);
+         switch (drive->dn) {
+               case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
+@@ -272,11 +309,6 @@
+       pci_read_config_word(dev, 0x4A, &csb5_pio);
+       pci_read_config_byte(dev, 0x54, &ultra_enable);
+-#ifdef DEBUG
+-      printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+-              drive->name, ultra_timing, dma_timing, pio_timing);
+-#endif
+-
+       pio_timing      &= ~0xFF;
+       dma_timing      &= ~0xFF;
+       ultra_timing    &= ~(0x0F << (4*unit));
+@@ -292,6 +324,7 @@
+                       pio_timing |= pio_modes[speed - XFER_PIO_0];
+                       csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
+                       break;
++
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+@@ -307,9 +340,9 @@
+               case XFER_UDMA_2:
+               case XFER_UDMA_1:
+               case XFER_UDMA_0:
+-                      pio_timing |= pio_modes[pio];
+-                      csb5_pio   |= (pio << (4*drive->dn));
+-                      dma_timing |= dma_modes[2];
++                      pio_timing   |= pio_modes[pio];
++                      csb5_pio     |= (pio << (4*drive->dn));
++                      dma_timing   |= dma_modes[2];
+                       ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+                       ultra_enable |= (0x01 << drive->dn);
+ #endif
+@@ -317,18 +350,6 @@
+                       break;
+       }
+-#ifdef DEBUG
+-      printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+-              drive->name, ultra_timing, dma_timing, pio_timing);
+-#endif
+-
+-#if OSB4_DEBUG_DRIVE_INFO
+-      printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
+-#endif /* OSB4_DEBUG_DRIVE_INFO */
+-
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
+-
+       pci_write_config_byte(dev, drive_pci, pio_timing);
+       if (csb5)
+               pci_write_config_word(dev, 0x4A, csb5_pio);
+@@ -337,42 +358,33 @@
+       pci_write_config_byte(dev, drive_pci2, dma_timing);
+       pci_write_config_byte(dev, drive_pci3, ultra_timing);
+       pci_write_config_byte(dev, 0x54, ultra_enable);
+-      
+-      if (speed > XFER_PIO_4) {
+-              outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+-      } else {
+-              outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+-      }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-      err = ide_config_drive_speed(drive, speed);
+-      drive->current_speed = speed;
+-      return err;
++      return (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;
++      byte timing, speed, pio;
+       pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+       if (xfer_pio> 4)
+               xfer_pio = 0;
+-      if (drive->id->eide_pio_iordy > 0) {
++      if (drive->id->eide_pio_iordy > 0)
+               for (xfer_pio = 5;
+                       xfer_pio>0 &&
+                       drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+                       xfer_pio--);
+-      } else {
++      else
+               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+                          (drive->id->eide_pio_modes & 2) ? 0x04 :
+                          (drive->id->eide_pio_modes & 1) ? 0x03 :
+                          (drive->id->tPIO & 2) ? 0x02 :
+                          (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+-      }
+       timing = (xfer_pio >= pio) ? xfer_pio : pio;
+@@ -406,38 +418,54 @@
+ static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
+-      struct pci_dev *dev     = HWIF(drive)->pci_dev;
+-      byte udma_66            = eighty_ninty_three(drive);
+-      byte                    speed;
+-
+-      int ultra66             = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+-      /* need specs to figure out if osb4 is capable of ata/66/100 */
+-      int ultra100            = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+-
+-      if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
+-              speed = XFER_UDMA_5;
+-      } else if (id->dma_ultra & 0x0010) {
+-              speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
+-      } else if (id->dma_ultra & 0x0008) {
+-              speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
+-      } else if (id->dma_ultra & 0x0004) {
+-              speed = XFER_UDMA_2;
+-      } else if (id->dma_ultra & 0x0002) {
+-              speed = XFER_UDMA_1;
+-      } else if (id->dma_ultra & 0x0001) {
+-              speed = XFER_UDMA_0;
+-      } else if (id->dma_mword & 0x0004) {
+-              speed = XFER_MW_DMA_2;
+-      } else if (id->dma_mword & 0x0002) {
+-              speed = XFER_MW_DMA_1;
+-      } else if (id->dma_1word & 0x0004) {
+-              speed = XFER_SW_DMA_2;
+-      } else {
+-              speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
++      byte mode               = svwks_ratemask(drive);
++      byte speed, dma         = 1;
++
++      if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
++              mode = 0;
++
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++#if 0
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++#endif
++              default:
++                      speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
++                      dma = 0;
++                      break;
+       }
+       (void) svwks_tune_chipset(drive, speed);
++//    return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
+       return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+@@ -450,6 +478,8 @@
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
++      drive->init_speed = 0;
++
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -458,7 +488,7 @@
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+-                      if (id->dma_ultra & 0x002F) {
++                      if (id->dma_ultra & 0x003F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+@@ -490,6 +520,7 @@
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+               config_chipset_for_pio(drive);
++              //      HWIF(drive)->tuneproc(drive, 5);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
+@@ -499,7 +530,41 @@
+       switch (func) {
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
+-              default :
++              case ide_dma_end:
++              {
++                      ide_hwif_t *hwif                = HWIF(drive);
++                      unsigned long dma_base          = hwif->dma_base;
++      
++                      if(IN_BYTE(dma_base+0x02)&1)
++                      {
++#if 0         
++                              int i;
++                              printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
++                              for(i=0;i<10;i++)
++                              {
++                                      if(!(IN_BYTE(dma_base+0x02)&1))
++                                      {
++                                              printk(KERN_ERR "OSB4 now finished.\n");
++                                              break;
++                                      }
++                                      udelay(5);
++                              }
++#endif                
++                              printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
++                              printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
++                              printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
++#if 0         
++                              /* Panic might sys_sync -> death by corrupt disk */
++                              panic("OSB4: continuing might cause disk corruption.\n");
++#else
++                              printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
++                              while(1)
++                                      cpu_relax();
++#endif                                
++                      }
++                      /* and drop through */
++              }
++              default:
+                       break;
+       }
+       /* Other cases are done by generic IDE-DMA code. */
+@@ -509,68 +574,154 @@
+ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
+ {
+-      unsigned int reg64;
++      unsigned int reg;
++      byte btr;
++      /* save revision id to determine DMA capability */
+       pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
++      /* force Master Latency Timer value to 64 PCICLKs */
++      pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
++
++      /* OSB4 : South Bridge and IDE */
+       if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+-              isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
++              isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
++                        PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
++              if (isa_dev) {
++                      pci_read_config_dword(isa_dev, 0x64, &reg);
++                      reg &= ~0x00002000; /* disable 600ns interrupt mask */
++                      reg |=  0x00004000; /* enable UDMA/33 support */
++                      pci_write_config_dword(isa_dev, 0x64, reg);
++              }
++      }
+-              pci_read_config_dword(isa_dev, 0x64, &reg64);
+-#ifdef DEBUG
+-              printk("%s: reg64 == 0x%08x\n", name, reg64);
++      /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
++      else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
++               (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) {
++              /* Third Channel Test */
++              if (!(PCI_FUNC(dev->devfn) & 1)) {
++#if 1
++                      struct pci_dev * findev = NULL;
++                      unsigned int reg4c = 0;
++                      findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
++                              PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
++                      if (findev) {
++                              pci_read_config_dword(findev, 0x4C, &reg4c);
++                              reg4c &= ~0x000007FF;
++                              reg4c |=  0x00000040;
++                              reg4c |=  0x00000020;
++                              pci_write_config_dword(findev, 0x4C, reg4c);
++                      }
+ #endif
+-
+-//            reg64 &= ~0x0000A000;
+-//#ifdef CONFIG_SMP
+-//            reg64 |= 0x00008000;
+-//#endif
+-      /* Assume the APIC was set up properly by the BIOS for now . If it
+-         wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
+-         APIC enable, routing and decode */
+-         
+-              reg64 &= ~0x00002000;   
+-              pci_write_config_dword(isa_dev, 0x64, reg64);
++                      outb_p(0x06, 0x0c00);
++                      dev->irq = inb_p(0x0c01);
++#if 1
++                      /* WE need to figure out how to get the correct one */
++                      printk("%s: interrupt %d\n", name, dev->irq);
++                      if (dev->irq != 0x0B)
++                              dev->irq = 0x0B;
++#endif
++              } else {
++                      /*
++                       * This is a device pin issue on CSB6.
++                       * Since there will be a future raid mode,
++                       * early versions of the chipset require the
++                       * interrupt pin to be set, and it is a compatablity
++                       * mode issue.
++                       */
++                      dev->irq = 0;
++              }
++              pci_write_config_dword(dev, 0x40, 0x99999999);
++              pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
++              /* setup the UDMA Control register
++               *
++               * 1. clear bit 6 to enable DMA
++               * 2. enable DMA modes with bits 0-1
++               *      00 : legacy
++               *      01 : udma2
++               *      10 : udma2/udma4
++               *      11 : udma2/udma4/udma5
++               */
++              pci_read_config_byte(dev, 0x5A, &btr);
++              btr &= ~0x40;
++              if (!(PCI_FUNC(dev->devfn) & 1))
++                      btr |= 0x2;
++              else
++                      btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
++              pci_write_config_byte(dev, 0x5A, btr);
+       }
+-      pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
++
++      svwks_devs[n_svwks_devs++] = dev;
+ #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+       if (!svwks_proc) {
+               svwks_proc = 1;
+-              bmide_dev = dev;
+               svwks_display_info = &svwks_get_info;
+       }
+ #endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+-      return 0;
++
++      return (dev->irq) ? dev->irq : 0;
+ }
+-/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem
+- * device ID indicate presence of an 80-pin cable.
++static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
++{
++//    struct pci_dev *dev = hwif->pci_dev;
++//    return 0;
++      return 1;
++}
++
++/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
++ * of the subsystem device ID indicate presence of an 80-pin cable.
+  * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+  * Bit 15 set   = secondary IDE channel has 80-pin cable.
+  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+  * Bit 14 set   = primary IDE channel has 80-pin cable.
+  */
+-
+ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+ {
+-      struct pci_dev *dev     = hwif->pci_dev;
+-      if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL        &&
+-          dev->vendor           == PCI_VENDOR_ID_SERVERWORKS &&
+-          dev->device           == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
++      struct pci_dev *dev = hwif->pci_dev;
++      if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
++          dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
++          (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
++           dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+               return ((1 << (hwif->channel + 14)) &
+                       dev->subsystem_device) ? 1 : 0;
+-
+       return 0;
++}
++/* Sun Cobalt Alpine hardware avoids the 80-pin cable
++ * detect issue by attaching the drives directly to the board.
++ * This check follows the Dell precedent (how scary is that?!)
++ *
++ * WARNING: this only works on Alpine hardware!
++ */
++static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
++{
++      struct pci_dev *dev = hwif->pci_dev;
++      if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
++          dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
++          dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
++              return ((1 << (hwif->channel + 14)) &
++                      dev->subsystem_device) ? 1 : 0;
++      return 0;
+ }
+ unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+ {
+-      struct pci_dev *dev     = hwif->pci_dev;
++      struct pci_dev *dev = hwif->pci_dev;
++
++      /* Server Works */
++      if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
++              return ata66_svwks_svwks (hwif);
++      
++      /* Dell PowerEdge */
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+               return ata66_svwks_dell (hwif);
+-      
++
++      /* Cobalt Alpine */
++      if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
++              return ata66_svwks_cobalt (hwif);
++
+       return 0;
+ }
+@@ -581,22 +732,58 @@
+       hwif->tuneproc = &svwks_tune_drive;
+       hwif->speedproc = &svwks_tune_chipset;
+-
+-#ifndef CONFIG_BLK_DEV_IDEDMA
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+       hwif->autodma = 0;
+-      return;
+-#else /* CONFIG_BLK_DEV_IDEDMA */
+-      if (hwif->dma_base) {
+-              if (!noautodma)
+-                      hwif->autodma = 1;
+-              hwif->dmaproc = &svwks_dmaproc;
+-      } else {
+-              hwif->autodma = 0;
+-              hwif->drives[0].autotune = 1;
+-              hwif->drives[1].autotune = 1;
+-      }
++      if (!hwif->dma_base)
++              return;
++
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      hwif->dmaproc = &svwks_dmaproc;
++# ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++# endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* !CONFIG_BLK_DEV_IDEDMA */
+ }
++
++/*
++ * We allow the BM-DMA driver to only work on enabled interfaces.
++ */
++void __init ide_dmacapable_svwks (ide_hwif_t *hwif, unsigned long dmabase)
++{
++      struct pci_dev *dev = hwif->pci_dev;
++      if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
++          (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
++              return;
++#if 0
++      if (svwks_revision == (SVWKS_CSB5_REVISION_NEW + 1)) {
++              if (hwif->mate && hwif->mate->dma_base) {
++                      dmabase = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
++              } else {
++                      dmabase = pci_resource_start(dev, 4);
++                      if (!dmabase) {
++                              printk("%s: dma_base is invalid (0x%04lx)\n",
++                                      hwif->name, dmabase);
++                              dmabase = 0;
++                      }
++              }
++      }
++#endif
++      ide_setup_dma(hwif, dmabase, 8);
++}
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      if (!(PCI_FUNC(dev->devfn) & 1)) {
++              d->bootable = NEVER_BOARD;
++      }
++
++      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 -Nur linux.org/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
+--- linux.org/drivers/ide/sis5513.c    Fri Sep  7 18:28:38 2001
++++ linux/drivers/ide/sis5513.c        Thu Jul 18 14:24:34 2002
+@@ -1,11 +1,35 @@
+ /*
+- * linux/drivers/ide/sis5513.c                Version 0.11    June 9, 2000
++ * linux/drivers/ide/sis5513.c                Version 0.13    March 6, 2002
+  *
+  * Copyright (C) 1999-2000    Andre Hedrick <andre@linux-ide.org>
++ * Copyright (C) 2002         Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+  * May be copied or modified under the terms of the GNU General Public License
+  *
+- * Thanks to SIS Taiwan for direct support and hardware.
+- * Tested and designed on the SiS620/5513 chipset.
++ *
++ * Thanks :
++ *
++ * SiS Taiwan         : for direct support and hardware.
++ * Daniela Engert     : for initial ATA100 advices and numerous others.
++ * John Fremlin, Manfred Spraul :
++ *                      for checking code correctness, providing patches.
++ *
++ *
++ * Original tests and design on the SiS620/5513 chipset.
++ * ATA100 tests and design on the SiS735/5513 chipset.
++ * ATA16/33 design from specs
++ */
++
++/*
++ * TODO:
++ *    - Get ridden of SisHostChipInfo[] completness dependancy.
++ *    - Get ATA-133 datasheets, implement ATA-133 init code.
++ *    - Study drivers/ide/ide-timing.h.
++ *    - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
++ *      or remove ATA_00 define
++ *    - More checks in the config registers (force values instead of
++ *      relying on the BIOS setting them correctly).
++ *    - Further optimisations ?
++ *      . for example ATA66+ regs 0x48 & 0x4A
+  */
+ #include <linux/config.h>
+@@ -28,88 +52,165 @@
+ #include "ide_modes.h"
++/* When DEBUG is defined it outputs initial PCI config register
++   values and changes made to them by the driver */   
++// #define DEBUG
++/* When BROKEN_LEVEL is defined it limits the DMA mode
++   at boot time to its value */
++// #define BROKEN_LEVEL XFER_SW_DMA_0
+ #define DISPLAY_SIS_TIMINGS
+-#define SIS5513_DEBUG_DRIVE_INFO      0
+-static struct pci_dev *host_dev = NULL;
++/* Miscellaneaous flags */
++#define SIS5513_LATENCY               0x01
++
++/* registers layout and init values are chipset family dependant */
++/* 1/ define families */
++#define ATA_00                0x00
++#define ATA_16                0x01
++#define ATA_33                0x02
++#define ATA_66                0x03
++#define ATA_100a      0x04 // SiS730 is ATA100 with ATA66 layout
++#define ATA_100               0x05
++#define ATA_133               0x06
++/* 2/ variable holding the controller chipset family value */
++static unsigned char chipset_family;
++
++
++/*
++ * Debug code: following IDE config registers' changes
++ */
++#ifdef DEBUG
++/* Copy of IDE Config registers 0x00 -> 0x57
++   Fewer might be used depending on the actual chipset */
++static unsigned char ide_regs_copy[0x58];
++
++static byte sis5513_max_config_register(void) {
++      switch(chipset_family) {
++              case ATA_00:
++              case ATA_16:    return 0x4f;
++              case ATA_33:    return 0x52;
++              case ATA_66:
++              case ATA_100a:
++              case ATA_100:
++              case ATA_133:
++              default:        return 0x57;
++      }
++}
++
++/* Read config registers, print differences from previous read */
++static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
++      int i;
++      byte reg_val;
++      byte changed=0;
++      byte max = sis5513_max_config_register();
++
++      printk("SIS5513: %s, changed registers:\n", info);
++      for(i=0; i<=max; i++) {
++              pci_read_config_byte(dev, i, &reg_val);
++              if (reg_val != ide_regs_copy[i]) {
++                      printk("%0#x: %0#x -> %0#x\n",
++                             i, ide_regs_copy[i], reg_val);
++                      ide_regs_copy[i]=reg_val;
++                      changed=1;
++              }
++      }
++
++      if (!changed) {
++              printk("none\n");
++      }
++}
++
++/* Load config registers, no printing */
++static void sis5513_load_registers(struct pci_dev* dev) {
++      int i;
++      byte max = sis5513_max_config_register();
++
++      for(i=0; i<=max; i++) {
++              pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
++      }
++}
++
++/* Print a register */
++static void sis5513_print_register(int reg) {
++      printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
++}
++
++/* Print valuable registers */
++static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
++      int i;
++      byte max = sis5513_max_config_register();
++
++      sis5513_load_registers(dev);
++      printk("SIS5513 %s\n", marker);
++      printk("SIS5513 dump:");
++      for(i=0x00; i<0x40; i++) {
++              if ((i % 0x10)==0) printk("\n             ");
++              sis5513_print_register(i);
++      }
++      for(; i<49; i++) {
++              sis5513_print_register(i);
++      }
++      printk("\n             ");
++
++      for(; i<=max; i++) {
++              sis5513_print_register(i);
++      }
++      printk("\n");
++}
++#endif
+-#define SIS5513_FLAG_ATA_00           0x00000000
+-#define SIS5513_FLAG_ATA_16           0x00000001
+-#define SIS5513_FLAG_ATA_33           0x00000002
+-#define SIS5513_FLAG_ATA_66           0x00000004
+-#define SIS5513_FLAG_LATENCY          0x00000010
++/*
++ * Devices supported
++ */
+ static const struct {
+       const char *name;
+       unsigned short host_id;
+-      unsigned int flags;
++      unsigned char chipset_family;
++      unsigned char flags;
+ } SiSHostChipInfo[] = {
+-      { "SiS530",     PCI_DEVICE_ID_SI_530,   SIS5513_FLAG_ATA_66, },
+-      { "SiS540",     PCI_DEVICE_ID_SI_540,   SIS5513_FLAG_ATA_66, },
+-      { "SiS620",     PCI_DEVICE_ID_SI_620,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS630",     PCI_DEVICE_ID_SI_630,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS635",     PCI_DEVICE_ID_SI_635,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS640",     PCI_DEVICE_ID_SI_640,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS645",     PCI_DEVICE_ID_SI_645,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS650",     PCI_DEVICE_ID_SI_650,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS730",     PCI_DEVICE_ID_SI_730,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS735",     PCI_DEVICE_ID_SI_735,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS740",     PCI_DEVICE_ID_SI_740,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS745",     PCI_DEVICE_ID_SI_745,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS750",     PCI_DEVICE_ID_SI_750,   SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+-      { "SiS5591",    PCI_DEVICE_ID_SI_5591,  SIS5513_FLAG_ATA_33, },
+-      { "SiS5597",    PCI_DEVICE_ID_SI_5597,  SIS5513_FLAG_ATA_33, },
+-      { "SiS5600",    PCI_DEVICE_ID_SI_5600,  SIS5513_FLAG_ATA_33, },
+-      { "SiS5511",    PCI_DEVICE_ID_SI_5511,  SIS5513_FLAG_ATA_16, },
+-};
+-
+-#if 0
+-
+-static struct _pio_mode_mapping {
+-      byte data_active;
+-      byte recovery;
+-      byte pio_mode;
+-} pio_mode_mapping[] = {
+-      { 8, 12, 0 },
+-      { 6,  7, 1 },
+-      { 4,  4, 2 },
+-      { 3,  3, 3 },
+-      { 3,  1, 4 }
++      { "SiS750",     PCI_DEVICE_ID_SI_750,   ATA_100,        SIS5513_LATENCY },
++      { "SiS745",     PCI_DEVICE_ID_SI_745,   ATA_100,        SIS5513_LATENCY },
++      { "SiS740",     PCI_DEVICE_ID_SI_740,   ATA_100,        SIS5513_LATENCY },
++      { "SiS735",     PCI_DEVICE_ID_SI_735,   ATA_100,        SIS5513_LATENCY },
++      { "SiS730",     PCI_DEVICE_ID_SI_730,   ATA_100a,       SIS5513_LATENCY },
++      { "SiS650",     PCI_DEVICE_ID_SI_650,   ATA_100,        SIS5513_LATENCY },
++      { "SiS645",     PCI_DEVICE_ID_SI_645,   ATA_100,        SIS5513_LATENCY },
++      { "SiS635",     PCI_DEVICE_ID_SI_635,   ATA_100,        SIS5513_LATENCY },
++      { "SiS640",     PCI_DEVICE_ID_SI_640,   ATA_66,         SIS5513_LATENCY },
++      { "SiS630",     PCI_DEVICE_ID_SI_630,   ATA_66,         SIS5513_LATENCY },
++      { "SiS620",     PCI_DEVICE_ID_SI_620,   ATA_66,         SIS5513_LATENCY },
++      { "SiS540",     PCI_DEVICE_ID_SI_540,   ATA_66,         0},
++      { "SiS530",     PCI_DEVICE_ID_SI_530,   ATA_66,         0},
++      { "SiS5600",    PCI_DEVICE_ID_SI_5600,  ATA_33,         0},
++      { "SiS5598",    PCI_DEVICE_ID_SI_5598,  ATA_33,         0},
++      { "SiS5597",    PCI_DEVICE_ID_SI_5597,  ATA_33,         0},
++      { "SiS5591",    PCI_DEVICE_ID_SI_5591,  ATA_33,         0},
++      { "SiS5513",    PCI_DEVICE_ID_SI_5513,  ATA_16,         0},
++      { "SiS5511",    PCI_DEVICE_ID_SI_5511,  ATA_16,         0},
+ };
+-static struct _dma_mode_mapping {
+-      byte data_active;
+-      byte recovery;
+-      byte dma_mode;
+-} dma_mode_mapping[] = {
+-      { 8, 8, 0 },
+-      { 3, 2, 1 },
+-      { 3, 1, 2 }
++/* Cycle time bits and values vary accross chip dma capabilities
++   These three arrays hold the register layout and the values to set.
++   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
++static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
++static byte cycle_time_range[] = {0,0,2,3,3,4,4};
++static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
++      {0,0,0,0,0,0}, /* no udma */
++      {0,0,0,0,0,0}, /* no udma */
++      {3,2,1,0,0,0},
++      {7,5,3,2,1,0},
++      {7,5,3,2,1,0},
++      {11,7,5,4,2,1},
++      {0,0,0,0,0,0} /* not yet known, ask SiS */
+ };
+-static struct _udma_mode_mapping {
+-      byte cycle_time;
+-      char * udma_mode;
+-} udma_mode_mapping[] = {
+-      { 8, "Mode 0" },
+-      { 6, "Mode 1" },
+-      { 4, "Mode 2" }, 
+-      { 3, "Mode 3" },
+-      { 2, "Mode 4" },
+-      { 0, "Mode 5" }
+-};
++static struct pci_dev *host_dev = NULL;
+-static __inline__ char * find_udma_mode (byte cycle_time)
+-{
+-      int n;
+-      
+-      for (n = 0; n <= 4; n++)
+-              if (udma_mode_mapping[n].cycle_time <= cycle_time)
+-                      return udma_mode_mapping[n].udma_mode;
+-      return udma_mode_mapping[4].udma_mode;
+-}
+-#endif
++/*
++ * Printing configuration
++ */
+ #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+ #include <linux/stat.h>
+ #include <linux/proc_fs.h>
+@@ -118,12 +219,12 @@
+ extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+ static struct pci_dev *bmide_dev;
+-static char *cable_type[] = {
++static char* cable_type[] = {
+       "80 pins",
+       "40 pins"
+ };
+-static char *recovery_time [] ={
++static char* recovery_time[] ={
+       "12 PCICLK", "1 PCICLK",
+       "2 PCICLK", "3 PCICLK",
+       "4 PCICLK", "5 PCICLCK",
+@@ -134,101 +235,228 @@
+       "15 PCICLK", "15 PCICLK"
+ };
+-static char * cycle_time [] = {
+-      "2 CLK", "2 CLK",
+-      "3 CLK", "4 CLK",
+-      "5 CLK", "6 CLK",
+-      "7 CLK", "8 CLK"
+-};
+-
+-static char * active_time [] = {
++static char* active_time[] = {
+       "8 PCICLK", "1 PCICLCK",
+-      "2 PCICLK", "2 PCICLK",
++      "2 PCICLK", "3 PCICLK",
+       "4 PCICLK", "5 PCICLK",
+       "6 PCICLK", "12 PCICLK"
+ };
++static char* cycle_time[] = {
++      "Reserved", "2 CLK",
++      "3 CLK", "4 CLK",
++      "5 CLK", "6 CLK",
++      "7 CLK", "8 CLK",
++      "9 CLK", "10 CLK",
++      "11 CLK", "12 CLK",
++      "Reserved", "Reserved",
++      "Reserved", "Reserved"
++};
++
++/* Generic add master or slave info function */
++static char* get_drives_info (char *buffer, byte pos)
++{
++      byte reg00, reg01, reg10, reg11; /* timing registers */
++      char* p = buffer;
++
++/* Postwrite/Prefetch */
++      pci_read_config_byte(bmide_dev, 0x4b, &reg00);
++      p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
++                   pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
++                   (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
++      p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
++                   (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
++                   (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
++
++      pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
++      pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
++      pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
++      pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
++
++/* UDMA */
++      if (chipset_family >= ATA_33) {
++              p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
++                           (reg01 & 0x80)  ? "Enabled" : "Disabled",
++                           (reg11 & 0x80) ? "Enabled" : "Disabled");
++
++              p += sprintf(p, "                UDMA Cycle Time    ");
++              switch(chipset_family) {
++                      case ATA_33:    p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
++                      case ATA_66:
++                      case ATA_100a:  p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
++                      case ATA_100:   p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
++                      case ATA_133:
++                      default:        p += sprintf(p, "133+ ?"); break;
++              }
++              p += sprintf(p, " \t UDMA Cycle Time    ");
++              switch(chipset_family) {
++                      case ATA_33:    p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
++                      case ATA_66:
++                      case ATA_100a:  p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
++                      case ATA_100:   p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
++                      case ATA_133:
++                      default:        p += sprintf(p, "133+ ?"); break;
++              }
++              p += sprintf(p, "\n");
++      }
++
++/* Data Active */
++      p += sprintf(p, "                Data Active Time   ");
++      switch(chipset_family) {
++              case ATA_00:
++              case ATA_16: /* confirmed */
++              case ATA_33:
++              case ATA_66:
++              case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
++              case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
++              case ATA_133:
++              default: p += sprintf(p, "133+ ?"); break;
++      }
++      p += sprintf(p, " \t Data Active Time   ");
++      switch(chipset_family) {
++              case ATA_00:
++              case ATA_16:
++              case ATA_33:
++              case ATA_66:
++              case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
++              case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
++              case ATA_133:
++              default: p += sprintf(p, "133+ ?"); break;
++      }
++      p += sprintf(p, "\n");
++
++/* Data Recovery */
++      /* warning: may need (reg&0x07) for pre ATA66 chips */
++      p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
++                   recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
++
++      return p;
++}
++
++static char* get_masters_info(char* buffer)
++{
++      return get_drives_info(buffer, 0);
++}
++
++static char* get_slaves_info(char* buffer)
++{
++      return get_drives_info(buffer, 1);
++}
++
++/* Main get_info, called on /proc/ide/sis reads */
+ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+ {
+-      int rc;
+       char *p = buffer;
+-      byte reg,reg1;
++      byte reg;
+       u16 reg2, reg3;
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+-      rc = pci_read_config_byte(bmide_dev, 0x4a, &reg);
+-      p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n",
+-                   (reg & 0x02) ? "On" : "Off",
+-                   (reg & 0x04) ? "On" : "Off");
+-                   
+-      rc = pci_read_config_byte(bmide_dev, 0x09, &reg);
++      p += sprintf(p, "\nSiS 5513 ");
++      switch(chipset_family) {
++              case ATA_00: p += sprintf(p, "Unknown???"); break;
++              case ATA_16: p += sprintf(p, "DMA 16"); break;
++              case ATA_33: p += sprintf(p, "Ultra 33"); break;
++              case ATA_66: p += sprintf(p, "Ultra 66"); break;
++              case ATA_100a:
++              case ATA_100: p += sprintf(p, "Ultra 100"); break;
++              case ATA_133:
++              default: p+= sprintf(p, "Ultra 133+"); break;
++      }
++      p += sprintf(p, " chipset\n");
++      p += sprintf(p, "--------------- Primary Channel "
++                      "---------------- Secondary Channel "
++                      "-------------\n");
++
++/* Status */
++      pci_read_config_byte(bmide_dev, 0x4a, &reg);
++      p += sprintf(p, "Channel Status: ");
++      if (chipset_family < ATA_66) {
++              p += sprintf(p, "%s \t \t \t \t %s\n",
++                           (reg & 0x04) ? "On" : "Off",
++                           (reg & 0x02) ? "On" : "Off");
++      } else {
++              p += sprintf(p, "%s \t \t \t \t %s \n",
++                           (reg & 0x02) ? "On" : "Off",
++                           (reg & 0x04) ? "On" : "Off");
++      }
++
++/* Operation Mode */
++      pci_read_config_byte(bmide_dev, 0x09, &reg);
+       p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+                    (reg & 0x01) ? "Native" : "Compatible",
+                    (reg & 0x04) ? "Native" : "Compatible");
+-                           
+-      rc = pci_read_config_byte(bmide_dev, 0x48, &reg);
+-      p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+-                   (reg & 0x10) ? cable_type[1] : cable_type[0],
+-                   (reg & 0x20) ? cable_type[1] : cable_type[0]);
+-                   
+-      rc = pci_read_config_word(bmide_dev, 0x4c, &reg2);
+-      rc = pci_read_config_word(bmide_dev, 0x4e, &reg3);
++
++/* 80-pin cable ? */
++      if (chipset_family > ATA_33) {
++              pci_read_config_byte(bmide_dev, 0x48, &reg);
++              p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
++                           (reg & 0x10) ? cable_type[1] : cable_type[0],
++                           (reg & 0x20) ? cable_type[1] : cable_type[0]);
++      }
++
++/* Prefetch Count */
++      pci_read_config_word(bmide_dev, 0x4c, &reg2);
++      pci_read_config_word(bmide_dev, 0x4e, &reg3);
+       p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+                    reg2, reg3);
+-      rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);            
+-      p += sprintf(p, "Drive 0:        Postwrite %s \t \t Postwrite %s\n",
+-                   (reg & 0x10) ? "Enabled" : "Disabled",
+-                   (reg & 0x40) ? "Enabled" : "Disabled");
+-      p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+-                   (reg & 0x01) ? "Enabled" : "Disabled",
+-                   (reg & 0x04) ? "Enabled" : "Disabled");
+-                        
+-      rc = pci_read_config_byte(bmide_dev, 0x41, &reg);
+-      rc = pci_read_config_byte(bmide_dev, 0x45, &reg1);
+-      p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+-                   (reg & 0x80)  ? "Enabled" : "Disabled",
+-                   (reg1 & 0x80) ? "Enabled" : "Disabled");
+-      p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+-                   cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+-      p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
+-                   active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
++      p = get_masters_info(p);
++      p = get_slaves_info(p);
+-      rc = pci_read_config_byte(bmide_dev, 0x40, &reg);
+-      rc = pci_read_config_byte(bmide_dev, 0x44, &reg1);
+-      p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+-                   recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
++      return p-buffer;
++}
++#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+-      rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);            
+-      p += sprintf(p, "Drive 1:        Postwrite %s \t \t Postwrite %s\n",
+-                   (reg & 0x20) ? "Enabled" : "Disabled",
+-                   (reg & 0x80) ? "Enabled" : "Disabled");
+-      p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+-                   (reg & 0x02) ? "Enabled" : "Disabled",
+-                   (reg & 0x08) ? "Enabled" : "Disabled");
++byte sis_proc = 0;
+-      rc = pci_read_config_byte(bmide_dev, 0x43, &reg);
+-      rc = pci_read_config_byte(bmide_dev, 0x47, &reg1);
+-      p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+-                   (reg & 0x80)  ? "Enabled" : "Disabled",
+-                   (reg1 & 0x80) ? "Enabled" : "Disabled");
+-      p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+-                   cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+-      p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
+-                   active_time[(reg & 0x07)], active_time[(reg1 &0x07)] ); 
++static byte sis5513_ratemask (ide_drive_t *drive)
++{
++//    struct pci_dev *dev     = HWIF(drive)->pci_dev;
++      byte mode               = 0x00;
+-      rc = pci_read_config_byte(bmide_dev, 0x42, &reg);
+-      rc = pci_read_config_byte(bmide_dev, 0x46, &reg1);
+-      p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+-                   recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
+-      return p-buffer;
++      switch(chipset_family) {
++              case ATA_133:   //      { mode |= 0x04; break; }
++              case ATA_100:
++              case ATA_100a:  { mode |= 0x03; break; }
++              case ATA_66:    { mode |= 0x02; break; }
++              case ATA_33:    { mode |= 0x01; break; }
++              case ATA_16:
++                case ATA_00:  
++              default:
++                      return (mode &= ~0xF8);
++      }
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
+ }
+-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+-byte sis_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
++static byte sis5513_ratefilter (ide_drive_t *drive, byte speed)
++{
++#ifdef CONFIG_BLK_DEV_IDEDMA
++      byte mode = sis5513_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++/*
++ * Configuration functions
++ */
++/* Enables per-drive prefetch and postwrite */
+ static void config_drive_art_rwp (ide_drive_t *drive)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+@@ -237,14 +465,24 @@
+       byte reg4bh             = 0;
+       byte rw_prefetch        = (0x11 << drive->dn);
+-      pci_read_config_byte(dev, 0x4b, &reg4bh);
++#ifdef DEBUG
++      printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
++      sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
++#endif
++
+       if (drive->media != ide_disk)
+               return;
+-      
++      pci_read_config_byte(dev, 0x4b, &reg4bh);
++
+       if ((reg4bh & rw_prefetch) != rw_prefetch)
+               pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
++#endif
+ }
++
++/* Set per-drive active and recovery time */
+ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+@@ -255,6 +493,10 @@
+       unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+       unsigned short xfer_pio = drive->id->eide_pio_modes;
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
++#endif
++
+       config_drive_art_rwp(drive);
+       pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+@@ -263,8 +505,8 @@
+       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 > 0) &&
++                      (drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+                       xfer_pio--);
+       } else {
+               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+@@ -274,14 +516,10 @@
+       timing = (xfer_pio >= pio) ? xfer_pio : pio;
+-/*
+- *               Mode 0       Mode 1     Mode 2     Mode 3     Mode 4
+- * Active time    8T (240ns)  6T (180ns) 4T (120ns) 3T  (90ns) 3T  (90ns)
+- * 0x41 2:0 bits  000          110        100        011        011
+- * Recovery time 12T (360ns)  7T (210ns) 4T (120ns) 3T  (90ns) 1T  (30ns)
+- * 0x40 3:0 bits 0000         0111       0100       0011       0001
+- * Cycle time    20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
+- */
++#ifdef DEBUG
++      printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
++             drive->dn, pio, timing);
++#endif
+       switch(drive->dn) {
+               case 0:         drive_pci = 0x40; break;
+@@ -291,31 +529,43 @@
+               default:        return;
+       }
+-      pci_read_config_byte(dev, drive_pci, &test1);
+-      pci_read_config_byte(dev, drive_pci|0x01, &test2);
+-
+-      /*
+-       * Do a blanket clear of active and recovery timings.
+-       */
+-
+-      test1 &= ~0x07;
+-      test2 &= ~0x0F;
+-
+-      switch(timing) {
+-              case 4:         test1 |= 0x01; test2 |= 0x03; break;
+-              case 3:         test1 |= 0x03; test2 |= 0x03; break;
+-              case 2:         test1 |= 0x04; test2 |= 0x04; break;
+-              case 1:         test1 |= 0x07; test2 |= 0x06; break;
+-              default:        break;
++      /* register layout changed with newer ATA100 chips */
++      if (chipset_family < ATA_100) {
++              pci_read_config_byte(dev, drive_pci, &test1);
++              pci_read_config_byte(dev, drive_pci+1, &test2);
++
++              /* Clear active and recovery timings */
++              test1 &= ~0x0F;
++              test2 &= ~0x07;
++
++              switch(timing) {
++                      case 4:         test1 |= 0x01; test2 |= 0x03; break;
++                      case 3:         test1 |= 0x03; test2 |= 0x03; break;
++                      case 2:         test1 |= 0x04; test2 |= 0x04; break;
++                      case 1:         test1 |= 0x07; test2 |= 0x06; break;
++                      default:        break;
++              }
++              pci_write_config_byte(dev, drive_pci, test1);
++              pci_write_config_byte(dev, drive_pci+1, test2);
++      } else {
++              switch(timing) { /*   active  recovery
++                                        v     v */
++                      case 4:         test1 = 0x30|0x01; break;
++                      case 3:         test1 = 0x30|0x03; break;
++                      case 2:         test1 = 0x40|0x04; break;
++                      case 1:         test1 = 0x60|0x07; break;
++                      default:        break;
++              }
++              pci_write_config_byte(dev, drive_pci, test1);
+       }
+-      pci_write_config_byte(dev, drive_pci, test1);
+-      pci_write_config_byte(dev, drive_pci|0x01, test2);
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
++#endif
+ }
+ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+ {
+-      int err;
+       byte speed;
+       switch(pio) {
+@@ -327,92 +577,86 @@
+       }
+       config_art_rwp_pio(drive, pio);
+-      drive->current_speed = speed;
+-      err = ide_config_drive_speed(drive, speed);
+-      return err;
++      return (ide_config_drive_speed(drive, speed));
+ }
+-static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
++static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
++      byte speed              = sis5513_ratefilter(drive, xferspeed);
++      byte                    drive_pci, reg;
+-      byte                    drive_pci, test1, test2;
+-      byte                    unmask, four_two, mask = 0;
+-
+-      if (host_dev) {
+-              switch(host_dev->device) {
+-                      case PCI_DEVICE_ID_SI_530:
+-                      case PCI_DEVICE_ID_SI_540:
+-                      case PCI_DEVICE_ID_SI_620:
+-                      case PCI_DEVICE_ID_SI_630:
+-                      case PCI_DEVICE_ID_SI_635:
+-                      case PCI_DEVICE_ID_SI_640:
+-                      case PCI_DEVICE_ID_SI_645:
+-                      case PCI_DEVICE_ID_SI_650:
+-                      case PCI_DEVICE_ID_SI_730:
+-                      case PCI_DEVICE_ID_SI_735:
+-                      case PCI_DEVICE_ID_SI_740:
+-                      case PCI_DEVICE_ID_SI_745:
+-                      case PCI_DEVICE_ID_SI_750:
+-                              unmask   = 0xF0;
+-                              four_two = 0x01;
+-                              break;
+-                      default:
+-                              unmask   = 0xE0;
+-                              four_two = 0x00;
+-                              break;
+-              }
+-      } else {
+-              unmask   = 0xE0;
+-              four_two = 0x00;
+-      }
+-
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
++      printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
++             drive->dn, speed);
++#endif
++#if 1
+       switch(drive->dn) {
+-              case 0:         drive_pci = 0x40;break;
+-              case 1:         drive_pci = 0x42;break;
+-              case 2:         drive_pci = 0x44;break;
+-              case 3:         drive_pci = 0x46;break;
++              case 0:         drive_pci = 0x40; break;
++              case 1:         drive_pci = 0x42; break;
++              case 2:         drive_pci = 0x44; break;
++              case 3:         drive_pci = 0x46; break;
+               default:        return ide_dma_off;
+       }
++#else
++//    drive_pci = (0x40 + ((drive->dn) *2));
++//    drive_pci = 0x40;
++//    drive_pci |= ((drive->dn) << 1);
++#endif
+-      pci_read_config_byte(dev, drive_pci, &test1);
+-      pci_read_config_byte(dev, drive_pci|0x01, &test2);
++#ifdef BROKEN_LEVEL
++#ifdef DEBUG
++      printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
++#endif
++      if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
++#endif
+-      if ((speed <= XFER_MW_DMA_2) && (test2 & 0x80)) {
+-              pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80);
+-              pci_read_config_byte(dev, drive_pci|0x01, &test2);
+-      } else {
+-              pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
++      pci_read_config_byte(dev, drive_pci+1, &reg);
++      /* Disable UDMA bit for non UDMA modes on UDMA chips */
++      if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
++              reg &= 0x7F;
++              pci_write_config_byte(dev, drive_pci+1, reg);
+       }
++      /* Config chip for mode */
+       switch(speed) {
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-              case XFER_UDMA_5: mask = 0x80; break;
+-              case XFER_UDMA_4: mask = 0x90; break;
+-              case XFER_UDMA_3: mask = 0xA0; break;
+-              case XFER_UDMA_2: mask = (four_two) ? 0xB0 : 0xA0; break;
+-              case XFER_UDMA_1: mask = (four_two) ? 0xD0 : 0xC0; break;
+-              case XFER_UDMA_0: mask = unmask; break;
++              case XFER_UDMA_5:
++              case XFER_UDMA_4:
++              case XFER_UDMA_3:
++              case XFER_UDMA_2:
++              case XFER_UDMA_1:
++              case XFER_UDMA_0:
++                      /* Force the UDMA bit on if we want to use UDMA */
++                      reg |= 0x80;
++                      /* clean reg cycle time bits */
++                      reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
++                               << cycle_time_offset[chipset_family]);
++                      /* set reg cycle time bits */
++                      reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
++                              << cycle_time_offset[chipset_family];
++                      pci_write_config_byte(dev, drive_pci+1, reg);
++                      break;
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_MW_DMA_0:
+               case XFER_SW_DMA_2:
+               case XFER_SW_DMA_1:
+-              case XFER_SW_DMA_0: break;
++              case XFER_SW_DMA_0:
++                      break;
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+               case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+               case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+               case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+               case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+               case XFER_PIO_0:
+-              default:         return((int) config_chipset_for_pio(drive, 0));
++              default:         return((int) config_chipset_for_pio(drive, 0));        
+       }
+-
+-      if (speed > XFER_MW_DMA_2)
+-              pci_write_config_byte(dev, drive_pci|0x01, test2|mask);
+-
+-      drive->current_speed = speed;
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
++#endif
+       return ((int) ide_config_drive_speed(drive, speed));
+ }
+@@ -425,77 +669,56 @@
+ /*
+  * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+  */
+-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
++static int config_chipset_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
+-      ide_hwif_t *hwif        = HWIF(drive);
+-
+-      byte                    four_two = 0, speed = 0;
+-      int                     err;
++      byte mode               = sis5513_ratemask(drive);
++      byte speed              = 0;
+-      byte unit               = (drive->select.b.unit & 0x01);
+-      byte udma_66            = eighty_ninty_three(drive);
+-      byte ultra_100          = 0;
++#ifdef DEBUG
++      printk("SIS5513: config_chipset_for_dma, drive %d ultra %d\n",
++             drive->dn, mode);
++#endif
+-      if (host_dev) {
+-              switch(host_dev->device) {
+-                      case PCI_DEVICE_ID_SI_635:
+-                      case PCI_DEVICE_ID_SI_640:
+-                      case PCI_DEVICE_ID_SI_645:
+-                      case PCI_DEVICE_ID_SI_650:
+-                      case PCI_DEVICE_ID_SI_730:
+-                      case PCI_DEVICE_ID_SI_735:
+-                      case PCI_DEVICE_ID_SI_740:
+-                      case PCI_DEVICE_ID_SI_745:
+-                      case PCI_DEVICE_ID_SI_750:
+-                              ultra_100 = 1;
+-                      case PCI_DEVICE_ID_SI_530:
+-                      case PCI_DEVICE_ID_SI_540:
+-                      case PCI_DEVICE_ID_SI_620:
+-                      case PCI_DEVICE_ID_SI_630:
+-                              four_two = 0x01;
+-                              break;
+-                      default:
+-                              four_two = 0x00; break;
+-              }
++      switch(mode) {
++              case 0x04:
++                      if (id->dma_ultra & 0x0040)
++                              { speed = XFER_UDMA_6; break; }
++              case 0x03:
++                      if (id->dma_ultra & 0x0020)
++                              { speed = XFER_UDMA_5; break; }
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_mword & 0x0001)
++                              { speed = XFER_MW_DMA_0; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++                      if (id->dma_1word & 0x0002)
++                              { speed = XFER_SW_DMA_1; break; }
++                      if (id->dma_1word & 0x0001)
++                              { speed = XFER_SW_DMA_0; break; }
++              default:
++                      return ((int) ide_dma_off_quietly);
+       }
+-
+-      if ((id->dma_ultra & 0x0020) && (ultra) && (udma_66) && (four_two) && (ultra_100))
+-              speed = XFER_UDMA_5;
+-      else if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two))
+-              speed = XFER_UDMA_4;
+-      else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two))
+-              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(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
+-
+-      err = sis5513_tune_chipset(drive, speed);
+-
+-#if SIS5513_DEBUG_DRIVE_INFO
+-      printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
+-#endif /* SIS5513_DEBUG_DRIVE_INFO */
+-
+-      return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
++      sis5513_tune_chipset(drive, speed);
++//    return ((int) ide_dma_on);
++      return ((int)   ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
++                      ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+@@ -507,6 +730,8 @@
+       struct hd_driveid *id           = drive->id;
+       ide_dma_action_t dma_func       = ide_dma_off_quietly;
++      drive->init_speed = 0;
++
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+@@ -517,7 +742,7 @@
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x003F) {
+                               /* Force if Capable UltraDMA */
+-                              dma_func = config_chipset_for_dma(drive, 1);
++                              dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+@@ -527,14 +752,14 @@
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+-                              dma_func = config_chipset_for_dma(drive, 0);
++                              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)) &&
+                          (id->eide_dma_time > 150)) {
+                       /* Consult the list of known "good" drives */
+-                      dma_func = config_chipset_for_dma(drive, 0);
++                      dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+@@ -544,15 +769,13 @@
+ fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+ no_dma_set:
+-              (void) config_chipset_for_pio(drive, 5);
++              sis5513_tune_drive(drive, 5);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+ }
+-/*
+- * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+- */
++/* initiates/aborts (U)DMA read/write operations on a drive. */
+ int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
+       switch (func) {
+@@ -567,15 +790,14 @@
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
++/* Chip detection and general config */
+ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
+ {
+       struct pci_dev *host;
+       int i = 0;
+-      byte latency = 0;
+-
+-      pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+-      for (i = 0; i < ARRAY_SIZE (SiSHostChipInfo) && !host_dev; i++) {
++      /* Find the chip */
++      for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
+               host = pci_find_device (PCI_VENDOR_ID_SI,
+                                       SiSHostChipInfo[i].host_id,
+                                       NULL);
+@@ -583,30 +805,71 @@
+                       continue;
+               host_dev = host;
++              chipset_family = SiSHostChipInfo[i].chipset_family;
+               printk(SiSHostChipInfo[i].name);
+               printk("\n");
+-              if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) {
+-                      if (latency != 0x10)
+-                              pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
++
++#ifdef DEBUG
++              sis5513_print_registers(dev, "pci_init_sis5513 start");
++#endif
++
++              if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
++                      byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
++                      pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+               }
+       }
++      /* Make general config ops here
++         1/ tell IDE channels to operate in Compabitility mode only
++         2/ tell old chips to allow per drive IDE timings */
+       if (host_dev) {
+-              byte reg52h = 0;
+-
+-              pci_read_config_byte(dev, 0x52, &reg52h);
+-              if (!(reg52h & 0x04)) {
+-                      /* set IDE controller to operate in Compabitility mode only */
+-                      pci_write_config_byte(dev, 0x52, reg52h|0x04);
++              byte reg;
++              switch(chipset_family) {
++                      case ATA_133:
++                      case ATA_100:
++                              /* Set compatibility bit */
++                              pci_read_config_byte(dev, 0x49, &reg);
++                              if (!(reg & 0x01)) {
++                                      pci_write_config_byte(dev, 0x49, reg|0x01);
++                              }
++                              break;
++                      case ATA_100a:
++                      case ATA_66:
++                              /* On ATA_66 chips the bit was elsewhere */
++                              pci_read_config_byte(dev, 0x52, &reg);
++                              if (!(reg & 0x04)) {
++                                      pci_write_config_byte(dev, 0x52, reg|0x04);
++                              }
++                              break;
++                      case ATA_33:
++                              /* On ATA_33 we didn't have a single bit to set */
++                              pci_read_config_byte(dev, 0x09, &reg);
++                              if ((reg & 0x0f) != 0x00) {
++                                      pci_write_config_byte(dev, 0x09, reg&0xf0);
++                              }
++                      case ATA_16:
++                              /* force per drive recovery and active timings
++                                 needed on ATA_33 and below chips */
++                              pci_read_config_byte(dev, 0x52, &reg);
++                              if (!(reg & 0x08)) {
++                                      pci_write_config_byte(dev, 0x52, reg|0x08);
++                              }
++                              break;
++                      case ATA_00:
++                      default: break;
+               }
++
+ #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+               if (!sis_proc) {
+                       sis_proc = 1;
+                       bmide_dev = dev;
+                       sis_display_info = &sis_get_info;
+               }
+-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
++#endif
+       }
++#ifdef DEBUG
++      sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
++#endif
+       return 0;
+ }
+@@ -616,27 +879,10 @@
+       byte mask = hwif->channel ? 0x20 : 0x10;
+       pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+-      if (host_dev) {
+-              switch(host_dev->device) {
+-                      case PCI_DEVICE_ID_SI_530:
+-                      case PCI_DEVICE_ID_SI_540:
+-                      case PCI_DEVICE_ID_SI_620:
+-                      case PCI_DEVICE_ID_SI_630:
+-                      case PCI_DEVICE_ID_SI_635:
+-                      case PCI_DEVICE_ID_SI_640:
+-                      case PCI_DEVICE_ID_SI_645:
+-                      case PCI_DEVICE_ID_SI_650:
+-                      case PCI_DEVICE_ID_SI_730:
+-                      case PCI_DEVICE_ID_SI_735:
+-                      case PCI_DEVICE_ID_SI_740:
+-                      case PCI_DEVICE_ID_SI_745:
+-                      case PCI_DEVICE_ID_SI_750:
+-                              ata66 = (reg48h & mask) ? 0 : 1;
+-                      default:
+-                              break;
+-              }
++      if (chipset_family >= ATA_66) {
++              ata66 = (reg48h & mask) ? 0 : 1;
+       }
+-        return (ata66);
++        return ata66;
+ }
+ void __init ide_init_sis5513 (ide_hwif_t *hwif)
+@@ -646,38 +892,36 @@
+       hwif->tuneproc = &sis5513_tune_drive;
+       hwif->speedproc = &sis5513_tune_chipset;
++      hwif->drives[0].autotune = 1;
++      hwif->drives[1].autotune = 1;
++      hwif->autodma = 0;
+       if (!(hwif->dma_base))
+               return;
+-      if (host_dev) {
+-              switch(host_dev->device) {
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-                      case PCI_DEVICE_ID_SI_530:
+-                      case PCI_DEVICE_ID_SI_540:
+-                      case PCI_DEVICE_ID_SI_620:
+-                      case PCI_DEVICE_ID_SI_630:
+-                      case PCI_DEVICE_ID_SI_635:
+-                      case PCI_DEVICE_ID_SI_640:
+-                      case PCI_DEVICE_ID_SI_645:
+-                      case PCI_DEVICE_ID_SI_650:
+-                      case PCI_DEVICE_ID_SI_730:
+-                      case PCI_DEVICE_ID_SI_735:
+-                      case PCI_DEVICE_ID_SI_740:
+-                      case PCI_DEVICE_ID_SI_745:
+-                      case PCI_DEVICE_ID_SI_750:
+-                      case PCI_DEVICE_ID_SI_5600:
+-                      case PCI_DEVICE_ID_SI_5597:
+-                      case PCI_DEVICE_ID_SI_5591:
+-                              if (!noautodma)
+-                                      hwif->autodma = 1;
+-                              hwif->dmaproc = &sis5513_dmaproc;
+-                              break;
++      if (host_dev) {
++              if (chipset_family > ATA_16)
++                      hwif->dmaproc = &sis5513_dmaproc;
++              else
++                      hwif->autodma = 0;
++      }
++# ifdef CONFIG_IDEDMA_AUTO
++      if (!noautodma)
++              hwif->autodma = 1;
++# endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+-                      default:
+-                              hwif->autodma = 0;
+-                              break;
+-              }
+-      }
+       return;
+ }
++
++extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
++
++void __init fixup_device_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
++{
++      if (dev->resource[0].start != 0x01F1)
++              ide_register_xp_fix(dev);
++
++      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 -Nur linux.org/drivers/ide/sl82c105.c linux/drivers/ide/sl82c105.c
+--- linux.org/drivers/ide/sl82c105.c   Fri Sep  7 19:45:30 2001
++++ linux/drivers/ide/sl82c105.c       Thu Jul 18 14:24:34 2002
+@@ -26,8 +26,6 @@
+ #include "ide_modes.h"
+-extern char *ide_xfer_verbose (byte xfer_rate);
+-
+ /*
+  * Convert a PIO mode and cycle time to the required on/off
+  * times for the interface.  This has protection against run-away
+@@ -243,7 +241,7 @@
+       unsigned int rev;
+       byte dma_state;
+-      dma_state = inb(dma_base + 2);
++      dma_state = IN_BYTE(dma_base + 2);
+       rev = sl82c105_bridge_revision(hwif->pci_dev);
+       if (rev <= 5) {
+               hwif->autodma = 0;
+@@ -256,7 +254,7 @@
+               dma_state |= 0x60;
+               hwif->autodma = 1;
+       }
+-      outb(dma_state, dma_base + 2);
++      OUT_BYTE(dma_state, dma_base + 2);
+       hwif->dmaproc = NULL;
+       ide_setup_dma(hwif, dma_base, 8);
+diff -Nur linux.org/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c
+--- linux.org/drivers/ide/slc90e66.c   Mon Jul 16 01:22:23 2001
++++ linux/drivers/ide/slc90e66.c       Thu Jul 18 14:24:34 2002
+@@ -60,7 +60,6 @@
+ static int slc90e66_get_info(char *, char **, off_t, int);
+ extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+-extern char *ide_media_verbose(ide_drive_t *);
+ static struct pci_dev *bmide_dev;
+ static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+@@ -86,26 +85,38 @@
+          * at that point bibma+0x2 et bibma+0xa are byte registers
+          * to investigate:
+          */
++#ifdef __mips__       /* only for mips? */
++      c0 = inb_p(bibma + 0x02);
++      c1 = inb_p(bibma + 0x0a);
++#else
+       c0 = inb_p((unsigned short)bibma + 0x02);
+       c1 = inb_p((unsigned short)bibma + 0x0a);
++#endif
+       p += sprintf(p, "                                SLC90E66 Chipset.\n");
+-      p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+-      p += sprintf(p, "                %sabled                         %sabled\n",
++      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",
++      p += sprintf(p, "--------------- drive0 --------- drive1 "
++                      "-------- drive0 ---------- drive1 ------\n");
++      p += sprintf(p, "DMA enabled:    %s              %s "
++                      "            %s               %s\n",
+                       (c0&0x20) ? "yes" : "no ",
+                       (c0&0x40) ? "yes" : "no ",
+                       (c1&0x20) ? "yes" : "no ",
+                       (c1&0x40) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
++      p += sprintf(p, "UDMA enabled:   %s              %s "
++                      "            %s               %s\n",
+                       (reg48&0x01) ? "yes" : "no ",
+                       (reg48&0x02) ? "yes" : "no ",
+                       (reg48&0x04) ? "yes" : "no ",
+                       (reg48&0x08) ? "yes" : "no " );
+-      p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
++      p += sprintf(p, "UDMA enabled:   %s                %s "
++                      "              %s                 %s\n",
+                       ((reg4a&0x04)==0x04) ? "4" :
+                       ((reg4a&0x03)==0x03) ? "3" :
+                       (reg4a&0x02) ? "2" :
+@@ -145,12 +156,40 @@
+ byte slc90e66_proc = 0;
+-extern char *ide_xfer_verbose (byte xfer_rate);
++static byte slc90e66_ratemask (ide_drive_t *drive)
++{
++      byte mode       = 0x00;
++
++      mode |= 0x02;
++
++      if (!eighty_ninty_three(drive)) {
++              mode &= ~0xFE;
++              mode |= 0x01;
++      }
++      return (mode &= ~0xF8);
++}
++static byte slc90e66_ratefilter (ide_drive_t *drive, byte speed)
++{
+ #ifdef CONFIG_BLK_DEV_IDEDMA
+-/*
+- *
+- */
++      byte mode = slc90e66_ratemask(drive);
++
++      switch(mode) {
++              case 0x04:      // while (speed > XFER_UDMA_6) speed--; break;
++              case 0x03:      // while (speed > XFER_UDMA_5) speed--; break;
++              case 0x02:      while (speed > XFER_UDMA_4) speed--; break;
++              case 0x01:      while (speed > XFER_UDMA_2) speed--; break;
++              case 0x00:
++              default:        while (speed > XFER_MW_DMA_2) speed--; break;
++                      break;
++      }
++#else
++      while (speed > XFER_PIO_4) speed--;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++//    printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
++      return speed;
++}
++
+ static byte slc90e66_dma_2_pio (byte xfer_rate) {
+       switch(xfer_rate) {
+               case XFER_UDMA_4:
+@@ -177,7 +216,6 @@
+                       return 0;
+       }
+ }
+-#endif /* CONFIG_BLK_DEV_IDEDMA */
+ /*
+  *  Based on settings done by AMI BIOS
+@@ -185,12 +223,14 @@
+  */
+ static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
+ {
++      ide_hwif_t *hwif        = HWIF(drive);
++      struct pci_dev *dev     = hwif->pci_dev;
++      int is_slave            = (&hwif->drives[1] == drive);
++      int master_port         = hwif->channel ? 0x42 : 0x40;
++      int slave_port          = 0x44;
+       unsigned long flags;
+       u16 master_data;
+       byte slave_data;
+-      int is_slave            = (&HWIF(drive)->drives[1] == drive);
+-      int master_port         = HWIF(drive)->index ? 0x42 : 0x40;
+-      int slave_port          = 0x44;
+                                /* ISP  RTC */
+       byte timings[][2]       = { { 0, 0 },
+                                   { 0, 0 },
+@@ -199,42 +239,38 @@
+                                   { 2, 3 }, };
+       pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+-      pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
++      spin_lock_irqsave(&io_request_lock, flags);
++      pci_read_config_word(dev, master_port, &master_data);
+       if (is_slave) {
+               master_data = master_data | 0x4000;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0070;
+-              pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
+-              slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
+-              slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
+-                                         << (HWIF(drive)->index ? 4 : 0)));
++              pci_read_config_byte(dev, slave_port, &slave_data);
++              slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
++              slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+       } else {
+               master_data = master_data & 0xccf8;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0007;
+-              master_data = master_data | (timings[pio][0] << 12) |
+-                            (timings[pio][1] << 8);
++              master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+       }
+-      save_flags(flags);
+-      cli();
+-      pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
++      pci_write_config_word(dev, master_port, master_data);
+       if (is_slave)
+-              pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
+-      restore_flags(flags);
++              pci_write_config_byte(dev, slave_port, slave_data);
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+-#ifdef CONFIG_BLK_DEV_IDEDMA
+-static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
++static int slc90e66_tune_chipset (ide_drive_t *drive, byte xferspeed)
+ {
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       byte maslave            = hwif->channel ? 0x42 : 0x40;
++      byte speed              = slc90e66_ratefilter(drive, xferspeed);
+       int a_speed             = 7 << (drive->dn * 4);
+       int u_flag              = 1 << drive->dn;
+       int u_speed             = 0;
+-      int err                 = 0;
+       int                     sitre;
+       short                   reg4042, reg44, reg48, reg4a;
+@@ -245,6 +281,7 @@
+       pci_read_config_word(dev, 0x4a, &reg4a);
+       switch(speed) {
++#ifdef CONFIG_BLK_DEV_IDEDMA
+               case XFER_UDMA_4:       u_speed = 4 << (drive->dn * 4); break;
+               case XFER_UDMA_3:       u_speed = 3 << (drive->dn * 4); break;
+               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
+@@ -253,6 +290,11 @@
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_SW_DMA_2:     break;
++#endif /* CONFIG_BLK_DEV_IDEDMA */
++              case XFER_PIO_4:
++              case XFER_PIO_3:
++              case XFER_PIO_2:
++              case XFER_PIO_0:        break;
+               default:                return -1;
+       }
+@@ -264,8 +306,7 @@
+                       pci_read_config_word(dev, 0x4a, &reg4a);
+                       pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+               }
+-      }
+-      if (speed < XFER_UDMA_0) {
++      } else {
+               if (reg48 & u_flag)
+                       pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+               if (reg4a & a_speed)
+@@ -273,46 +314,45 @@
+       }
+       slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+-
+-#if SLC90E66_DEBUG_DRIVE_INFO
+-      printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
+-#endif /* SLC90E66_DEBUG_DRIVE_INFO */
+-      if (!drive->init_speed)
+-              drive->init_speed = speed;
+-      err = ide_config_drive_speed(drive, speed);
+-      drive->current_speed = speed;
+-      return err;
++      return (ide_config_drive_speed(drive, speed));
+ }
++#ifdef CONFIG_BLK_DEV_IDEDMA
+ static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+ {
+       struct hd_driveid *id   = drive->id;
+-      int ultra               = 1;
+-      byte speed              = 0;
+-      byte udma_66            = eighty_ninty_three(drive);
+-
+-      if ((id->dma_ultra & 0x0010) && (ultra)) {
+-              speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
+-      } else if ((id->dma_ultra & 0x0008) && (ultra)) {
+-              speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1;
+-      } else if ((id->dma_ultra & 0x0004) && (ultra)) {
+-              speed = XFER_UDMA_2;
+-      } else if ((id->dma_ultra & 0x0002) && (ultra)) {
+-              speed = XFER_UDMA_1;
+-      } else if ((id->dma_ultra & 0x0001) && (ultra)) {
+-              speed = XFER_UDMA_0;
+-      } else if (id->dma_mword & 0x0004) {
+-              speed = XFER_MW_DMA_2;
+-      } else if (id->dma_mword & 0x0002) {
+-              speed = XFER_MW_DMA_1;
+-      } else if (id->dma_1word & 0x0004) {
+-              speed = XFER_SW_DMA_2;
+-        } else {
+-              speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
++      byte mode               = slc90e66_ratemask(drive);
++      byte speed, tspeed, dma = 1;
++
++      switch(mode) {
++              case 0x02:
++                      if (id->dma_ultra & 0x0010)
++                              { speed = XFER_UDMA_4; break; }
++                      if (id->dma_ultra & 0x0008)
++                              { speed = XFER_UDMA_3; break; }
++              case 0x01:
++                      if (id->dma_ultra & 0x0004)
++                              { speed = XFER_UDMA_2; break; }
++                      if (id->dma_ultra & 0x0002)
++                              { speed = XFER_UDMA_1; break; }
++                      if (id->dma_ultra & 0x0001)
++                              { speed = XFER_UDMA_0; break; }
++              case 0x00:
++                      if (id->dma_mword & 0x0004)
++                              { speed = XFER_MW_DMA_2; break; }
++                      if (id->dma_mword & 0x0002)
++                              { speed = XFER_MW_DMA_1; break; }
++                      if (id->dma_1word & 0x0004)
++                              { speed = XFER_SW_DMA_2; break; }
++              default:
++                      tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
++                      speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
++                      dma = 0;
++                      break;
+       }
+       (void) slc90e66_tune_chipset(drive, speed);
+-
++//    return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
+       return ((int)   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+@@ -320,11 +360,62 @@
+                                                    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;
++
++      drive->init_speed = 0;
++
++      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 & 0x007F) {
++                              /* Force if Capable UltraDMA */
++                              dma_func = slc90e66_config_drive_for_dma(drive);
++                              if ((id->field_valid & 2) &&
++                                  (dma_func != ide_dma_on))
++                                      goto try_dma_modes;
++                      }
++              } else if (id->field_valid & 2) {
++try_dma_modes:
++                      if ((id->dma_mword & 0x0007) ||
++                          (id->dma_1word & 0x007)) {
++                              /* Force if Capable regular DMA modes */
++                              dma_func = slc90e66_config_drive_for_dma(drive);
++                              if (dma_func != ide_dma_on)
++                                      goto no_dma_set;
++                      }
++              } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
++                      if (id->eide_dma_time > 150) {
++                              goto no_dma_set;
++                      }
++                      /* Consult the list of known "good" drives */
++                      dma_func = slc90e66_config_drive_for_dma(drive);
++                      if (dma_func != ide_dma_on)
++                              goto no_dma_set;
++              } else {
++                      goto fast_ata_pio;
++              }
++      } else if ((id->capability & 8) || (id->field_valid & 2)) {
++fast_ata_pio:
++              dma_func = ide_dma_off_quietly;
++no_dma_set:
++              slc90e66_tune_drive(drive, 5);
++      }
++      return HWIF(drive)->dmaproc(dma_func, drive);
++}
++
+ static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+ {
+       switch (func) {
+               case ide_dma_check:
+-                       return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive);
++                      return config_drive_xfer_rate(drive);
+               default :
+                       break;
+       }
+@@ -347,16 +438,11 @@
+ unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
+ {
+-#if 1
+       byte reg47 = 0, ata66 = 0;
+       byte mask = hwif->channel ? 0x01 : 0x02;        /* bit0:Primary */
+       pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+-
+       ata66 = (reg47 & mask) ? 0 : 1; /* bit[0(1)]: 0:80, 1:40 */
+-#else
+-      byte ata66 = 0;
+-#endif
+       return ata66;
+ }
+@@ -365,6 +451,8 @@
+       if (!hwif->irq)
+               hwif->irq = hwif->channel ? 15 : 14;
++      hwif->autodma = 0;
++      hwif->speedproc = &slc90e66_tune_chipset;
+       hwif->tuneproc = &slc90e66_tune_drive;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+@@ -372,11 +460,11 @@
+       if (!hwif->dma_base)
+               return;
+-      hwif->autodma = 0;
+ #ifdef CONFIG_BLK_DEV_IDEDMA 
++      hwif->dmaproc = &slc90e66_dmaproc;
++#ifdef CONFIG_IDEDMA_AUTO
+       if (!noautodma)
+               hwif->autodma = 1;
+-      hwif->dmaproc = &slc90e66_dmaproc;
+-      hwif->speedproc = &slc90e66_tune_chipset;
++#endif /* CONFIG_IDEDMA_AUTO */
+ #endif /* !CONFIG_BLK_DEV_IDEDMA */
+ }
+diff -Nur linux.org/drivers/ide/trm290.c linux/drivers/ide/trm290.c
+--- linux.org/drivers/ide/trm290.c     Tue Jun 20 16:52:36 2000
++++ linux/drivers/ide/trm290.c Thu Jul 18 14:24:34 2002
+@@ -148,23 +148,23 @@
+       /* select PIO or DMA */
+       reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       if (reg != hwif->select_data) {
+               hwif->select_data = reg;
+-              outb(0x51|(hwif->channel<<3), hwif->config_data+1);     /* set PIO/DMA */
+-              outw(reg & 0xff, hwif->config_data);
++              /* set PIO/DMA */
++              OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
++              OUT_WORD(reg & 0xff, hwif->config_data);
+       }
+       /* enable IRQ if not probing */
+       if (drive->present) {
+-              reg = inw(hwif->config_data+3) & 0x13;
++              reg = IN_WORD(hwif->config_data+3) & 0x13;
+               reg &= ~(1 << hwif->channel);
+-              outw(reg, hwif->config_data+3);
++              OUT_WORD(reg, hwif->config_data+3);
+       }
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+ }
+ static void trm290_selectproc (ide_drive_t *drive)
+@@ -176,6 +176,7 @@
+ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+ {
+       ide_hwif_t *hwif = HWIF(drive);
++//    ide_task_t *args = HWGROUP(drive)->rq->special;
+       unsigned int count, reading = 2, writing = 0;
+       switch (func) {
+@@ -187,24 +188,46 @@
+ #endif
+               case ide_dma_read:
+                       if (!(count = ide_build_dmatable(drive, func)))
+-                              break;          /* try PIO instead of DMA */
+-                      trm290_prepare_drive(drive, 1); /* select DMA xfer */
++                              /* try PIO instead of DMA */
++                              break;
++                      /* select DMA xfer */
++                      trm290_prepare_drive(drive, 1);
+                       outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
+                       drive->waiting_for_dma = 1;
+-                      outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
++                      /* start DMA */
++                      OUT_WORD((count * 2) - 1, hwif->dma_base+2);
+                       if (drive->media != ide_disk)
+                               return 0;
++                      if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
++                              BUG();
+                       ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+-                      OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+-                      return 0;
++/*
++ * FIX ME to use only ACB ide_task_t args Struct
++ */
++#if 0
++              {
++                      ide_task_t *args = HWGROUP(drive)->rq->special;
++                      OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++              }
++#else
++                      if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
++                              ide_task_t *args = HWGROUP(drive)->rq->special;
++                              OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
++                      } else if (drive->addressing == 1)
++                              OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
++                      else
++                              OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
++#endif
++                      return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+               case ide_dma_begin:
+                       return 0;
+               case ide_dma_end:
+                       drive->waiting_for_dma = 0;
+-                      ide_destroy_dmatable(drive);            /* purge DMA mappings */
+-                      return (inw(hwif->dma_base+2) != 0x00ff);
++                      /* purge DMA mappings */
++                      ide_destroy_dmatable(drive);
++                      return (IN_WORD(hwif->dma_base+2) != 0x00ff);
+               case ide_dma_test_irq:
+-                      return (inw(hwif->dma_base+2) == 0x00ff);
++                      return (IN_WORD(hwif->dma_base+2) == 0x00ff);
+               default:
+                       return ide_dmaproc(func, drive);
+       }
+@@ -225,25 +248,28 @@
+       hwif->chipset = ide_trm290;
+       cfgbase = pci_resource_start(dev, 4);
+-      if ((dev->class & 5) && cfgbase)
+-      {
++      if ((dev->class & 5) && cfgbase) {
+               hwif->config_data = cfgbase;
+-              printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
++              printk("TRM290: chip config base at 0x%04lx\n",
++                      hwif->config_data);
+       } else {
+               hwif->config_data = 0x3df0;
+-              printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
++              printk("TRM290: using default config base at 0x%04lx\n",
++                      hwif->config_data);
+       }
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       /* put config reg into first byte of hwif->select_data */
+-      outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+-      hwif->select_data = 0x21;                       /* select PIO as default */
+-      outb(hwif->select_data, hwif->config_data);
+-      reg = inb(hwif->config_data+3);                 /* get IRQ info */
+-      reg = (reg & 0x10) | 0x03;                      /* mask IRQs for both ports */
+-      outb(reg, hwif->config_data+3);
+-      __restore_flags(flags); /* local CPU only */
++      OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
++      /* select PIO as default */
++      hwif->select_data = 0x21;
++      OUT_BYTE(hwif->select_data, hwif->config_data);
++      /* get IRQ info */
++      reg = IN_BYTE(hwif->config_data+3);
++      /* mask IRQs for both ports */
++      reg = (reg & 0x10) | 0x03;
++      OUT_BYTE(reg, hwif->config_data+3);
++      local_irq_restore(flags);
+       if ((reg & 0x10))
+               hwif->irq = hwif->channel ? 15 : 14;    /* legacy mode */
+@@ -256,20 +282,20 @@
+ #endif /* CONFIG_BLK_DEV_IDEDMA */
+       hwif->selectproc = &trm290_selectproc;
+-      hwif->autodma = 0;                              /* play it safe for now */
++      hwif->autodma = 0;                      /* play it safe for now */
+ #if 1
+       {
+-              /*
+-               * My trm290-based card doesn't seem to work with all possible values
+-               * for the control basereg, so this kludge ensures that we use only
+-               * values that are known to work.  Ugh.         -ml
+-               */
++      /*
++       * My trm290-based card doesn't seem to work with all possible values
++       * for the control basereg, so this kludge ensures that we use only
++       * values that are known to work.  Ugh.         -ml
++       */
+               unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+               static unsigned short next_offset = 0;
+-              outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+-              old = inw(hwif->config_data) & ~1;
+-              if (old != compat && inb(old+2) == 0xff) {
++              OUT_BYTE(0x54|(hwif->channel<<3), hwif->config_data+1);
++              old = IN_WORD(hwif->config_data) & ~1;
++              if (old != compat && IN_BYTE(old+2) == 0xff) {
+                       compat += (next_offset += 0x400);       /* leave lower 10 bits untouched */
+ #if 1
+                       if (ide_check_region(compat + 2, 1))
+@@ -281,8 +307,8 @@
+                        */
+ #endif
+                       hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+-                      outw(compat|1, hwif->config_data);
+-                      printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
++                      OUT_WORD(compat|1, hwif->config_data);
++                      printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, IN_WORD(hwif->config_data) & ~1);
+               }
+       }
+ #endif
+diff -Nur linux.org/drivers/ide/umc8672.c linux/drivers/ide/umc8672.c
+--- linux.org/drivers/ide/umc8672.c    Fri Apr 14 07:54:26 2000
++++ linux/drivers/ide/umc8672.c        Thu Jul 18 14:24:34 2002
+@@ -73,36 +73,34 @@
+ static void out_umc (char port,char wert)
+ {
+-      outb_p (port,0x108);
+-      outb_p (wert,0x109);
++      outb_p(port,0x108);
++      outb_p(wert,0x109);
+ }
+ static inline byte in_umc (char port)
+ {
+-      outb_p (port,0x108);
+-      return inb_p (0x109);
++      outb_p(port,0x108);
++      return inb_p(0x109);
+ }
+ static void umc_set_speeds (byte speeds[])
+ {
+       int i, tmp;
+-      outb_p (0x5A,0x108); /* enable umc */
++      outb_p(0x5A,0x108); /* enable umc */
+       out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+       out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+       tmp = 0;
+-      for (i = 3; i >= 0; i--)
+-      {
++      for (i = 3; i >= 0; i--) {
+               tmp = (tmp << 2) | speedtab[1][speeds[i]];
+       }
+       out_umc (0xdc,tmp);
+-      for (i = 0;i < 4; i++)
+-      {
++      for (i = 0;i < 4; i++) {
+               out_umc (0xd0+i,speedtab[2][speeds[i]]);
+               out_umc (0xd8+i,speedtab[2][speeds[i]]);
+       }
+-      outb_p (0xa5,0x108); /* disable umc */
++      outb_p(0xa5,0x108); /* disable umc */
+       printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+               speeds[0], speeds[1], speeds[2], speeds[3]);
+@@ -114,40 +112,38 @@
+       ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+-      printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
+-      save_flags(flags);      /* all CPUs */
+-      cli();                  /* all CPUs */
++      printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
++              drive->name, pio, pio_to_umc[pio]);
++      spin_lock_irqsave(&io_request_lock, flags);
+       if (hwgroup && hwgroup->handler != NULL) {
+               printk("umc8672: other interface is busy: exiting tune_umc()\n");
+       } else {
+               current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+               umc_set_speeds (current_speeds);
+       }
+-      restore_flags(flags);   /* all CPUs */
++      spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ void __init init_umc8672 (void)       /* called from ide.c */
+ {
+       unsigned long flags;
+-      __save_flags(flags);    /* local CPU only */
+-      __cli();                /* local CPU only */
++      local_irq_save(flags);
+       if (check_region(0x108, 2)) {
+-              __restore_flags(flags);
++              local_irq_restore(flags);
+               printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
+               return;
+       }
+-      outb_p (0x5A,0x108); /* enable umc */
+-      if (in_umc (0xd5) != 0xa0)
+-      {
+-              __restore_flags(flags); /* local CPU only */
++      outb_p(0x5A,0x108); /* enable umc */
++      if (in_umc (0xd5) != 0xa0) {
++              local_irq_restore(flags);
+               printk ("umc8672: not found\n");
+               return;  
+       }
+-      outb_p (0xa5,0x108); /* disable umc */
++      outb_p(0xa5,0x108); /* disable umc */
+       umc_set_speeds (current_speeds);
+-      __restore_flags(flags); /* local CPU only */
++      local_irq_restore(flags);
+       request_region(0x108, 2, "umc8672");
+       ide_hwifs[0].chipset = ide_umc8672;
+diff -Nur linux.org/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
+--- linux.org/drivers/ide/via82cxxx.c  Tue Sep 11 17:40:36 2001
++++ linux/drivers/ide/via82cxxx.c      Thu Jul 18 14:24:34 2002
+@@ -1,5 +1,5 @@
+ /*
+- * $Id$
++ * $Id$
+  *
+  *  Copyright (c) 2000-2001 Vojtech Pavlik
+  *
+@@ -7,23 +7,21 @@
+  *    Michel Aubry
+  *    Jeff Garzik
+  *    Andre Hedrick
+- *
+- *  Sponsored by SuSE
+  */
+ /*
+  * VIA IDE driver for Linux. Supports
+  *
+  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233
++ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a
+  *
+  * southbridges, which can be found in
+  *
+  *  VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro,
+  *    ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z,
+  *    PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T,
+- *    PX266, PM266, KX133, KT133, KT133A, KLE133, KT266, KX266, KM133, KM133A,
+- *    KL133, KN133, KM266
++ *    PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133,
++ *    KM133A, KL133, KN133, KM266
+  *  PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo,
+  *    BXTel, BXpert
+  *  AMD 640, 640 AGP, 750 IronGate, 760, 760MP
+@@ -32,9 +30,9 @@
+  *
+  * chipsets. Supports
+  *
+- *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5
++ *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6
+  *
+- * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are
++ * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are
+  * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
+  * the BIOS data and assume the cable is present, use 'ide0=ata66' or
+  * 'ide1=ata66' on the kernel command line.
+@@ -56,8 +54,8 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  *
+  * Should you need to contact me, the author, you can do so either by
+- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
++ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+  */
+ #include <linux/config.h>
+@@ -87,10 +85,12 @@
+ #define VIA_UDMA_33           0x001
+ #define VIA_UDMA_66           0x002
+ #define VIA_UDMA_100          0x003
++#define VIA_UDMA_133          0x004
+ #define VIA_BAD_PREQ          0x010   /* Crashes if PREQ# till DDACK# set */
+ #define VIA_BAD_CLK66         0x020   /* 66 MHz clock doesn't work correctly */
+ #define VIA_SET_FIFO          0x040   /* Needs to have FIFO split set */
+ #define VIA_NO_UNMASK         0x080   /* Doesn't work with IRQ unmasking on */
++#define VIA_BAD_ID            0x100   /* Has wrong vendor ID (0x1107) */
+ /*
+  * VIA SouthBridge chips.
+@@ -104,10 +104,11 @@
+       unsigned short flags;
+ } via_isa_bridges[] = {
+ #ifdef FUTURE_BRIDGES
+-      { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_100 },
+-      { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_100 },
+-      { "vt8233c",    PCI_DEVICE_ID_VIA_8233C,    0x00, 0x2f, VIA_UDMA_100 },
++      { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
++      { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
+ #endif
++      { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
++      { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
+       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
+       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
+@@ -121,6 +122,7 @@
+       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
++      { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+       { NULL }
+ };
+@@ -128,7 +130,7 @@
+ static unsigned char via_enabled;
+ static unsigned int via_80w;
+ static unsigned int via_clock;
+-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
++static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+ /*
+  * VIA /proc entry.
+@@ -151,7 +153,7 @@
+ static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+ {
+-      short speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
++      int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+                uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+       struct pci_dev *dev = bmide_dev;
+       unsigned int v, u, i;
+@@ -161,7 +163,7 @@
+       via_print("----------VIA BusMastering IDE Configuration----------------");
+-      via_print("Driver Version:                     3.29");
++      via_print("Driver Version:                     3.34");
+       via_print("South Bridge:                       VIA %s", via_config->name);
+       pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+@@ -170,7 +172,7 @@
+       via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
+       via_print("BM-DMA base:                        %#x", via_base);
+-      via_print("PCI clock:                          %dMHz", via_clock);
++      via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
+       pci_read_config_byte(dev, VIA_MISC_1, &t);
+       via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
+@@ -191,7 +193,7 @@
+       pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+       via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+-      c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
++      c = IN_BYTE(via_base + 0x02) | (IN_BYTE(via_base + 0x0a) << 8);
+       via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+       via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+@@ -218,40 +220,45 @@
+               uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+               den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+-              speed[i] = 20 * via_clock / (active[i] + recover[i]);
+-              cycle[i] = 1000 / via_clock * (active[i] + recover[i]);
++              speed[i] = 2 * via_clock / (active[i] + recover[i]);
++              cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+               if (!uen[i] || !den[i])
+                       continue;
+               switch (via_config->flags & VIA_UDMA) {
+-                      
+-                      case VIA_UDMA_100:
+-                              speed[i] = 60 * via_clock / udma[i];
+-                              cycle[i] = 333 / via_clock * udma[i];
++
++                      case VIA_UDMA_33:
++                              speed[i] = 2 * via_clock / udma[i];
++                              cycle[i] = 1000000 * udma[i] / via_clock;
+                               break;
+                       case VIA_UDMA_66:
+-                              speed[i] = 40 * via_clock / (udma[i] * umul[i]);
+-                              cycle[i] = 500 / via_clock * (udma[i] * umul[i]);
++                              speed[i] = 4 * via_clock / (udma[i] * umul[i]);
++                              cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+                               break;
+-                      case VIA_UDMA_33:
+-                              speed[i] = 20 * via_clock / udma[i];
+-                              cycle[i] = 1000 / via_clock * udma[i];
++                      case VIA_UDMA_100:
++                              speed[i] = 6 * via_clock / udma[i];
++                              cycle[i] = 333333 * udma[i] / via_clock;
++                              break;
++
++                      case VIA_UDMA_133:
++                              speed[i] = 8 * via_clock / udma[i];
++                              cycle[i] = 250000 * udma[i] / via_clock;
+                               break;
+               }
+       }
+       via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+-      via_print_drive("Address Setup: ", "%8dns", (1000 / via_clock) * setup[i]);
+-      via_print_drive("Cmd Active:    ", "%8dns", (1000 / via_clock) * active8b[i]);
+-      via_print_drive("Cmd Recovery:  ", "%8dns", (1000 / via_clock) * recover8b[i]);
+-      via_print_drive("Data Active:   ", "%8dns", (1000 / via_clock) * active[i]);
+-      via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]);
++      via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
++      via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
++      via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
++      via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
++      via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
+       via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
+-      via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10);
++      via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
+       return p - buffer;      /* hoping it is less than 4K... */
+ }
+@@ -280,6 +287,7 @@
+               case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+               case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+               case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
++              case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+               default: return;
+       }
+@@ -296,20 +304,21 @@
+ {
+       ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+       struct ide_timing t, p;
+-      int T, UT;
++      unsigned int T, UT;
+       if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+               if (ide_config_drive_speed(drive, speed))
+                       printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
+                               drive->dn >> 1, drive->dn & 1);
+-      T = 1000 / via_clock;
++      T = 1000000000 / via_clock;
+       switch (via_config->flags & VIA_UDMA) {
+               case VIA_UDMA_33:   UT = T;   break;
+               case VIA_UDMA_66:   UT = T/2; break;
+               case VIA_UDMA_100:  UT = T/3; break;
+-              default:            UT = T;   break;
++              case VIA_UDMA_133:  UT = T/4; break;
++              default: UT = T;
+       }
+       ide_timing_compute(drive, speed, &t, T, UT);
+@@ -365,7 +374,8 @@
+                       XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+                       (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+                       (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+-                      (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0));
++                      (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
++                      (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+               via_set_drive(drive, speed);
+@@ -395,14 +405,16 @@
+  */
+       for (via_config = via_isa_bridges; via_config->id; via_config++)
+-              if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) {
++              if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
++                      !!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
++
+                       pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+                       if (t >= via_config->rev_min && t <= via_config->rev_max)
+                               break;
+               }
+       if (!via_config->id) {
+-              printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n");
++              printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
+               return -ENODEV;
+       }
+@@ -412,22 +424,28 @@
+       switch (via_config->flags & VIA_UDMA) {
+-              case VIA_UDMA_100:
+-
+-                      pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+-                      for (i = 24; i >= 0; i -= 8)
+-                              if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3)))
+-                                      via_80w |= (1 << (1 - (i >> 4)));       /* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */
+-                      break;
+-
+               case VIA_UDMA_66:
+-
+                       pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);        /* Enable Clk66 */
+                       pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
+                       for (i = 24; i >= 0; i -= 8)
+                               if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
+                                       via_80w |= (1 << (1 - (i >> 4)));       /* 2x PCI clock and UDMA w/ < 3T/cycle */
+                       break;
++
++              case VIA_UDMA_100:
++                      pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
++                      for (i = 24; i >= 0; i -= 8)
++                              if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
++                                      via_80w |= (1 << (1 - (i >> 4)));       /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
++                      break;
++
++              case VIA_UDMA_133:
++                      pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
++                      for (i = 24; i >= 0; i -= 8)
++                              if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
++                                      via_80w |= (1 << (1 - (i >> 4)));       /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
++                      break;
++
+       }
+       if (via_config->flags & VIA_BAD_CLK66) {                        /* Disable Clk66 */
+@@ -466,11 +484,18 @@
+  * Determine system bus clock.
+  */
+-      via_clock = system_bus_clock();
+-      if (via_clock < 20 || via_clock > 50) {
++      via_clock = system_bus_clock() * 1000;
++
++      switch (via_clock) {
++              case 33000: via_clock = 33333; break;
++              case 37000: via_clock = 37500; break;
++              case 41000: via_clock = 41666; break;
++      }
++
++      if (via_clock < 20000 || via_clock > 50000) {
+               printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
+-              printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n");
+-              via_clock = 33;
++              printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
++              via_clock = 33333;
+       }
+ /*
+--- linux.org/include/linux/ide.h      Thu Nov 22 20:48:07 2001
++++ linux/include/linux/ide.h  Thu Jul 18 14:24:44 2002
+@@ -14,7 +14,16 @@
+ #include <linux/blkdev.h>
+ #include <linux/proc_fs.h>
+ #include <linux/devfs_fs_kernel.h>
++#include <asm/byteorder.h>
++#include <asm/system.h>
+ #include <asm/hdreg.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
++#  define __IDEDMA_TIMEOUT
++#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
++#  undef __IDEDMA_TIMEOUT
++#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+ /*
+  * This is the multiple IDE interface driver, as evolved from hd.c.
+@@ -65,13 +74,14 @@
+ /*
+  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
+  */
+-#define IDE_DRIVE_CMD         99      /* (magic) undef to reduce kernel size*/
++#define IDE_DRIVE_CMD                 99      /* (magic) undef to reduce kernel size*/
++
++#define IDE_DRIVE_TASK                        98
+ /*
+- * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
++ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
+  */
+-#define IDE_DRIVE_TASK                98
+-#define IDE_DRIVE_CMD_AEB     98
++#define IDE_DRIVE_TASKFILE            97
+ /*
+  *  "No user-serviceable parts" beyond this point  :)
+@@ -120,6 +130,17 @@
+ #define IDE_FEATURE_OFFSET    IDE_ERROR_OFFSET
+ #define IDE_COMMAND_OFFSET    IDE_STATUS_OFFSET
++#define IDE_DATA_OFFSET_HOB   (0)
++#define IDE_ERROR_OFFSET_HOB  (1)
++#define IDE_NSECTOR_OFFSET_HOB        (2)
++#define IDE_SECTOR_OFFSET_HOB (3)
++#define IDE_LCYL_OFFSET_HOB   (4)
++#define IDE_HCYL_OFFSET_HOB   (5)
++#define IDE_SELECT_OFFSET_HOB (6)
++#define IDE_CONTROL_OFFSET_HOB        (7)
++
++#define IDE_FEATURE_OFFSET_HOB        IDE_ERROR_OFFSET_HOB
++
+ #define IDE_DATA_REG          (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+ #define IDE_ERROR_REG         (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+ #define IDE_NSECTOR_REG               (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+@@ -131,6 +152,16 @@
+ #define IDE_CONTROL_REG               (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+ #define IDE_IRQ_REG           (HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
++#define IDE_DATA_REG_HOB      (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
++#define IDE_ERROR_REG_HOB     (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
++#define IDE_NSECTOR_REG_HOB   (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
++#define IDE_SECTOR_REG_HOB    (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
++#define IDE_LCYL_REG_HOB      (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
++#define IDE_HCYL_REG_HOB      (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
++#define IDE_SELECT_REG_HOB    (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
++#define IDE_STATUS_REG_HOB    (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
++#define IDE_CONTROL_REG_HOB   (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
++
+ #define IDE_FEATURE_REG               IDE_ERROR_REG
+ #define IDE_COMMAND_REG               IDE_STATUS_REG
+ #define IDE_ALTSTATUS_REG     IDE_CONTROL_REG
+@@ -156,11 +187,21 @@
+ #define PARTN_BITS    6       /* number of minor dev bits for partitions */
+ #define PARTN_MASK    ((1<<PARTN_BITS)-1)     /* a useful bit mask */
+ #define MAX_DRIVES    2       /* per interface; 2 assumed by lots of code */
+-#define SECTOR_WORDS  (512 / 4)       /* number of 32bit words per sector */
++#define CASCADE_DRIVES        8       /* per interface; 8|2 assumed by lots of code */
++#define SECTOR_SIZE   512
++#define SECTOR_WORDS  (SECTOR_SIZE / 4)       /* number of 32bit words per sector */
+ #define IDE_LARGE_SEEK(b1,b2,t)       (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
+ #define IDE_MIN(a,b)  ((a)<(b) ? (a):(b))
+ #define IDE_MAX(a,b)  ((a)>(b) ? (a):(b))
++#ifndef SPLIT_WORD
++#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
++#endif
++#ifndef MAKE_WORD
++#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
++#endif
++
++
+ /*
+  * Timeouts for various operations:
+  */
+@@ -170,8 +211,7 @@
+ #else
+ #define WAIT_READY    (3*HZ/100)      /* 30msec - should be instantaneous */
+ #endif /* CONFIG_APM || CONFIG_APM_MODULE */
+-#define WAIT_PIDENTIFY        (10*HZ) /* 10sec  - should be less than 3ms (?)
+-                                          if all ATAPI CD is closed at boot */
++#define WAIT_PIDENTIFY        (10*HZ) /* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
+ #define WAIT_WORSTCASE        (30*HZ) /* 30sec  - worst case when spinning up */
+ #define WAIT_CMD      (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
+ #define WAIT_MIN_SLEEP        (2*HZ/100)      /* 20msec - minimum sleep time */
+@@ -209,6 +249,11 @@
+               (drive)->quirk_list = hwif->quirkproc(drive);   \
+ }
++#define HOST(hwif,chipset)                                    \
++{                                                             \
++      return ((hwif)->chipset == chipset) ? 1 : 0;            \
++}
++
+ #define IDE_DEBUG(lineno) \
+       printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
+@@ -223,6 +268,18 @@
+ #endif
+ /*
++ * hwif_chipset_t is used to keep track of the specific hardware
++ * chipset used by each IDE interface, if known.
++ */
++typedef enum {        ide_unknown,    ide_generic,    ide_pci,
++              ide_cmd640,     ide_dtc2278,    ide_ali14xx,
++              ide_qd65xx,     ide_umc8672,    ide_ht6560b,
++              ide_pdc4030,    ide_rz1000,     ide_trm290,
++              ide_cmd646,     ide_cy82c693,   ide_4drives,
++              ide_pmac,       ide_etrax100
++} hwif_chipset_t;
++
++/*
+  * Structure to hold all information about the location of this port
+  */
+ typedef struct hw_regs_s {
+@@ -231,6 +288,7 @@
+       int             dma;                    /* our dma entry */
+       ide_ack_intr_t  *ack_intr;              /* acknowledge interrupt */
+       void            *priv;                  /* interface specific data */
++      hwif_chipset_t  chipset;
+ } hw_regs_t;
+ /*
+@@ -257,19 +315,23 @@
+  */
+ #ifndef HAVE_ARCH_OUT_BYTE
+-#ifdef REALLY_FAST_IO
+-#define OUT_BYTE(b,p)          outb((b),(p))
+-#else
+-#define OUT_BYTE(b,p)          outb_p((b),(p))
+-#endif
++# ifdef REALLY_FAST_IO
++#  define OUT_BYTE(b,p)               outb((b),(p))
++#  define OUT_WORD(w,p)               outw((w),(p))
++# else
++#  define OUT_BYTE(b,p)               outb_p((b),(p))
++#  define OUT_WORD(w,p)               outw_p((w),(p))
++# endif
+ #endif
+ #ifndef HAVE_ARCH_IN_BYTE
+-#ifdef REALLY_FAST_IO
+-#define IN_BYTE(p)             (byte)inb_p(p)
+-#else
+-#define IN_BYTE(p)             (byte)inb(p)
+-#endif
++# ifdef REALLY_FAST_IO
++#  define IN_BYTE(p)          (byte)inb(p)
++#  define IN_WORD(p)          (short)inw(p)
++# else
++#  define IN_BYTE(p)          (byte)inb_p(p)
++#  define IN_WORD(p)          (short)inw_p(p)
++# endif
+ #endif
+ /*
+@@ -286,14 +348,74 @@
+ typedef union {
+       unsigned all                    : 8;    /* all of the bits together */
+       struct {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
+               unsigned set_geometry   : 1;    /* respecify drive geometry */
+               unsigned recalibrate    : 1;    /* seek to cyl 0      */
+               unsigned set_multmode   : 1;    /* set multmode count */
+               unsigned set_tune       : 1;    /* tune interface for drive */
+-              unsigned reserved       : 4;    /* unused */
++              unsigned serviced       : 1;    /* service command */
++              unsigned reserved       : 3;    /* unused */
++#elif defined(__BIG_ENDIAN_BITFIELD)
++              unsigned reserved       : 3;    /* unused */
++              unsigned serviced       : 1;    /* service command */
++              unsigned set_tune       : 1;    /* tune interface for drive */
++              unsigned set_multmode   : 1;    /* set multmode count */
++              unsigned recalibrate    : 1;    /* seek to cyl 0      */
++              unsigned set_geometry   : 1;    /* respecify drive geometry */
++#else
++#error "Please fix <asm/byteorder.h>"
++#endif
+       } b;
+ } special_t;
++typedef union {
++      unsigned all                    : 8;    /* all of the bits together */
++      struct {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++              unsigned head           : 4;    /* always zeros here */
++              unsigned unit           : 1;    /* drive select number: 0/1 */
++              unsigned bit5           : 1;    /* always 1 */
++              unsigned lba            : 1;    /* using LBA instead of CHS */
++              unsigned bit7           : 1;    /* always 1 */
++#elif defined(__BIG_ENDIAN_BITFIELD)
++              unsigned bit7           : 1;    /* always 1 */
++              unsigned lba            : 1;    /* using LBA instead of CHS */
++              unsigned bit5           : 1;    /* always 1 */
++              unsigned unit           : 1;    /* drive select number: 0/1 */
++              unsigned head           : 4;    /* always zeros here */
++#else
++#error "Please fix <asm/byteorder.h>"
++#endif
++      } b;
++} select_t;
++
++typedef union {
++      unsigned all                    : 8;    /* all of the bits together */
++      struct {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++              unsigned bit0           : 1;
++              unsigned nIEN           : 1;    /* device INTRQ to host */
++              unsigned SRST           : 1;    /* host soft reset bit */
++              unsigned bit3           : 1;    /* ATA-2 thingy */
++              unsigned reserved456    : 3;
++              unsigned HOB            : 1;    /* 48-bit address ordering */
++#elif defined(__BIG_ENDIAN_BITFIELD)
++              unsigned HOB            : 1;    /* 48-bit address ordering */
++              unsigned reserved456    : 3;
++              unsigned bit3           : 1;    /* ATA-2 thingy */
++              unsigned SRST           : 1;    /* host soft reset bit */
++              unsigned nIEN           : 1;    /* device INTRQ to host */
++              unsigned bit0           : 1;
++#else
++#error "Please fix <asm/byteorder.h>"
++#endif
++      } b;
++} control_t;
++
++
++struct ide_driver_s;
++struct ide_settings_s;
++
+ typedef struct ide_drive_s {
+       request_queue_t          queue; /* request queue */
+       struct ide_drive_s      *next;  /* circular list of hwgroup drives */
+@@ -328,6 +450,12 @@
+       unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
+       unsigned remap_0_to_1   : 2;    /* 0=remap if ezdrive, 1=remap, 2=noremap */
+       unsigned ata_flash      : 1;    /* 1=present, 0=default */
++      unsigned addressing;            /*      : 3;
++                                       *  0=28-bit
++                                       *  1=48-bit
++                                       *  2=48-bit doing 28-bit
++                                       *  3=64-bit
++                                       */
+       byte            scsi;           /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
+       byte            media;          /* disk, cdrom, tape, floppy, ... */
+       select_t        select;         /* basic drive/head select reg value */
+@@ -340,7 +468,7 @@
+       byte            bad_wstat;      /* used for ignoring WRERR_STAT */
+       byte            nowerr;         /* used for ignoring WRERR_STAT */
+       byte            sect0;          /* offset of first sector for DM6:DDO */
+-      byte            usage;          /* current "open()" count for drive */
++      unsigned int    usage;          /* current "open()" count for drive */
+       byte            head;           /* "real" number of heads */
+       byte            sect;           /* "real" sectors per track */
+       byte            bios_head;      /* BIOS/fdisk/LILO number of heads */
+@@ -348,17 +476,18 @@
+       unsigned int    bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
+       unsigned int    cyl;            /* "real" number of cyls */
+       unsigned long   capacity;       /* total number of sectors */
++      unsigned long long capacity48;  /* total number of sectors */
+       unsigned int    drive_data;     /* for use by tuneproc/selectproc as needed */
+-      void              *hwif;        /* actually (ide_hwif_t *) */
++      struct hwif_s     *hwif;        /* actually (ide_hwif_t *) */
+       wait_queue_head_t wqueue;       /* used to wait for drive in open() */
+       struct hd_driveid *id;          /* drive model identification info */
+       struct hd_struct  *part;        /* drive partition table */
+       char            name[4];        /* drive name, such as "hda" */
+-      void            *driver;        /* (ide_driver_t *) */
++      struct ide_driver_s *driver;    /* (ide_driver_t *) */
+       void            *driver_data;   /* extra driver data */
+       devfs_handle_t  de;             /* directory for device */
+       struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
+-      void            *settings;      /* /proc/ide/ drive settings */
++      struct ide_settings_s *settings;        /* /proc/ide/ drive settings */
+       char            driver_req[10]; /* requests specific driver */
+       int             last_lun;       /* last logical unit */
+       int             forced_lun;     /* if hdxlun was given at boot */
+@@ -369,6 +498,8 @@
+       byte            init_speed;     /* transfer rate set at boot */
+       byte            current_speed;  /* current transfer rate set */
+       byte            dn;             /* now wide spread use */
++      byte            wcache;         /* status of write cache */
++      byte            acoustic;       /* acoustic management */
+       unsigned int    failures;       /* current failure count */
+       unsigned int    max_failures;   /* maximum allowed failure count */
+ } ide_drive_t;
+@@ -387,6 +518,7 @@
+ typedef enum {        ide_dma_read,   ide_dma_write,          ide_dma_begin,
+               ide_dma_end,    ide_dma_check,          ide_dma_on,
+               ide_dma_off,    ide_dma_off_quietly,    ide_dma_test_irq,
++              ide_dma_host_on,                        ide_dma_host_off,
+               ide_dma_bad_drive,                      ide_dma_good_drive,
+               ide_dma_verbose,                        ide_dma_retune,
+               ide_dma_lostirq,                        ide_dma_timeout
+@@ -412,6 +544,81 @@
+ typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
+ /*
++ * mapping stuff, prepare for highmem...
++ * 
++ * temporarily mapping a (possible) highmem bio for PIO transfer
++ */
++#define ide_rq_offset(rq) \
++      (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
++
++extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
++{
++      return rq->buffer + ide_rq_offset(rq);
++}
++
++extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
++{
++      do { } while (0);
++}
++
++/*
++ * A Verbose noise maker for debugging on the attempted transfer rates.
++ */
++extern inline 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");
++      }
++}
++
++/*
++ * A Verbose noise maker for debugging on the attempted dmaing calls.
++ */
++extern inline 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_host_on:           return("ide_dma_host_on");
++              case ide_dma_host_off:          return("ide_dma_host_off");
++              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");
++      }
++}
++
++/*
+  * An ide_tuneproc_t() is used to set the speed of an IDE interface
+  * to a particular PIO mode.  The "byte" parameter is used
+  * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
+@@ -438,19 +645,7 @@
+ /*
+  * ide soft-power support
+  */
+-typedef int (ide_busproc_t) (struct hwif_s *, int);
+-
+-/*
+- * hwif_chipset_t is used to keep track of the specific hardware
+- * chipset used by each IDE interface, if known.
+- */
+-typedef enum {        ide_unknown,    ide_generic,    ide_pci,
+-              ide_cmd640,     ide_dtc2278,    ide_ali14xx,
+-              ide_qd65xx,     ide_umc8672,    ide_ht6560b,
+-              ide_pdc4030,    ide_rz1000,     ide_trm290,
+-              ide_cmd646,     ide_cy82c693,   ide_4drives,
+-              ide_pmac,       ide_etrax100
+-} hwif_chipset_t;
++typedef int (ide_busproc_t) (ide_drive_t *, int);
+ #define IDE_CHIPSET_PCI_MASK  \
+     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
+@@ -468,21 +663,29 @@
+ typedef struct hwif_s {
+       struct hwif_s   *next;          /* for linked-list in ide_hwgroup_t */
+-      void            *hwgroup;       /* actually (ide_hwgroup_t *) */
++      struct hwgroup_s *hwgroup;      /* actually (ide_hwgroup_t *) */
+       ide_ioreg_t     io_ports[IDE_NR_PORTS]; /* task file registers */
++/*
++ *     FIXME!! need a generic register set :-/  PPC guys ideas??
++ *
++ *     ide_mmioreg_t   mm_ports[IDE_NR_PORTS]; "task file registers"
++ *
++ */
+       hw_regs_t       hw;             /* Hardware info */
+       ide_drive_t     drives[MAX_DRIVES];     /* drive info */
+       struct gendisk  *gd;            /* gendisk structure */
+-      ide_tuneproc_t  *tuneproc;      /* routine to tune PIO mode for drives */
+-      ide_speedproc_t *speedproc;     /* routine to retune DMA modes for drives */
+-      ide_selectproc_t *selectproc;   /* tweaks hardware to select drive */
+-      ide_resetproc_t *resetproc;     /* routine to reset controller after a disk reset */
+-      ide_intrproc_t  *intrproc;      /* special interrupt handling for shared pci interrupts */
+-      ide_maskproc_t  *maskproc;      /* special host masking for drive selection */
+-      ide_quirkproc_t *quirkproc;     /* check host's drive quirk list */
+-      ide_rw_proc_t   *rwproc;        /* adjust timing based upon rq->cmd direction */
+-      ide_ideproc_t   *ideproc;       /* CPU-polled transfer routine */
+-      ide_dmaproc_t   *dmaproc;       /* dma read/write/abort routine */
++      int             addressing;     /* hosts addressing */
++      void            (*tuneproc)(ide_drive_t *, byte);       /* routine to tune PIO mode for drives */
++      int             (*speedproc)(ide_drive_t *, byte);      /* routine to retune DMA modes for drives */
++      void            (*selectproc)(ide_drive_t *);           /* tweaks hardware to select drive */
++      void            (*resetproc)(ide_drive_t *);            /* routine to reset controller after a disk reset */
++      void            (*intrproc)(ide_drive_t *);             /* special interrupt handling for shared pci interrupts */
++      void            (*maskproc)(ide_drive_t *, int);        /* special host masking for drive selection */
++      int             (*quirkproc)(ide_drive_t *);            /* check host's drive quirk list */
++      void            (*rwproc)(ide_drive_t *, ide_dma_action_t);     /* adjust timing based upon rq->cmd direction */
++      void            (*ideproc)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);      /* CPU-polled transfer routine */
++      int             (*dmaproc)(ide_dma_action_t, ide_drive_t *);    /* dma read/write/abort routine */
++      int             (*busproc)(ide_drive_t *, int);         /* driver soft-power interface */
+       unsigned int    *dmatable_cpu;  /* dma physical region descriptor table (cpu view) */
+       dma_addr_t      dmatable_dma;   /* dma physical region descriptor table (dma view) */
+       struct scatterlist *sg_table;   /* Scatter-gather list used to build the above */
+@@ -507,6 +710,7 @@
+       unsigned        reset      : 1; /* reset after probe */
+       unsigned        autodma    : 1; /* automatically try to enable DMA at boot */
+       unsigned        udma_four  : 1; /* 1=ATA-66 capable, 0=default */
++      unsigned        highmem    : 1; /* can do full 32-bit dma */
+       byte            channel;        /* for dual-port chips: 0=primary, 1=secondary */
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+       struct pci_dev  *pci_dev;       /* for pci chipsets */
+@@ -517,11 +721,9 @@
+ #endif
+       byte            straight8;      /* Alan's straight 8 check */
+       void            *hwif_data;     /* extra hwif data */
+-      ide_busproc_t   *busproc;       /* driver soft-power interface */
+       byte            bus_state;      /* power state of the IDE bus */
+ } ide_hwif_t;
+-
+ /*
+  * Status returned from various ide_ functions
+  */
+@@ -533,7 +735,9 @@
+ /*
+  *  internal ide interrupt handler type
+  */
++typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
+ typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
++typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
+ /*
+  * when ide_timer_expiry fires, invoke a handler of this type
+@@ -543,6 +747,7 @@
+ typedef struct hwgroup_s {
+       ide_handler_t           *handler;/* irq handler, if active */
++      ide_handler_t           *handler_save;/* irq handler, if active */
+       volatile int            busy;   /* BOOL: protects all fields below */
+       int                     sleeping; /* BOOL: wake us up on timer expiry */
+       ide_drive_t             *drive; /* current drive */
+@@ -552,8 +757,11 @@
+       struct request          wrq;    /* local copy of current write rq */
+       unsigned long           poll_timeout;   /* timeout value during long polls */
+       ide_expiry_t            *expiry;        /* queried upon timeouts */
++      int                     pio_clock;      /* ide_system_bus_speed */
+ } ide_hwgroup_t;
++/* structure attached to the request for IDE_TASK_CMDS */
++
+ /*
+  * configurable drive settings
+  */
+@@ -604,6 +812,8 @@
+ #ifdef CONFIG_PROC_FS
+ void proc_ide_create(void);
+ void proc_ide_destroy(void);
++void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
++void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+ void destroy_proc_ide_drives(ide_hwif_t *);
+ void create_proc_ide_interfaces(void);
+ void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
+@@ -635,20 +845,6 @@
+  */
+ #define IDE_SUBDRIVER_VERSION 1
+-typedef int           (ide_cleanup_proc)(ide_drive_t *);
+-typedef ide_startstop_t       (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
+-typedef void          (ide_end_request_proc)(byte, ide_hwgroup_t *);
+-typedef int           (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+-typedef int           (ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
+-typedef void          (ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
+-typedef int           (ide_check_media_change_proc)(ide_drive_t *);
+-typedef void          (ide_revalidate_proc)(ide_drive_t *);
+-typedef void          (ide_pre_reset_proc)(ide_drive_t *);
+-typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
+-typedef ide_startstop_t       (ide_special_proc)(ide_drive_t *);
+-typedef void          (ide_setting_proc)(ide_drive_t *);
+-typedef int           (ide_driver_reinit_proc)(ide_drive_t *);
+-
+ typedef struct ide_driver_s {
+       const char                      *name;
+       const char                      *version;
+@@ -656,22 +852,31 @@
+       unsigned busy                   : 1;
+       unsigned supports_dma           : 1;
+       unsigned supports_dsc_overlap   : 1;
+-      ide_cleanup_proc                *cleanup;
+-      ide_do_request_proc             *do_request;
+-      ide_end_request_proc            *end_request;
+-      ide_ioctl_proc                  *ioctl;
+-      ide_open_proc                   *open;
+-      ide_release_proc                *release;
+-      ide_check_media_change_proc     *media_change;
+-      ide_revalidate_proc             *revalidate;
+-      ide_pre_reset_proc              *pre_reset;
+-      ide_capacity_proc               *capacity;
+-      ide_special_proc                *special;
+-      ide_proc_entry_t                *proc;
+-      ide_driver_reinit_proc          *driver_reinit;
++      int             (*cleanup)(ide_drive_t *);
++      int             (*standby)(ide_drive_t *);
++      int             (*suspend)(ide_drive_t *);
++      int             (*resume)(ide_drive_t *);
++      int             (*flushcache)(ide_drive_t *);
++      ide_startstop_t (*do_request)(ide_drive_t *, struct request *, unsigned long);
++      int             (*end_request)(ide_drive_t *, int);
++      byte            (*sense)(ide_drive_t *, const char *, byte);
++      ide_startstop_t (*error)(ide_drive_t *, const char *, byte);
++      int             (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
++      int             (*open)(struct inode *, struct file *, ide_drive_t *);
++      void            (*release)(struct inode *, struct file *, ide_drive_t *);
++      int             (*media_change)(ide_drive_t *);
++      void            (*revalidate)(ide_drive_t *);
++      void            (*pre_reset)(ide_drive_t *);
++      unsigned long   (*capacity)(ide_drive_t *);
++      ide_startstop_t (*special)(ide_drive_t *);
++      ide_proc_entry_t        *proc;
++      int             (*init)(void);
++      int             (*reinit)(ide_drive_t *);
++      void            (*ata_prebuilder)(ide_drive_t *);
++      void            (*atapi_prebuilder)(ide_drive_t *);
+ } ide_driver_t;
+-#define DRIVER(drive)         ((ide_driver_t *)((drive)->driver))
++#define DRIVER(drive)         ((drive)->driver)
+ /*
+  * IDE modules.
+@@ -711,21 +916,7 @@
+ #define LOCAL_END_REQUEST     /* Don't generate end_request in blk.h */
+ #include <linux/blk.h>
+-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
+-
+-/*
+- * This is used for (nearly) all data transfers from/to the IDE interface
+- * FIXME for 2.5, to a pointer pass verses memcpy........
+- */
+-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+-
+-/*
+- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
+- * FIXME for 2.5, to a pointer pass verses memcpy........
+- */
+-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
++int ide_end_request (ide_drive_t *drive, int uptodate);
+ /*
+  * This is used on exit from the driver, to designate the next irq handler
+@@ -748,7 +939,7 @@
+  * Issue a simple drive command
+  * The drive must be selected beforehand.
+  */
+-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
++void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+ /*
+  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+@@ -768,8 +959,6 @@
+  */
+ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+-int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+-
+ /*
+  * This routine is called from the partition-table code in genhd.c
+  * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
+@@ -796,7 +985,7 @@
+  * Re-Start an operation for an IDE interface.
+  * The caller should return immediately after invoking this.
+  */
+-ide_startstop_t restart_request (ide_drive_t *);
++int restart_request (ide_drive_t *, struct request *);
+ /*
+  * This function is intended to be used prior to invoking ide_do_drive_cmd().
+@@ -843,24 +1032,100 @@
+ /*
+  * Clean up after success/failure of an explicit drive cmd.
+  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
++ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
+  */
+ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+ /*
+- * Issue ATA command and wait for completion.
++ * Issue ATA command and wait for completion. use for implementing commands in kernel
+  */
+ int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
++
+ int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
++ 
++typedef struct ide_task_s {
++      task_ioreg_t            tfRegister[8];
++      task_ioreg_t            hobRegister[8];
++      ide_reg_valid_t         tf_out_flags;
++      ide_reg_valid_t         tf_in_flags;
++      int                     data_phase;
++      int                     command_type;
++      ide_pre_handler_t       *prehandler;
++      ide_handler_t           *handler;
++      ide_post_handler_t      *posthandler;
++      struct request          *rq;            /* copy of request */
++      void                    *special;       /* valid_t generally */
++} ide_task_t;
++
++typedef struct pkt_task_s {
++      task_ioreg_t            tfRegister[8];
++      int                     data_phase;
++      int                     command_type;
++      ide_handler_t           *handler;
++      struct request          *rq;            /* copy of request */
++      void                    *special;
++} pkt_task_t;
++
++void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
++void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
++void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
++void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
++void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
++void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
++
++int drive_is_ready (ide_drive_t *drive);
++int wait_for_ready (ide_drive_t *drive, int timeout);
++
++/*
++ * taskfile io for disks for now...and builds request from ide_ioctl
++ */
++ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
++
++void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err);
++
++/*
++ * Special Flagged Register Validation Caller
++ */
++ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
++
++ide_startstop_t set_multmode_intr (ide_drive_t *drive);
++ide_startstop_t set_geometry_intr (ide_drive_t *drive);
++ide_startstop_t recal_intr (ide_drive_t *drive);
++ide_startstop_t task_no_data_intr (ide_drive_t *drive);
++ide_startstop_t task_in_intr (ide_drive_t *drive);
++ide_startstop_t task_mulin_intr (ide_drive_t *drive);
++ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
++ide_startstop_t task_out_intr (ide_drive_t *drive);
++ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq);
++ide_startstop_t task_mulout_intr (ide_drive_t *drive);
++void ide_init_drive_taskfile (struct request *rq);
++
++int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
++
++ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
++ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
++ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
++/* Expects args is a full set of TF registers and parses the command type */
++int ide_cmd_type_parser (ide_task_t *args);
++
++int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
++int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
++int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
++
++#ifdef CONFIG_PKT_TASK_IOCTL
++int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
++#endif /* CONFIG_PKT_TASK_IOCTL */
+ void ide_delay_50ms (void);
+ int system_bus_clock(void);
+ byte ide_auto_reduce_xfer (ide_drive_t *drive);
+ int ide_driveid_update (ide_drive_t *drive);
+-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
++int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
+ int ide_config_drive_speed (ide_drive_t *drive, byte speed);
+ byte eighty_ninty_three (ide_drive_t *drive);
+-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
++int set_transfer (ide_drive_t *drive, ide_task_t *args);
++int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf);
+ /*
+  * ide_system_bus_speed() returns what we think is the system VESA/PCI
+@@ -871,12 +1136,6 @@
+ int ide_system_bus_speed (void);
+ /*
+- * ide_multwrite() transfers a block of up to mcount sectors of data
+- * to a drive as part of a disk multwrite operation.
+- */
+-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+-
+-/*
+  * ide_stall_queue() can be used by a drive to give excess bandwidth back
+  * to the hwgroup by sleeping for timeout jiffies.
+  */
+@@ -905,23 +1164,30 @@
+ extern ide_proc_entry_t generic_subdriver_entries[];
+ #endif
++int ide_reinit_drive (ide_drive_t *drive);
++
+ #ifdef _IDE_C
+ #ifdef CONFIG_BLK_DEV_IDE
+ int ideprobe_init (void);
+ #endif /* CONFIG_BLK_DEV_IDE */
+ #ifdef CONFIG_BLK_DEV_IDEDISK
++int idedisk_reinit (ide_drive_t *drive);
+ int idedisk_init (void);
+ #endif /* CONFIG_BLK_DEV_IDEDISK */
+ #ifdef CONFIG_BLK_DEV_IDECD
++int ide_cdrom_reinit (ide_drive_t *drive);
+ int ide_cdrom_init (void);
+ #endif /* CONFIG_BLK_DEV_IDECD */
+ #ifdef CONFIG_BLK_DEV_IDETAPE
++int idetape_reinit (ide_drive_t *drive);
+ int idetape_init (void);
+ #endif /* CONFIG_BLK_DEV_IDETAPE */
+ #ifdef CONFIG_BLK_DEV_IDEFLOPPY
++int idefloppy_reinit (ide_drive_t *drive);
+ int idefloppy_init (void);
+ #endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+ #ifdef CONFIG_BLK_DEV_IDESCSI
++int idescsi_reinit (ide_drive_t *drive);
+ int idescsi_init (void);
+ #endif /* CONFIG_BLK_DEV_IDESCSI */
+ #endif /* _IDE_C */
+@@ -942,6 +1208,56 @@
+ #  define OFF_BOARD           NEVER_BOARD
+ #endif /* CONFIG_BLK_DEV_OFFBOARD */
++
++typedef struct ide_pci_enablebit_s {
++      byte    reg;    /* byte pci reg holding the enable-bit */
++      byte    mask;   /* mask to isolate the enable-bit */
++      byte    val;    /* value of masked reg when "enabled" */
++} ide_pci_enablebit_t;
++
++typedef struct ide_pci_device_s {
++      ide_pci_devid_t         devid;
++      char                    *name;
++      void                    (*fixup_device)(struct pci_dev *, struct ide_pci_device_s *);
++      unsigned int            (*init_chipset)(struct pci_dev *, const char *);
++      unsigned int            (*ata66_check)(ide_hwif_t *);
++      void                    (*init_hwif)(ide_hwif_t *);
++      void                    (*dma_init)(ide_hwif_t *, unsigned long);
++      ide_pci_enablebit_t     enablebits[2];
++      byte                    bootable;
++      unsigned int            extra;
++} ide_pci_device_t;
++
++#ifdef LINUX_PCI_H
++extern inline void ide_register_xp_fix(struct pci_dev *dev)
++{
++      int i;
++      unsigned short cmd;
++      unsigned long flags;
++      unsigned long base_address[4] = { 0x1f0, 0x3f4, 0x170, 0x374 };
++
++      local_irq_save(flags);
++      pci_read_config_word(dev, PCI_COMMAND, &cmd);
++      pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
++      for (i=0; i<4; i++) {
++              dev->resource[i].start = 0;
++              dev->resource[i].end = 0;
++              dev->resource[i].flags = 0;
++      }
++      for (i=0; i<4; i++) {
++              dev->resource[i].start = base_address[i];
++              dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
++              pci_write_config_dword(dev,
++                      (PCI_BASE_ADDRESS_0 + (i * 4)),
++                      dev->resource[i].start);
++      }
++      pci_write_config_word(dev, PCI_COMMAND, cmd);
++      local_irq_restore(flags);
++}
++
++void ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) __init;
++#endif /* LINUX_PCI_H */
++
+ unsigned long ide_find_free_region (unsigned short size) __init;
+ void ide_scan_pcibus (int scan_direction) __init;
+ #endif
+@@ -957,8 +1273,11 @@
+ int ide_release_dma (ide_hwif_t *hwif);
+ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
+ unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
+-#endif
++#endif /* CONFIG_BLK_DEV_IDEPCI */
+ void hwif_unregister (ide_hwif_t *hwif);
++void export_ide_init_queue (ide_drive_t *drive);
++byte export_probe_for_drive (ide_drive_t *drive);
++
+ #endif /* _IDE_H */
+--- linux.org/include/linux/hdreg.h    Thu Nov 22 20:46:18 2001
++++ linux-2.4.19-rc1-ac7/include/linux/hdreg.h Thu Jul 18 14:24:44 2002
+@@ -6,106 +6,315 @@
+  * Various sources.  
+  */
+-#define HD_IRQ 14             /* the standard disk interrupt */
++#define HD_IRQ 14                     /* the standard disk interrupt */
+ /* ide.c has its own port definitions in "ide.h" */
+ /* Hd controller regs. Ref: IBM AT Bios-listing */
+-#define HD_DATA               0x1f0   /* _CTL when writing */
+-#define HD_ERROR      0x1f1   /* see err-bits */
+-#define HD_NSECTOR    0x1f2   /* nr of sectors to read/write */
+-#define HD_SECTOR     0x1f3   /* starting sector */
+-#define HD_LCYL               0x1f4   /* starting cylinder */
+-#define HD_HCYL               0x1f5   /* high byte of starting cyl */
+-#define HD_CURRENT    0x1f6   /* 101dhhhh , d=drive, hhhh=head */
+-#define HD_STATUS     0x1f7   /* see status-bits */
+-#define HD_FEATURE HD_ERROR   /* same io address, read=error, write=feature */
+-#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+-#define HD_COMMAND HD_STATUS  /* same io address, read=status, write=cmd */
++#define HD_DATA               0x1f0           /* _CTL when writing */
++#define HD_ERROR      0x1f1           /* see err-bits */
++#define HD_NSECTOR    0x1f2           /* nr of sectors to read/write */
++#define HD_SECTOR     0x1f3           /* starting sector */
++#define HD_LCYL               0x1f4           /* starting cylinder */
++#define HD_HCYL               0x1f5           /* high byte of starting cyl */
++#define HD_CURRENT    0x1f6           /* 101dhhhh , d=drive, hhhh=head */
++#define HD_STATUS     0x1f7           /* see status-bits */
++#define HD_FEATURE    HD_ERROR        /* same io address, read=error, write=feature */
++#define HD_PRECOMP    HD_FEATURE      /* obsolete use of this port - predates IDE */
++#define HD_COMMAND    HD_STATUS       /* same io address, read=status, write=cmd */
+-#define HD_CMD                0x3f6   /* used for resets */
+-#define HD_ALTSTATUS  0x3f6   /* same as HD_STATUS but doesn't clear irq */
++#define HD_CMD                0x3f6           /* used for resets */
++#define HD_ALTSTATUS  0x3f6           /* same as HD_STATUS but doesn't clear irq */
+ /* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
+ /* Bits of HD_STATUS */
+-#define ERR_STAT      0x01
+-#define INDEX_STAT    0x02
+-#define ECC_STAT      0x04    /* Corrected error */
+-#define DRQ_STAT      0x08
+-#define SEEK_STAT     0x10
+-#define WRERR_STAT    0x20
+-#define READY_STAT    0x40
+-#define BUSY_STAT     0x80
+-
+-/* Values for HD_COMMAND */
+-#define WIN_RESTORE           0x10
+-#define WIN_READ              0x20
+-#define WIN_WRITE             0x30
+-#define WIN_WRITE_VERIFY      0x3C
+-#define WIN_VERIFY            0x40
+-#define WIN_FORMAT            0x50
+-#define WIN_INIT              0x60
+-#define WIN_SEEK              0x70
+-#define WIN_DIAGNOSE          0x90
+-#define WIN_SPECIFY           0x91    /* set drive geometry translation */
+-#define WIN_IDLEIMMEDIATE     0xE1    /* force drive to become "ready" */
+-#define WIN_SETIDLE1          0xE3
+-#define WIN_SETIDLE2          0x97
+-
+-#define WIN_STANDBYNOW1               0xE0
+-#define WIN_STANDBYNOW2               0x94
+-#define WIN_SLEEPNOW1         0xE6
+-#define WIN_SLEEPNOW2         0x99
+-#define WIN_CHECKPOWERMODE1   0xE5
+-#define WIN_CHECKPOWERMODE2   0x98
+-
+-#define WIN_DOORLOCK          0xDE    /* lock door on removable drives */
+-#define WIN_DOORUNLOCK                0xDF    /* unlock door on removable drives */
+-
+-#define WIN_MULTREAD          0xC4    /* read sectors using multiple mode */
+-#define WIN_MULTWRITE         0xC5    /* write sectors using multiple mode */
+-#define WIN_SETMULT           0xC6    /* enable/disable multiple mode */
+-#define WIN_IDENTIFY          0xEC    /* ask drive to identify itself */
+-#define WIN_IDENTIFY_DMA      0xEE    /* same as WIN_IDENTIFY, but DMA */
+-#define WIN_SETFEATURES               0xEF    /* set special drive features */
+-#define WIN_READDMA           0xC8    /* read sectors using DMA transfers */
+-#define WIN_WRITEDMA          0xCA    /* write sectors using DMA transfers */
+-
+-#define WIN_QUEUED_SERVICE    0xA2    /* */
+-#define WIN_READDMA_QUEUED    0xC7    /* read sectors using Queued DMA transfers */
+-#define WIN_WRITEDMA_QUEUED   0xCC    /* write sectors using Queued DMA transfers */
+-
+-#define WIN_READ_BUFFER               0xE4    /* force read only 1 sector */
+-#define WIN_WRITE_BUFFER      0xE8    /* force write only 1 sector */
+-
+-#define WIN_SMART             0xB0    /* self-monitoring and reporting */
+-
+-/* Additional drive command codes used by ATAPI devices. */
+-#define WIN_PIDENTIFY         0xA1    /* identify ATAPI device        */
+-#define WIN_SRST              0x08    /* ATAPI soft reset command */
+-#define WIN_PACKETCMD         0xA0    /* Send a packet command. */
++#define ERR_STAT              0x01
++#define INDEX_STAT            0x02
++#define ECC_STAT              0x04    /* Corrected error */
++#define DRQ_STAT              0x08
++#define SEEK_STAT             0x10
++#define WRERR_STAT            0x20
++#define READY_STAT            0x40
++#define BUSY_STAT             0x80
+-#define DISABLE_SEAGATE               0xFB
+-#define EXABYTE_ENABLE_NEST   0xF0
++/* Bits for HD_ERROR */
++#define MARK_ERR              0x01    /* Bad address mark */
++#define TRK0_ERR              0x02    /* couldn't find track 0 */
++#define ABRT_ERR              0x04    /* Command aborted */
++#define MCR_ERR                       0x08    /* media change request */
++#define ID_ERR                        0x10    /* ID field not found */
++#define MC_ERR                        0x20    /* media changed */
++#define ECC_ERR                       0x40    /* Uncorrectable ECC error */
++#define BBD_ERR                       0x80    /* pre-EIDE meaning:  block marked bad */
++#define ICRC_ERR              0x80    /* new meaning:  CRC error during transfer */
+-/* WIN_SMART sub-commands */
++/*
++ * Command Header sizes for IOCTL commands
++ *    HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
++ */
+-#define SMART_READ_VALUES     0xd0
+-#define SMART_READ_THRESHOLDS 0xd1
+-#define SMART_AUTOSAVE                0xd2
+-#define SMART_SAVE            0xd3
+-#define SMART_IMMEDIATE_OFFLINE       0xd4
+-#define SMART_READ_LOG_SECTOR 0xd5
+-#define SMART_WRITE_LOG_SECTOR        0xd6
+-#define SMART_WRITE_THRESHOLDS        0xd7
+-#define SMART_ENABLE          0xd8
+-#define SMART_DISABLE         0xd9
+-#define SMART_STATUS          0xda
+-#define SMART_AUTO_OFFLINE    0xdb
++#if 0
++#include <asm/hdreg.h>
++typedef ide_ioreg_t task_ioreg_t;
++#else
++typedef unsigned char task_ioreg_t;
++#endif
++
++#define HDIO_DRIVE_CMD_HDR_SIZE               4*sizeof(task_ioreg_t)
++#define HDIO_DRIVE_TASK_HDR_SIZE      8*sizeof(task_ioreg_t)
++#define HDIO_DRIVE_HOB_HDR_SIZE               8*sizeof(task_ioreg_t)
++
++#define IDE_DRIVE_TASK_INVALID                -1
++#define IDE_DRIVE_TASK_NO_DATA                0
++#define IDE_DRIVE_TASK_SET_XFER               1
++
++#define IDE_DRIVE_TASK_IN             2
++
++#define IDE_DRIVE_TASK_OUT            3
++#define IDE_DRIVE_TASK_RAW_WRITE      4
++
++struct hd_drive_cmd_hdr {
++      task_ioreg_t command;
++      task_ioreg_t sector_number;
++      task_ioreg_t feature;
++      task_ioreg_t sector_count;
++};
+-/* WIN_SETFEATURES sub-commands */
++typedef struct hd_drive_task_hdr {
++      task_ioreg_t data;
++      task_ioreg_t feature;
++      task_ioreg_t sector_count;
++      task_ioreg_t sector_number;
++      task_ioreg_t low_cylinder;
++      task_ioreg_t high_cylinder;
++      task_ioreg_t device_head;
++      task_ioreg_t command;
++} task_struct_t;
++
++typedef struct hd_drive_hob_hdr {
++      task_ioreg_t data;
++      task_ioreg_t feature;
++      task_ioreg_t sector_count;
++      task_ioreg_t sector_number;
++      task_ioreg_t low_cylinder;
++      task_ioreg_t high_cylinder;
++      task_ioreg_t device_head;
++      task_ioreg_t control;
++} hob_struct_t;
++
++typedef union ide_reg_valid_s {
++      unsigned all                            : 16;
++      struct {
++              unsigned data                   : 1;
++              unsigned error_feature          : 1;
++              unsigned sector                 : 1;
++              unsigned nsector                : 1;
++              unsigned lcyl                   : 1;
++              unsigned hcyl                   : 1;
++              unsigned select                 : 1;
++              unsigned status_command         : 1;
++
++              unsigned data_hob               : 1;
++              unsigned error_feature_hob      : 1;
++              unsigned sector_hob             : 1;
++              unsigned nsector_hob            : 1;
++              unsigned lcyl_hob               : 1;
++              unsigned hcyl_hob               : 1;
++              unsigned select_hob             : 1;
++              unsigned control_hob            : 1;
++      } b;
++} ide_reg_valid_t;
++
++/*
++ * Define standard taskfile in/out register
++ */
++#define IDE_TASKFILE_STD_OUT_FLAGS    0xFE
++#define IDE_TASKFILE_STD_IN_FLAGS     0xFE
++#define IDE_HOB_STD_OUT_FLAGS         0x3C     /* sector, nsector lcyl and hcyl */
++#define IDE_HOB_STD_IN_FLAGS          0x3C
++
++typedef struct ide_task_request_s {
++      task_ioreg_t    io_ports[8];
++      task_ioreg_t    hob_ports[8];
++      ide_reg_valid_t out_flags;
++      ide_reg_valid_t in_flags;
++      int             data_phase;
++      int             req_cmd;
++      unsigned long   out_size;
++      unsigned long   in_size;
++} ide_task_request_t;
++
++typedef struct ide_ioctl_request_s {
++      ide_task_request_t      *task_request;
++      unsigned char           *out_buffer;
++      unsigned char           *in_buffer;
++} ide_ioctl_request_t;
++
++#define TASKFILE_INVALID              0x7fff
++#define TASKFILE_48                   0x8000
++
++#define TASKFILE_NO_DATA              0x0000
++
++#define TASKFILE_IN                   0x0001
++#define TASKFILE_MULTI_IN             0x0002
++
++#define TASKFILE_OUT                  0x0004
++#define TASKFILE_MULTI_OUT            0x0008
++#define TASKFILE_IN_OUT                       0x0010
++
++#define TASKFILE_IN_DMA                       0x0020
++#define TASKFILE_OUT_DMA              0x0040
++#define TASKFILE_IN_DMAQ              0x0080
++#define TASKFILE_OUT_DMAQ             0x0100
++
++#define TASKFILE_P_IN                 0x0200
++#define TASKFILE_P_OUT                        0x0400
++#define TASKFILE_P_IN_DMA             0x0800
++#define TASKFILE_P_OUT_DMA            0x1000
++#define TASKFILE_P_IN_DMAQ            0x2000
++#define TASKFILE_P_OUT_DMAQ           0x4000
++
++/* ATA/ATAPI Commands pre T13 Spec */
++#define WIN_NOP                               0x00
++/*
++ *    0x01->0x02 Reserved
++ */
++#define CFA_REQ_EXT_ERROR_CODE                0x03 /* CFA Request Extended Error Code */
++/*
++ *    0x04->0x07 Reserved
++ */
++#define WIN_SRST                      0x08 /* ATAPI soft reset command */
++#define WIN_DEVICE_RESET              0x08
++/*
++ *    0x09->0x0F Reserved
++ */
++#define WIN_RECAL                     0x10
++/*
++ *    0x10->0x1F Reserved
++ */
++#define WIN_RESTORE                   WIN_RECAL
++#define WIN_READ                      0x20 /* 28-Bit */
++#define WIN_READ_ONCE                 0x21 /* 28-Bit without retries */
++#define WIN_READ_LONG                 0x22 /* 28-Bit */
++#define WIN_READ_LONG_ONCE            0x23 /* 28-Bit without retries */
++#define WIN_READ_EXT                  0x24 /* 48-Bit */
++#define WIN_READDMA_EXT                       0x25 /* 48-Bit */
++#define WIN_READDMA_QUEUED_EXT                0x26 /* 48-Bit */
++#define WIN_READ_NATIVE_MAX_EXT               0x27 /* 48-Bit */
++#define WIN_MULTREAD_EXT              0x29 /* 48-Bit */
++/*
++ *    0x2A->0x2F Reserved
++ */
++#define WIN_WRITE                     0x30 /* 28-Bit */
++#define WIN_WRITE_ONCE                        0x31 /* 28-Bit without retries */
++#define WIN_WRITE_LONG                        0x32 /* 28-Bit */
++#define WIN_WRITE_LONG_ONCE           0x33 /* 28-Bit without retries */
++#define WIN_WRITE_EXT                 0x34 /* 48-Bit */
++#define WIN_WRITEDMA_EXT              0x35 /* 48-Bit */
++#define WIN_WRITEDMA_QUEUED_EXT               0x36 /* 48-Bit */
++#define WIN_SET_MAX_EXT                       0x37 /* 48-Bit */
++#define CFA_WRITE_SECT_WO_ERASE               0x38 /* CFA Write Sectors without erase */
++#define WIN_MULTWRITE_EXT             0x39 /* 48-Bit */
++/*
++ *    0x3A->0x3B Reserved
++ */
++#define WIN_WRITE_VERIFY              0x3C /* 28-Bit */
++/*
++ *    0x3D->0x3F Reserved
++ */
++#define WIN_VERIFY                    0x40 /* 28-Bit - Read Verify Sectors */
++#define WIN_VERIFY_ONCE                       0x41 /* 28-Bit - without retries */
++#define WIN_VERIFY_EXT                        0x42 /* 48-Bit */
++/*
++ *    0x43->0x4F Reserved
++ */
++#define WIN_FORMAT                    0x50
++/*
++ *    0x51->0x5F Reserved
++ */
++#define WIN_INIT                      0x60
++/*
++ *    0x61->0x5F Reserved
++ */
++#define WIN_SEEK                      0x70 /* 0x70-0x7F Reserved */
++#define CFA_TRANSLATE_SECTOR          0x87 /* CFA Translate Sector */
++#define WIN_DIAGNOSE                  0x90
++#define WIN_SPECIFY                   0x91 /* set drive geometry translation */
++#define WIN_DOWNLOAD_MICROCODE                0x92
++#define WIN_STANDBYNOW2                       0x94
++#define WIN_SETIDLE2                  0x97
++#define WIN_CHECKPOWERMODE2           0x98
++#define WIN_SLEEPNOW2                 0x99
++/*
++ *    0x9A VENDOR
++ */
++#define WIN_PACKETCMD                 0xA0 /* Send a packet command. */
++#define WIN_PIDENTIFY                 0xA1 /* identify ATAPI device   */
++#define WIN_QUEUED_SERVICE            0xA2
++#define WIN_SMART                     0xB0 /* self-monitoring and reporting */
++#define CFA_ERASE_SECTORS             0xC0
++#define WIN_MULTREAD                  0xC4 /* read sectors using multiple mode*/
++#define WIN_MULTWRITE                 0xC5 /* write sectors using multiple mode */
++#define WIN_SETMULT                   0xC6 /* enable/disable multiple mode */
++#define WIN_READDMA_QUEUED            0xC7 /* read sectors using Queued DMA transfers */
++#define WIN_READDMA                   0xC8 /* read sectors using DMA transfers */
++#define WIN_READDMA_ONCE              0xC9 /* 28-Bit - without retries */
++#define WIN_WRITEDMA                  0xCA /* write sectors using DMA transfers */
++#define WIN_WRITEDMA_ONCE             0xCB /* 28-Bit - without retries */
++#define WIN_WRITEDMA_QUEUED           0xCC /* write sectors using Queued DMA transfers */
++#define CFA_WRITE_MULTI_WO_ERASE      0xCD /* CFA Write multiple without erase */
++#define WIN_GETMEDIASTATUS            0xDA    
++#define WIN_DOORLOCK                  0xDE /* lock door on removable drives */
++#define WIN_DOORUNLOCK                        0xDF /* unlock door on removable drives */
++#define WIN_STANDBYNOW1                       0xE0
++#define WIN_IDLEIMMEDIATE             0xE1 /* force drive to become "ready" */
++#define WIN_STANDBY                   0xE2 /* Set device in Standby Mode */
++#define WIN_SETIDLE1                  0xE3
++#define WIN_READ_BUFFER                       0xE4 /* force read only 1 sector */
++#define WIN_CHECKPOWERMODE1           0xE5
++#define WIN_SLEEPNOW1                 0xE6
++#define WIN_FLUSH_CACHE                       0xE7
++#define WIN_WRITE_BUFFER              0xE8 /* force write only 1 sector */
++#define WIN_WRITE_SAME                        0xE9 /* read ata-2 to use */
++#define WIN_FLUSH_CACHE_EXT           0xEA /* 48-Bit */
++#define WIN_IDENTIFY                  0xEC /* ask drive to identify itself    */
++#define WIN_MEDIAEJECT                        0xED
++#define WIN_IDENTIFY_DMA              0xEE /* same as WIN_IDENTIFY, but DMA */
++#define WIN_SETFEATURES                       0xEF /* set special drive features */
++#define EXABYTE_ENABLE_NEST           0xF0
++#define WIN_SECURITY_SET_PASS         0xF1
++#define WIN_SECURITY_UNLOCK           0xF2
++#define WIN_SECURITY_ERASE_PREPARE    0xF3
++#define WIN_SECURITY_ERASE_UNIT               0xF4
++#define WIN_SECURITY_FREEZE_LOCK      0xF5
++#define WIN_SECURITY_DISABLE          0xF6
++#define WIN_READ_NATIVE_MAX           0xF8 /* return the native maximum address */
++#define WIN_SET_MAX                   0xF9
++#define DISABLE_SEAGATE                       0xFB
++/* WIN_SMART sub-commands */
++
++#define SMART_READ_VALUES             0xD0
++#define SMART_READ_THRESHOLDS         0xD1
++#define SMART_AUTOSAVE                        0xD2
++#define SMART_SAVE                    0xD3
++#define SMART_IMMEDIATE_OFFLINE               0xD4
++#define SMART_READ_LOG_SECTOR         0xD5
++#define SMART_WRITE_LOG_SECTOR                0xD6
++#define SMART_WRITE_THRESHOLDS                0xD7
++#define SMART_ENABLE                  0xD8
++#define SMART_DISABLE                 0xD9
++#define SMART_STATUS                  0xDA
++#define SMART_AUTO_OFFLINE            0xDB
++
++/* Password used in TF4 & TF5 executing SMART commands */
++
++#define SMART_LCYL_PASS                       0x4F
++#define SMART_HCYL_PASS                       0xC2
++              
++/* WIN_SETFEATURES sub-commands */
++#define SETFEATURES_EN_8BIT   0x01    /* Enable 8-Bit Transfers */
+ #define SETFEATURES_EN_WCACHE 0x02    /* Enable write cache */
+ #define SETFEATURES_XFER      0x03    /* Set transfer mode */
+ #     define XFER_UDMA_7      0x47    /* 0100|0111 */
+@@ -131,39 +340,38 @@
+ #define SETFEATURES_DIS_DEFECT        0x04    /* Disable Defect Management */
+ #define SETFEATURES_EN_APM    0x05    /* Enable advanced power management */
+ #define SETFEATURES_DIS_MSN   0x31    /* Disable Media Status Notification */
++#define SETFEATURES_DIS_RETRY 0x33    /* Disable Retry */
++#define SETFEATURES_EN_AAM    0x42    /* Enable Automatic Acoustic Management */
++#define SETFEATURES_RW_LONG   0x44    /* Set Lenght of VS bytes */
++#define SETFEATURES_SET_CACHE 0x54    /* Set Cache segments to SC Reg. Val */
+ #define SETFEATURES_DIS_RLA   0x55    /* Disable read look-ahead feature */
+ #define SETFEATURES_EN_RI     0x5D    /* Enable release interrupt */
+ #define SETFEATURES_EN_SI     0x5E    /* Enable SERVICE interrupt */
+ #define SETFEATURES_DIS_RPOD  0x66    /* Disable reverting to power on defaults */
++#define SETFEATURES_DIS_ECC   0x77    /* Disable ECC byte count */
++#define SETFEATURES_DIS_8BIT  0x81    /* Disable 8-Bit Transfers */
+ #define SETFEATURES_DIS_WCACHE        0x82    /* Disable write cache */
+ #define SETFEATURES_EN_DEFECT 0x84    /* Enable Defect Management */
+ #define SETFEATURES_DIS_APM   0x85    /* Disable advanced power management */
++#define SETFEATURES_EN_ECC    0x88    /* Enable ECC byte count */
+ #define SETFEATURES_EN_MSN    0x95    /* Enable Media Status Notification */
++#define SETFEATURES_EN_RETRY  0x99    /* Enable Retry */
+ #define SETFEATURES_EN_RLA    0xAA    /* Enable read look-ahead feature */
+ #define SETFEATURES_PREFETCH  0xAB    /* Sets drive prefetch value */
++#define SETFEATURES_4B_RW_LONG        0xBB    /* Set Lenght of 4 bytes */
++#define SETFEATURES_DIS_AAM   0xC2    /* Disable Automatic Acoustic Management */
+ #define SETFEATURES_EN_RPOD   0xCC    /* Enable reverting to power on defaults */
+ #define SETFEATURES_DIS_RI    0xDD    /* Disable release interrupt */
+ #define SETFEATURES_DIS_SI    0xDE    /* Disable SERVICE interrupt */
+ /* WIN_SECURITY sub-commands */
+-#define SECURITY_SET_PASSWORD         0xBA    /* 0xF1 */
+-#define SECURITY_UNLOCK                       0xBB    /* 0xF2 */
+-#define SECURITY_ERASE_PREPARE                0xBC    /* 0xF3 */
+-#define SECURITY_ERASE_UNIT           0xBD    /* 0xF4 */
+-#define SECURITY_FREEZE_LOCK          0xBE    /* 0xF5 */
+-#define SECURITY_DISABLE_PASSWORD     0xBF    /* 0xF6 */
+-
+-/* Bits for HD_ERROR */
+-#define MARK_ERR      0x01    /* Bad address mark */
+-#define TRK0_ERR      0x02    /* couldn't find track 0 */
+-#define ABRT_ERR      0x04    /* Command aborted */
+-#define MCR_ERR               0x08    /* media change request */
+-#define ID_ERR                0x10    /* ID field not found */
+-#define MC_ERR                0x20    /* media changed */
+-#define ECC_ERR               0x40    /* Uncorrectable ECC error */
+-#define       BBD_ERR         0x80    /* pre-EIDE meaning:  block marked bad */
+-#define       ICRC_ERR        0x80    /* new meaning:  CRC error during transfer */
++#define SECURITY_SET_PASSWORD         0xBA
++#define SECURITY_UNLOCK                       0xBB
++#define SECURITY_ERASE_PREPARE                0xBC
++#define SECURITY_ERASE_UNIT           0xBD
++#define SECURITY_FREEZE_LOCK          0xBE
++#define SECURITY_DISABLE_PASSWORD     0xBF
+ struct hd_geometry {
+       unsigned char heads;
+@@ -172,6 +380,14 @@
+       unsigned long start;
+ };
++/* BIG GEOMETRY */
++struct hd_big_geometry {
++      unsigned char heads;
++      unsigned char sectors;
++      unsigned int cylinders;
++      unsigned long start;
++};
++
+ /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
+ #define HDIO_GETGEO           0x0301  /* get device geometry */
+ #define HDIO_GET_UNMASKINTR   0x0302  /* get current unmask setting */
+@@ -186,9 +402,10 @@
+ #define HDIO_GET_IDENTITY     0x030d  /* get IDE identification info */
+ #define HDIO_GET_WCACHE               0x030e  /* get write cache mode on|off */
+ #define HDIO_GET_ACOUSTIC     0x030f  /* get acoustic value */
++#define       HDIO_GET_ADDRESS        0x0310  /* */
+ #define HDIO_GET_BUSSTATE     0x031a  /* get the bus state of the hwif */
+-#define HDIO_TRISTATE_HWIF    0x031b  /* OBSOLETE - use SET_BUSSTATE */
++#define HDIO_TRISTATE_HWIF    0x031b  /* execute a channel tristate */
+ #define HDIO_DRIVE_RESET      0x031c  /* execute a device reset */
+ #define HDIO_DRIVE_TASKFILE   0x031d  /* execute raw taskfile */
+ #define HDIO_DRIVE_TASK               0x031e  /* execute task and special drive command */
+@@ -211,6 +428,7 @@
+ #define HDIO_SET_ACOUSTIC     0x032c  /* change acoustic behavior */
+ #define HDIO_SET_BUSSTATE     0x032d  /* set the bus state of the hwif */
+ #define HDIO_SET_QDMA         0x032e  /* change use-qdma flag */
++#define HDIO_SET_ADDRESS      0x032f  /* change lba addressing modes */
+ /* bus states */
+ enum {
+@@ -219,34 +437,30 @@
+       BUSSTATE_TRISTATE
+ };
+-/* BIG GEOMETRY */
+-struct hd_big_geometry {
+-      unsigned char heads;
+-      unsigned char sectors;
+-      unsigned int cylinders;
+-      unsigned long start;
+-};
+-
+ /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
+ #define HDIO_GETGEO_BIG               0x0330  /* */
+ #define HDIO_GETGEO_BIG_RAW   0x0331  /* */
+ #define __NEW_HD_DRIVE_ID
+-/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
++/* structure returned by HDIO_GET_IDENTITY,
++ * as per ANSI NCITS ATA6 rev.1b spec
++ */
+ struct hd_driveid {
+       unsigned short  config;         /* lots of obsolete bit flags */
+-      unsigned short  cyls;           /* "physical" cyls */
++      unsigned short  cyls;           /* Obsolete, "physical" cyls */
+       unsigned short  reserved2;      /* reserved (word 2) */
+-      unsigned short  heads;          /* "physical" heads */
++      unsigned short  heads;          /* Obsolete, "physical" heads */
+       unsigned short  track_bytes;    /* unformatted bytes per track */
+       unsigned short  sector_bytes;   /* unformatted bytes per sector */
+-      unsigned short  sectors;        /* "physical" sectors per track */
++      unsigned short  sectors;        /* Obsolete, "physical" sectors per track */
+       unsigned short  vendor0;        /* vendor unique */
+       unsigned short  vendor1;        /* vendor unique */
+-      unsigned short  vendor2;        /* vendor unique */
++      unsigned short  vendor2;        /* Retired vendor unique */
+       unsigned char   serial_no[20];  /* 0 = not_specified */
+-      unsigned short  buf_type;
+-      unsigned short  buf_size;       /* 512 byte increments; 0 = not_specified */
++      unsigned short  buf_type;       /* Retired */
++      unsigned short  buf_size;       /* Retired, 512 byte increments
++                                       * 0 = not_specified
++                                       */
+       unsigned short  ecc_bytes;      /* for r/w long cmds; 0 = not_specified */
+       unsigned char   fw_rev[8];      /* 0 = not_specified */
+       unsigned char   model[40];      /* 0 = not_specified */
+@@ -254,72 +468,228 @@
+       unsigned char   vendor3;        /* vendor unique */
+       unsigned short  dword_io;       /* 0=not_implemented; 1=implemented */
+       unsigned char   vendor4;        /* vendor unique */
+-      unsigned char   capability;     /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
++      unsigned char   capability;     /* (upper byte of word 49)
++                                       *  3:  IORDYsup
++                                       *  2:  IORDYsw
++                                       *  1:  LBA
++                                       *  0:  DMA
++                                       */
+       unsigned short  reserved50;     /* reserved (word 50) */
+-      unsigned char   vendor5;        /* vendor unique */
+-      unsigned char   tPIO;           /* 0=slow, 1=medium, 2=fast */
+-      unsigned char   vendor6;        /* vendor unique */
+-      unsigned char   tDMA;           /* 0=slow, 1=medium, 2=fast */
+-      unsigned short  field_valid;    /* bits 0:cur_ok 1:eide_ok */
+-      unsigned short  cur_cyls;       /* logical cylinders */
+-      unsigned short  cur_heads;      /* logical heads */
+-      unsigned short  cur_sectors;    /* logical sectors per track */
+-      unsigned short  cur_capacity0;  /* logical total sectors on drive */
+-      unsigned short  cur_capacity1;  /*  (2 words, misaligned int)     */
++      unsigned char   vendor5;        /* Obsolete, vendor unique */
++      unsigned char   tPIO;           /* Obsolete, 0=slow, 1=medium, 2=fast */
++      unsigned char   vendor6;        /* Obsolete, vendor unique */
++      unsigned char   tDMA;           /* Obsolete, 0=slow, 1=medium, 2=fast */
++      unsigned short  field_valid;    /* (word 53)
++                                       *  2:  ultra_ok        word  88
++                                       *  1:  eide_ok         words 64-70
++                                       *  0:  cur_ok          words 54-58
++                                       */
++      unsigned short  cur_cyls;       /* Obsolete, logical cylinders */
++      unsigned short  cur_heads;      /* Obsolete, l heads */
++      unsigned short  cur_sectors;    /* Obsolete, l sectors per track */
++      unsigned short  cur_capacity0;  /* Obsolete, l total sectors on drive */
++      unsigned short  cur_capacity1;  /* Obsolete, (2 words, misaligned int)     */
+       unsigned char   multsect;       /* current multiple sector count */
+       unsigned char   multsect_valid; /* when (bit0==1) multsect is ok */
+-      unsigned int    lba_capacity;   /* total number of sectors */
+-      unsigned short  dma_1word;      /* single-word dma info */
++      unsigned int    lba_capacity;   /* Obsolete, total number of sectors */
++      unsigned short  dma_1word;      /* Obsolete, single-word dma info */
+       unsigned short  dma_mword;      /* multiple-word dma info */
+       unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
+       unsigned short  eide_dma_min;   /* min mword dma cycle time (ns) */
+       unsigned short  eide_dma_time;  /* recommended mword dma cycle time (ns) */
+       unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
+       unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
+-      unsigned short  words69_70[2];  /* reserved words 69-70 */
++      unsigned short  words69_70[2];  /* reserved words 69-70
++                                       * future command overlap and queuing
++                                       */
+       /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+-      unsigned short  words71_74[4];  /* reserved words 71-74 */
+-      unsigned short  queue_depth;    /*  */
++      unsigned short  words71_74[4];  /* reserved words 71-74
++                                       * for IDENTIFY PACKET DEVICE command
++                                       */
++      unsigned short  queue_depth;    /* (word 75)
++                                       * 15:5 reserved
++                                       *  4:0 Maximum queue depth -1
++                                       */
+       unsigned short  words76_79[4];  /* reserved words 76-79 */
+-      unsigned short  major_rev_num;  /*  */
+-      unsigned short  minor_rev_num;  /*  */
+-      unsigned short  command_set_1;  /* bits 0:Smart 1:Security 2:Removable 3:PM */
+-      unsigned short  command_set_2;  /* bits 14:Smart Enabled 13:0 zero */
+-      unsigned short  cfsse;          /* command set-feature supported extensions */
+-      unsigned short  cfs_enable_1;   /* command set-feature enabled */
+-      unsigned short  cfs_enable_2;   /* command set-feature enabled */
+-      unsigned short  csf_default;    /* command set-feature default */
+-      unsigned short  dma_ultra;      /*  */
+-      unsigned short  word89;         /* reserved (word 89) */
+-      unsigned short  word90;         /* reserved (word 90) */
++      unsigned short  major_rev_num;  /* (word 80) */
++      unsigned short  minor_rev_num;  /* (word 81) */
++      unsigned short  command_set_1;  /* (word 82) supported
++                                       * 15:  Obsolete
++                                       * 14:  NOP command
++                                       * 13:  READ_BUFFER
++                                       * 12:  WRITE_BUFFER
++                                       * 11:  Obsolete
++                                       * 10:  Host Protected Area
++                                       *  9:  DEVICE Reset
++                                       *  8:  SERVICE Interrupt
++                                       *  7:  Release Interrupt
++                                       *  6:  look-ahead
++                                       *  5:  write cache
++                                       *  4:  PACKET Command
++                                       *  3:  Power Management Feature Set
++                                       *  2:  Removable Feature Set
++                                       *  1:  Security Feature Set
++                                       *  0:  SMART Feature Set
++                                       */
++      unsigned short  command_set_2;  /* (word 83)
++                                       * 15:  Shall be ZERO
++                                       * 14:  Shall be ONE
++                                       * 13:  FLUSH CACHE EXT
++                                       * 12:  FLUSH CACHE
++                                       * 11:  Device Configuration Overlay
++                                       * 10:  48-bit Address Feature Set
++                                       *  9:  Automatic Acoustic Management
++                                       *  8:  SET MAX security
++                                       *  7:  reserved 1407DT PARTIES
++                                       *  6:  SetF sub-command Power-Up
++                                       *  5:  Power-Up in Standby Feature Set
++                                       *  4:  Removable Media Notification
++                                       *  3:  APM Feature Set
++                                       *  2:  CFA Feature Set
++                                       *  1:  READ/WRITE DMA QUEUED
++                                       *  0:  Download MicroCode
++                                       */
++      unsigned short  cfsse;          /* (word 84)
++                                       * cmd set-feature supported extensions
++                                       * 15:  Shall be ZERO
++                                       * 14:  Shall be ONE
++                                       * 13:6 reserved
++                                       *  5:  General Purpose Logging
++                                       *  4:  Streaming Feature Set
++                                       *  3:  Media Card Pass Through
++                                       *  2:  Media Serial Number Valid
++                                       *  1:  SMART selt-test supported
++                                       *  0:  SMART error logging
++                                       */
++      unsigned short  cfs_enable_1;   /* (word 85)
++                                       * command set-feature enabled
++                                       * 15:  Obsolete
++                                       * 14:  NOP command
++                                       * 13:  READ_BUFFER
++                                       * 12:  WRITE_BUFFER
++                                       * 11:  Obsolete
++                                       * 10:  Host Protected Area
++                                       *  9:  DEVICE Reset
++                                       *  8:  SERVICE Interrupt
++                                       *  7:  Release Interrupt
++                                       *  6:  look-ahead
++                                       *  5:  write cache
++                                       *  4:  PACKET Command
++                                       *  3:  Power Management Feature Set
++                                       *  2:  Removable Feature Set
++                                       *  1:  Security Feature Set
++                                       *  0:  SMART Feature Set
++                                       */
++      unsigned short  cfs_enable_2;   /* (word 86)
++                                       * command set-feature enabled
++                                       * 15:  Shall be ZERO
++                                       * 14:  Shall be ONE
++                                       * 13:  FLUSH CACHE EXT
++                                       * 12:  FLUSH CACHE
++                                       * 11:  Device Configuration Overlay
++                                       * 10:  48-bit Address Feature Set
++                                       *  9:  Automatic Acoustic Management
++                                       *  8:  SET MAX security
++                                       *  7:  reserved 1407DT PARTIES
++                                       *  6:  SetF sub-command Power-Up
++                                       *  5:  Power-Up in Standby Feature Set
++                                       *  4:  Removable Media Notification
++                                       *  3:  APM Feature Set
++                                       *  2:  CFA Feature Set
++                                       *  1:  READ/WRITE DMA QUEUED
++                                       *  0:  Download MicroCode
++                                       */
++      unsigned short  csf_default;    /* (word 87)
++                                       * command set-feature default
++                                       * 15:  Shall be ZERO
++                                       * 14:  Shall be ONE
++                                       * 13:6 reserved
++                                       *  5:  General Purpose Logging enabled
++                                       *  4:  Valid CONFIGURE STREAM executed
++                                       *  3:  Media Card Pass Through enabled
++                                       *  2:  Media Serial Number Valid
++                                       *  1:  SMART selt-test supported
++                                       *  0:  SMART error logging
++                                       */
++      unsigned short  dma_ultra;      /* (word 88) */
++      unsigned short  trseuc;         /* time required for security erase */
++      unsigned short  trsEuc;         /* time required for enhanced erase */
+       unsigned short  CurAPMvalues;   /* current APM values */
+-      unsigned short  word92;         /* reserved (word 92) */
+-      unsigned short  hw_config;      /* hardware config */
+-      unsigned short  words94_125[32];/* reserved words 94-125 */
+-      unsigned short  last_lun;       /* reserved (word 126) */
+-      unsigned short  word127;        /* reserved (word 127) */
+-      unsigned short  dlf;            /* device lock function
++      unsigned short  mprc;           /* master password revision code */
++      unsigned short  hw_config;      /* hardware config (word 93)
++                                       * 15:  Shall be ZERO
++                                       * 14:  Shall be ONE
++                                       * 13:
++                                       * 12:
++                                       * 11:
++                                       * 10:
++                                       *  9:
++                                       *  8:
++                                       *  7:
++                                       *  6:
++                                       *  5:
++                                       *  4:
++                                       *  3:
++                                       *  2:
++                                       *  1:
++                                       *  0:  Shall be ONE
++                                       */
++      unsigned short  acoustic;       /* (word 94)
++                                       * 15:8 Vendor's recommended value
++                                       *  7:0 current value
++                                       */
++      unsigned short  msrqs;          /* min stream request size */
++      unsigned short  sxfert;         /* stream transfer time */
++      unsigned short  sal;            /* stream access latency */
++      unsigned int    spg;            /* stream performance granularity */
++      unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
++      unsigned short  words104_125[22];/* reserved words 104-125 */
++      unsigned short  last_lun;       /* (word 126) */
++      unsigned short  word127;        /* (word 127) Feature Set
++                                       * Removable Media Notification
++                                       * 15:2 reserved
++                                       *  1:0 00 = not supported
++                                       *      01 = supported
++                                       *      10 = reserved
++                                       *      11 = reserved
++                                       */
++      unsigned short  dlf;            /* (word 128)
++                                       * device lock function
+                                        * 15:9 reserved
+-                                       * 8    security level 1:max 0:high
+-                                       * 7:6  reserved
+-                                       * 5    enhanced erase
+-                                       * 4    expire
+-                                       * 3    frozen
+-                                       * 2    locked
+-                                       * 1    en/disabled
+-                                       * 0    capability
++                                       *  8   security level 1:max 0:high
++                                       *  7:6 reserved
++                                       *  5   enhanced erase
++                                       *  4   expire
++                                       *  3   frozen
++                                       *  2   locked
++                                       *  1   en/disabled
++                                       *  0   capability
+                                        */
+-      unsigned short  csfo;           /* current set features options
++      unsigned short  csfo;           /*  (word 129)
++                                       * current set features options
+                                        * 15:4 reserved
+-                                       * 3    auto reassign
+-                                       * 2    reverting
+-                                       * 1    read-look-ahead
+-                                       * 0    write cache
++                                       *  3:  auto reassign
++                                       *  2:  reverting
++                                       *  1:  read-look-ahead
++                                       *  0:  write cache
+                                        */
+       unsigned short  words130_155[26];/* reserved vendor words 130-155 */
+-      unsigned short  word156;
++      unsigned short  word156;        /* reserved vendor word 156 */
+       unsigned short  words157_159[3];/* reserved vendor words 157-159 */
+-      unsigned short  words160_255[95];/* reserved words 160-255 */
++      unsigned short  cfa_power;      /* (word 160) CFA Power Mode
++                                       * 15 word 160 supported
++                                       * 14 reserved
++                                       * 13
++                                       * 12
++                                       * 11:0
++                                       */
++      unsigned short  words161_175[14];/* Reserved for CFA */
++      unsigned short  words176_205[31];/* Current Media Serial Number */
++      unsigned short  words206_254[48];/* reserved words 206-254 */
++      unsigned short  integrity_word; /* (word 255)
++                                       * 15:8 Checksum
++                                       *  7:0 Signature
++                                       */
+ };
+ /*
+--- linux.org/include/asm-i386/ide.h   Thu Nov 22 20:46:58 2001
++++ linux-2.4.19-rc1-ac7/include/asm-i386/ide.h        Thu Jul 18 14:24:43 2002
+@@ -23,8 +23,6 @@
+ # endif
+ #endif
+-#define ide__sti()    __sti()
+-
+ static __inline__ int ide_default_irq(ide_ioreg_t base)
+ {
+       switch (base) {
+@@ -86,17 +84,6 @@
+ #endif /* CONFIG_BLK_DEV_IDEPCI */
+ }
+-typedef union {
+-      unsigned all                    : 8;    /* all of the bits together */
+-      struct {
+-              unsigned head           : 4;    /* always zeros here */
+-              unsigned unit           : 1;    /* drive select number, 0 or 1 */
+-              unsigned bit5           : 1;    /* always 1 */
+-              unsigned lba            : 1;    /* using LBA instead of CHS */
+-              unsigned bit7           : 1;    /* always 1 */
+-      } b;
+-      } select_t;
+-
+ #define ide_request_irq(irq,hand,flg,dev,id)  request_irq((irq),(hand),(flg),(dev),(id))
+ #define ide_free_irq(irq,dev_id)              free_irq((irq), (dev_id))
+ #define ide_check_region(from,extent)         check_region((from), (extent))
+--- linux.org/include/linux/blkdev.h   Mon Nov 26 14:29:17 2001
++++ linux-2.4.19-rc1-ac7/include/linux/blkdev.h        Thu Jul 18 14:24:44 2002
+@@ -6,6 +6,7 @@
+ #include <linux/genhd.h>
+ #include <linux/tqueue.h>
+ #include <linux/list.h>
++/* #include <linux/blkcdb.h> */
+ struct request_queue;
+ typedef struct request_queue request_queue_t;
+@@ -30,13 +31,16 @@
+       kdev_t rq_dev;
+       int cmd;                /* READ or WRITE */
+       int errors;
++      unsigned long start_time;
+       unsigned long sector;
+       unsigned long nr_sectors;
+       unsigned long hard_sector, hard_nr_sectors;
+       unsigned int nr_segments;
+       unsigned int nr_hw_segments;
+       unsigned long current_nr_sectors;
++      unsigned long hard_cur_sectors;
+       void * special;
++/*    void * cdb;     */
+       char * buffer;
+       struct completion * waiting;
+       struct buffer_head * bh;
+@@ -119,9 +123,9 @@
+       spinlock_t              queue_lock;
+       /*
+-       * Tasks wait here for free request
++       * Tasks wait here for free read and write requests
+        */
+-      wait_queue_head_t       wait_for_request;
++      wait_queue_head_t       wait_for_requests[2];
+ };
+ struct blk_dev_struct {
+@@ -175,6 +179,8 @@
+ extern int * max_segments[MAX_BLKDEV];
++extern char * blkdev_varyio[MAX_BLKDEV];
++
+ #define MAX_SEGMENTS 128
+ #define MAX_SECTORS 255
+@@ -228,4 +234,12 @@
+       return retval;
+ }
++static inline int get_blkdev_varyio(int major, int minor)
++{
++      int retval = 0;
++      if (blkdev_varyio[major]) {
++              retval = blkdev_varyio[major][minor];   
++      }
++      return retval;
++}
+ #endif
+--- linux.org/include/linux/pci_ids.h  Mon Feb 25 20:38:13 2002
++++ linux-2.4.19-rc1-ac7/include/linux/pci_ids.h       Thu Jul 18 14:24:44 2002
+@@ -133,6 +133,7 @@
+ #define PCI_DEVICE_ID_COMPAQ_1280     0x3033
+ #define PCI_DEVICE_ID_COMPAQ_TRIFLEX  0x4000
+ #define PCI_DEVICE_ID_COMPAQ_6010     0x6010
++#define PCI_DEVICE_ID_COMPAQ_TACHYON  0xa0fc
+ #define PCI_DEVICE_ID_COMPAQ_SMART2P  0xae10
+ #define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32
+ #define PCI_DEVICE_ID_COMPAQ_NETEL10  0xae34
+@@ -346,6 +347,8 @@
+ #define PCI_DEVICE_ID_IBM_MPIC                0x0046
+ #define PCI_DEVICE_ID_IBM_3780IDSP    0x007d
+ #define PCI_DEVICE_ID_IBM_CHUKAR      0x0096
++#define PCI_DEVICE_ID_IBM_CPC710_PCI64        0x00fc
++#define PCI_DEVICE_ID_IBM_CPC710_PCI32        0x0105
+ #define       PCI_DEVICE_ID_IBM_405GP         0x0156
+ #define PCI_DEVICE_ID_IBM_SERVERAIDI960       0x01bd
+ #define PCI_DEVICE_ID_IBM_MPIC_2      0xffff
+@@ -443,6 +446,7 @@
+ #define PCI_DEVICE_ID_NEC_PCX2                0x0046
+ #define PCI_DEVICE_ID_NEC_NILE4               0x005a
+ #define PCI_DEVICE_ID_NEC_VRC5476       0x009b
++#define PCI_DEVICE_ID_NEC_VRC5477_AC97  0x00a6
+ #define PCI_VENDOR_ID_FD              0x1036
+ #define PCI_DEVICE_ID_FD_36C70                0x0000
+@@ -505,6 +509,9 @@
+ #define PCI_DEVICE_ID_HP_DIVA1                0x1049
+ #define PCI_DEVICE_ID_HP_DIVA2                0x104A
+ #define PCI_DEVICE_ID_HP_SP2_0                0x104B
++#define PCI_DEVICE_ID_HP_ZX1_SBA      0x1229
++#define PCI_DEVICE_ID_HP_ZX1_IOC      0x122a
++#define PCI_DEVICE_ID_HP_ZX1_LBA      0x122e
+ #define PCI_VENDOR_ID_PCTECH          0x1042
+ #define PCI_DEVICE_ID_PCTECH_RZ1000   0x1000
+@@ -535,10 +542,6 @@
+ #define PCI_DEVICE_ID_ELSA_MICROLINK  0x1000
+ #define PCI_DEVICE_ID_ELSA_QS3000     0x3000
+-#define PCI_VENDOR_ID_ELSA            0x1048
+-#define PCI_DEVICE_ID_ELSA_MICROLINK  0x1000
+-#define PCI_DEVICE_ID_ELSA_QS3000     0x3000
+-
+ #define PCI_VENDOR_ID_SGS             0x104a
+ #define PCI_DEVICE_ID_SGS_2000                0x0008
+ #define PCI_DEVICE_ID_SGS_1764                0x0009
+@@ -595,6 +598,7 @@
+ #define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+ #define PCI_DEVICE_ID_MOTOROLA_RAVEN  0x4801
+ #define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802
++#define PCI_DEVICE_ID_MOTOROLA_HAWK   0x4803
+ #define PCI_DEVICE_ID_MOTOROLA_CPX8216        0x4806
+ #define PCI_VENDOR_ID_PROMISE         0x105a
+@@ -602,10 +606,14 @@
+ #define PCI_DEVICE_ID_PROMISE_20267   0x4d30
+ #define PCI_DEVICE_ID_PROMISE_20246   0x4d33
+ #define PCI_DEVICE_ID_PROMISE_20262   0x4d38
++#define PCI_DEVICE_ID_PROMISE_20263   0x0D38
+ #define PCI_DEVICE_ID_PROMISE_20268   0x4d68
+-#define PCI_DEVICE_ID_PROMISE_20268R  0x6268
++#define PCI_DEVICE_ID_PROMISE_20270   0x6268
+ #define PCI_DEVICE_ID_PROMISE_20269   0x4d69
++#define PCI_DEVICE_ID_PROMISE_20271   0x6269
+ #define PCI_DEVICE_ID_PROMISE_20275   0x1275
++#define PCI_DEVICE_ID_PROMISE_20276   0x5275
++#define PCI_DEVICE_ID_PROMISE_20277   0x7275
+ #define PCI_DEVICE_ID_PROMISE_5300    0x5300
+ #define PCI_VENDOR_ID_N9              0x105d
+@@ -807,6 +815,7 @@
+ #define PCI_DEVICE_ID_AL_M1621          0x1621
+ #define PCI_DEVICE_ID_AL_M1631          0x1631
+ #define PCI_DEVICE_ID_AL_M1641          0x1641
++#define PCI_DEVICE_ID_AL_M1644          0x1644
+ #define PCI_DEVICE_ID_AL_M1647          0x1647
+ #define PCI_DEVICE_ID_AL_M1651          0x1651
+ #define PCI_DEVICE_ID_AL_M1543                0x1543
+@@ -923,6 +932,10 @@
+ #define PCI_VENDOR_ID_TTI             0x1103
+ #define PCI_DEVICE_ID_TTI_HPT343      0x0003
+ #define PCI_DEVICE_ID_TTI_HPT366      0x0004
++#define PCI_DEVICE_ID_TTI_HPT372      0x0005
++#define PCI_DEVICE_ID_TTI_HPT302      0x0006
++#define PCI_DEVICE_ID_TTI_HPT371      0x0007
++#define PCI_DEVICE_ID_TTI_HPT374      0x0008
+ #define PCI_VENDOR_ID_VIA             0x1106
+ #define PCI_DEVICE_ID_VIA_8363_0      0x0305
+@@ -959,11 +972,12 @@
+ #define PCI_DEVICE_ID_VIA_8233_7      0x3065
+ #define PCI_DEVICE_ID_VIA_82C686_6    0x3068
+ #define PCI_DEVICE_ID_VIA_8233_0      0x3074
++#define PCI_DEVICE_ID_VIA_8633_0      0x3091
++#define PCI_DEVICE_ID_VIA_8367_0      0x3099
+ #define PCI_DEVICE_ID_VIA_8622                0x3102
+ #define PCI_DEVICE_ID_VIA_8233C_0     0x3109
+ #define PCI_DEVICE_ID_VIA_8361                0x3112
+-#define PCI_DEVICE_ID_VIA_8633_0      0x3091
+-#define PCI_DEVICE_ID_VIA_8367_0      0x3099
++#define PCI_DEVICE_ID_VIA_8233A               0x3147
+ #define PCI_DEVICE_ID_VIA_86C100A     0x6100
+ #define PCI_DEVICE_ID_VIA_8231                0x8231
+ #define PCI_DEVICE_ID_VIA_8231_4      0x8235
+@@ -973,7 +987,7 @@
+ #define PCI_DEVICE_ID_VIA_82C597_1    0x8597
+ #define PCI_DEVICE_ID_VIA_82C598_1    0x8598
+ #define PCI_DEVICE_ID_VIA_8601_1      0x8601
+-#define PCI_DEVICE_ID_VIA_8505_1      0X8605
++#define PCI_DEVICE_ID_VIA_8505_1      0x8605
+ #define PCI_DEVICE_ID_VIA_8633_1      0xB091
+ #define PCI_DEVICE_ID_VIA_8367_1      0xB099
+@@ -1094,12 +1108,18 @@
+ #define PCI_DEVICE_ID_SERVERWORKS_LE    0x0009
+ #define PCI_DEVICE_ID_SERVERWORKS_CIOB30  0x0010
+ #define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011
++#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
+ #define PCI_DEVICE_ID_SERVERWORKS_OSB4          0x0200
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB5          0x0201
++#define PCI_DEVICE_ID_SERVERWORKS_CSB6    0x0203
+ #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
++#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+ #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
++#define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221
++#define PCI_DEVICE_ID_SERVERWORKS_GCLE    0x0225
++#define PCI_DEVICE_ID_SERVERWORKS_GCLE2   0x0227
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230
+ #define PCI_VENDOR_ID_SBE             0x1176
+@@ -1112,6 +1132,11 @@
+ #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a
+ #define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
++#define PCI_VENDOR_ID_TOSHIBA_2               0x102f
++#define PCI_DEVICE_ID_TOSHIBA_TX3927  0x000a
++#define PCI_DEVICE_ID_TOSHIBA_TC35815CF       0x0030
++#define PCI_DEVICE_ID_TOSHIBA_TX4927  0x0180
++
+ #define PCI_VENDOR_ID_RICOH           0x1180
+ #define PCI_DEVICE_ID_RICOH_RL5C465   0x0465
+ #define PCI_DEVICE_ID_RICOH_RL5C466   0x0466
+@@ -1287,13 +1312,9 @@
+ #define PCI_VENDOR_ID_ITE             0x1283
+ #define PCI_DEVICE_ID_ITE_IT8172G     0x8172
+ #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
+-
+-#define PCI_VENDOR_ID_ITE             0x1283
+-#define PCI_DEVICE_ID_ITE_IT8172G     0x8172
+-
+-#define PCI_VENDOR_ID_ITE                     0x1283
+ #define PCI_DEVICE_ID_ITE_8872                0x8872
++#define PCI_DEVICE_ID_ITE_IT8330G_0    0xe886
+ /* formerly Platform Tech */
+ #define PCI_VENDOR_ID_ESS_OLD         0x1285
+@@ -1458,6 +1479,8 @@
+ #define PCI_DEVICE_ID_LAVA_DSERIAL    0x0100 /* 2x 16550 */
+ #define PCI_DEVICE_ID_LAVA_QUATRO_A   0x0101 /* 2x 16550, half of 4 port */
+ #define PCI_DEVICE_ID_LAVA_QUATRO_B   0x0102 /* 2x 16550, half of 4 port */
++#define PCI_DEVICE_ID_LAVA_OCTO_A     0x0180 /* 4x 16550A, half of 8 port */
++#define PCI_DEVICE_ID_LAVA_OCTO_B     0x0181 /* 4x 16550A, half of 8 port */
+ #define PCI_DEVICE_ID_LAVA_PORT_PLUS  0x0200 /* 2x 16650 */
+ #define PCI_DEVICE_ID_LAVA_QUAD_A     0x0201 /* 2x 16650, half of 4 port */
+ #define PCI_DEVICE_ID_LAVA_QUAD_B     0x0202 /* 2x 16650, half of 4 port */
+@@ -1474,9 +1497,9 @@
+ #define PCI_VENDOR_ID_OXSEMI          0x1415
+ #define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403
+ #define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
+-#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x950A
+ #define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+ #define PCI_DEVICE_ID_OXSEMI_16PCI954PP       0x9513
++#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
+ #define PCI_VENDOR_ID_AIRONET         0x14b9
+ #define PCI_DEVICE_ID_AIRONET_4800_1  0x0001
+@@ -1506,7 +1529,11 @@
+ #define PCI_VENDOR_ID_BROADCOM                0x14e4
+ #define PCI_DEVICE_ID_TIGON3_5700     0x1644
+ #define PCI_DEVICE_ID_TIGON3_5701     0x1645
++#define PCI_DEVICE_ID_TIGON3_5702     0x1646
+ #define PCI_DEVICE_ID_TIGON3_5703     0x1647
++#define PCI_DEVICE_ID_TIGON3_5702FE   0x164d
++#define PCI_DEVICE_ID_TIGON3_5702X    0x16a6
++#define PCI_DEVICE_ID_TIGON3_5703X    0x16a7
+ #define PCI_VENDOR_ID_SYBA            0x1592
+ #define PCI_DEVICE_ID_SYBA_2P_EPP     0x0782
+@@ -1521,6 +1548,10 @@
+ #define PCI_VENDOR_ID_PDC             0x15e9
+ #define PCI_DEVICE_ID_PDC_1841                0x1841
++#define PCI_VENDOR_ID_ALTIMA          0x173b
++#define PCI_DEVICE_ID_ALTIMA_AC1000   0x03e8
++#define PCI_DEVICE_ID_ALTIMA_AC9100   0x03ea
++
+ #define PCI_VENDOR_ID_SYMPHONY                0x1c1c
+ #define PCI_DEVICE_ID_SYMPHONY_101    0x0001
+@@ -1571,13 +1602,15 @@
+ #define PCI_DEVICE_ID_S3_ViRGE_MXPMV  0x8c03
+ #define PCI_DEVICE_ID_S3_SONICVIBES   0xca00
++#define PCI_VENDOR_ID_DUNORD          0x5544
++#define PCI_DEVICE_ID_DUNORD_I3000    0x0001
++#define PCI_VENDOR_ID_GENROCO         0x5555
++#define PCI_DEVICE_ID_GENROCO_HFP832  0x0003
++
+ #define PCI_VENDOR_ID_DCI             0x6666
+ #define PCI_DEVICE_ID_DCI_PCCOM4      0x0001
+ #define PCI_DEVICE_ID_DCI_PCCOM8      0x0002
+-#define PCI_VENDOR_ID_GENROCO         0x5555
+-#define PCI_DEVICE_ID_GENROCO_HFP832  0x0003
+-
+ #define PCI_VENDOR_ID_INTEL           0x8086
+ #define PCI_DEVICE_ID_INTEL_21145     0x0039
+ #define PCI_DEVICE_ID_INTEL_82375     0x0482
+@@ -1586,6 +1619,7 @@
+ #define PCI_DEVICE_ID_INTEL_82430     0x0486
+ #define PCI_DEVICE_ID_INTEL_82434     0x04a3
+ #define PCI_DEVICE_ID_INTEL_I960      0x0960
++#define PCI_DEVICE_ID_INTEL_I960RM    0x0962
+ #define PCI_DEVICE_ID_INTEL_82562ET   0x1031
+ #define PCI_DEVICE_ID_INTEL_82559ER   0x1209
+ #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
+@@ -1631,16 +1665,6 @@
+ #define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443
+ #define PCI_DEVICE_ID_INTEL_82801BA_3 0x2444
+ #define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445
+-#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480
+-#define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482
+-#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483
+-#define PCI_DEVICE_ID_INTEL_82801CA_4 0x2484
+-#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485
+-#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486
+-#define PCI_DEVICE_ID_INTEL_82801CA_7 0x2487
+-#define PCI_DEVICE_ID_INTEL_82801CA_10        0x248a
+-#define PCI_DEVICE_ID_INTEL_82801CA_11        0x248b
+-#define PCI_DEVICE_ID_INTEL_82801CA_12        0x248c
+ #define PCI_DEVICE_ID_INTEL_82801BA_5 0x2446
+ #define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448
+ #define PCI_DEVICE_ID_INTEL_82801BA_7 0x2449
+@@ -1648,6 +1672,13 @@
+ #define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b
+ #define PCI_DEVICE_ID_INTEL_82801BA_10        0x244c
+ #define PCI_DEVICE_ID_INTEL_82801BA_11        0x244e
++#define PCI_DEVICE_ID_INTEL_82801E_0  0x2450
++#define PCI_DEVICE_ID_INTEL_82801E_2  0x2452
++#define PCI_DEVICE_ID_INTEL_82801E_3  0x2453
++#define PCI_DEVICE_ID_INTEL_82801E_9  0x2459
++#define PCI_DEVICE_ID_INTEL_82801E_11 0x245B
++#define PCI_DEVICE_ID_INTEL_82801E_14 0x245D
++#define PCI_DEVICE_ID_INTEL_82801E_15 0x245E
+ #define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480
+ #define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482
+ #define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483
+@@ -1658,6 +1689,15 @@
+ #define PCI_DEVICE_ID_INTEL_82801CA_10        0x248a
+ #define PCI_DEVICE_ID_INTEL_82801CA_11        0x248b
+ #define PCI_DEVICE_ID_INTEL_82801CA_12        0x248c
++#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0
++#define PCI_DEVICE_ID_INTEL_82801DB_2 0x24c2
++#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
++#define PCI_DEVICE_ID_INTEL_82801DB_4 0x24c4
++#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5
++#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6
++#define PCI_DEVICE_ID_INTEL_82801DB_7 0x24c7
++#define PCI_DEVICE_ID_INTEL_82801DB_11        0x24cb
++#define PCI_DEVICE_ID_INTEL_82801DB_13        0x24cd
+ #define PCI_DEVICE_ID_INTEL_80310     0x530d
+ #define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120
+ #define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121
This page took 6.277186 seconds and 4 git commands to generate.