--- /dev/null
+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, ®49h);
+-// 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, ®49h);
++ 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, ®54h);
++ 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, ®54h);
+- 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, ®53h);
+ 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, ®5xh);
+ pci_read_config_byte(bmide_dev, 0x5c, ®5yh);
+ 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, ®5xh);
+ pci_read_config_byte(bmide_dev, 0x5d, ®5yh);
+ 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, ®5xh);
+ pci_read_config_byte(bmide_dev, 0x55, ®5yh);
+- 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, ®5yh1);
+
+ 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, ®5xh);
+ pci_read_config_byte(bmide_dev, 0x57, ®5yh);
+ 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, ®50);
+- (void) pci_read_config_byte(bmide_dev, ARTTIM0, ®53);
+- (void) pci_read_config_byte(bmide_dev, DRWTIM0, ®54);
+- (void) pci_read_config_byte(bmide_dev, ARTTIM1, ®55);
+- (void) pci_read_config_byte(bmide_dev, DRWTIM1, ®56);
+- (void) pci_read_config_byte(bmide_dev, ARTTIM2, ®57);
+- (void) pci_read_config_byte(bmide_dev, DRWTIM2, ®58);
+- (void) pci_read_config_byte(bmide_dev, DRWTIM3, ®5b);
+- (void) pci_read_config_byte(bmide_dev, MRDMODE, ®71);
+- (void) pci_read_config_byte(bmide_dev, BMIDESR0, ®72);
+- (void) pci_read_config_byte(bmide_dev, UDIDETCR0, ®73);
+- (void) pci_read_config_byte(bmide_dev, BMIDESR1, ®7a);
+- (void) pci_read_config_byte(bmide_dev, UDIDETCR1, ®7b);
+-
+- 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, ®50);
++ (void) pci_read_config_byte(dev, ARTTIM0, ®53);
++ (void) pci_read_config_byte(dev, DRWTIM0, ®54);
++ (void) pci_read_config_byte(dev, ARTTIM1, ®55);
++ (void) pci_read_config_byte(dev, DRWTIM1, ®56);
++ (void) pci_read_config_byte(dev, ARTTIM2, ®57);
++ (void) pci_read_config_byte(dev, DRWTIM2, ®58);
++ (void) pci_read_config_byte(dev, DRWTIM3, ®5b);
++ (void) pci_read_config_byte(dev, MRDMODE, ®71);
++ (void) pci_read_config_byte(dev, BMIDESR0, ®72);
++ (void) pci_read_config_byte(dev, UDIDETCR0, ®73);
++ (void) pci_read_config_byte(dev, BMIDESR1, ®7a);
++ (void) pci_read_config_byte(dev, UDIDETCR1, ®7b);
++
++ 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, ®D);
+ (void) pci_read_config_byte(dev, pciU, ®U);
+@@ -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, ®D);
+ (void) pci_read_config_byte(dev, pciU, ®U);
++#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, ®1);
+- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2);
++ pci_read_config_dword(dev, 0x44, ®1);
++ pci_read_config_dword(dev, 0x48, ®2);
+ 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, ®1);
+- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2);
++ pci_read_config_dword(dev, 0x44, ®1);
++ pci_read_config_dword(dev, 0x48, ®2);
+ 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, ®1);
+- /* 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, ®1);
+ 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, ®5a);
++ pci_read_config_byte(dev, 0x5a, ®5a);
+ 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, ®50h);
+- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h);
+- pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, ®5ah);
+- printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
++ pci_read_config_byte(dev, 0x50, ®50h);
++ pci_read_config_byte(dev, 0x52, ®52h);
++ pci_read_config_byte(dev, 0x5a, ®5ah);
++ 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, ®59h);
++ 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, ®59h);
++ pci_read_config_byte(dev, state_reg, ®XXh);
++
++ 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, ®5ah);
++ /* 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, ®5bh);
++ if (reg5bh & 0x80) {
++ /* spin looking for the clock to destabilize */
++ for (i = 0; i < 0x1000; ++i) {
++ pci_read_config_byte(dev, 0x5b,
++ ®5bh);
++ 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, ®1);
++
++ /* 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, ®5ah);
+- 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, ®48);
+- pci_read_config_byte(dev, 0x4a, ®4a);
++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, ®48);
++ pci_read_config_byte(dev, 0x4a, ®4a);
+
+ /*
+ * 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, ®68h);
+ pci_read_config_dword(dev, 0x6c, ®6ch);
+
++ 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, ®55);
+
+ 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, ®)
+- && !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, ®) &&
++ !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 & PCI_COMMAND_IO)) {
++ if (!pci_read_config_word (dev, PCI_COMMAND, ®) &&
++ !(reg & PCI_COMMAND_IO)) {
+ printk("%s: buggy IDE controller disabled (BIOS)\n", name);
+ return;
+ }
+- if (!pci_read_config_word (dev, 0x40, ®)
+- && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
+- {
++ if (!pci_read_config_word (dev, 0x40, ®) &&
++ !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, ®40);
+- pci_read_config_dword(bmide_dev, 0x44, ®44);
+- pci_read_config_word(bmide_dev, 0x48, ®48);
+- pci_read_config_byte(bmide_dev, 0x54, ®54);
+- pci_read_config_word(bmide_dev, 0x56, ®56);
+-
+- /*
+- * 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, ®40);
++ pci_read_config_dword(dev, 0x44, ®44);
++ pci_read_config_word(dev, 0x48, ®48);
++ pci_read_config_byte(dev, 0x54, ®54);
++ pci_read_config_word(dev, 0x56, ®56);
++
++ /*
++ * 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, ®);
++ 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 &= ~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, ®64);
+-#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, ®4c);
++ 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, ®_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, ®00);
++ 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, ®00);
++ pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01);
++ pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10);
++ pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11);
++
++/* 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, ®);
+- 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, ®);
++ 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, ®);
++ 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, ®);
+ 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, ®);
+- 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, ®2);
+- rc = pci_read_config_word(bmide_dev, 0x4e, ®3);
++
++/* 80-pin cable ? */
++ if (chipset_family > ATA_33) {
++ pci_read_config_byte(bmide_dev, 0x48, ®);
++ 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, ®2);
++ pci_read_config_word(bmide_dev, 0x4e, ®3);
+ p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+ reg2, reg3);
+
+- rc = pci_read_config_byte(bmide_dev, 0x4b, ®);
+- 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, ®);
+- rc = pci_read_config_byte(bmide_dev, 0x45, ®1);
+- 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, ®);
+- rc = pci_read_config_byte(bmide_dev, 0x44, ®1);
+- 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, ®);
+- 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, ®);
+- rc = pci_read_config_byte(bmide_dev, 0x47, ®1);
+- 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, ®);
+- rc = pci_read_config_byte(bmide_dev, 0x46, ®1);
+- 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, ®4bh);
++#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, ®4bh);
++
+ 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, ®);
++ /* 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, ®52h);
+- 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, ®);
++ 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, ®);
++ 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, ®);
++ 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, ®);
++ 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, ®48h);
+
+- 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, ®4a);
+
+ 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, ®4a);
+ 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, ®47);
+-
+ 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