[LWN Logo]
[LWN.net]
From:	 Martin Dalecki <dalecki@evision-ventures.com>
To:	 Linus Torvalds <torvalds@transmeta.com>
Subject: [PATCH] 2.5.15 IDE 64
Date:	 Wed, 15 May 2002 14:04:24 +0200
Cc:	 Kernel Mailing List <linux-kernel@vger.kernel.org>

Tue May 14 13:35:04 CEST 2002 ide-clean-64:

Let's just get over with  this before queue handling will be targeted again...

- Implement suggestions by Russel King for improved portability and separation
   between PCI and non PCI host code.

- pdc202xxx updates from Thierry Vignaud.

- Tinny PIO fix from Tomita.

diff -urN linux-2.5.15/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.15/drivers/ide/ide.c	2002-05-15 14:55:12.000000000 +0200
+++ linux/drivers/ide/ide.c	2002-05-15 13:34:25.000000000 +0200
@@ -1145,7 +1145,7 @@
 }
 
 /*
- * Select the next device which will be serviced.  This selects onlt between
+ * Select the next device which will be serviced.  This selects only between
  * devices on the same channel, since everything else will be scheduled on the
  * queue level.
  */
diff -urN linux-2.5.15/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- linux-2.5.15/drivers/ide/ide-dma.c	2002-05-15 14:55:05.000000000 +0200
+++ linux/drivers/ide/ide-dma.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,866 +0,0 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- *  Copyright (c) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- *  Copyright (c) 1995-1998  Mark Lord
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Special Thanks to Mark for his Six years of work.
- *
- * This module provides support for the bus-master IDE DMA functions
- * of various PCI chipsets, including the Intel PIIX (i82371FB for
- * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and
- * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
- * ("PIIX" stands for "PCI ISA IDE Xcellerator").
- *
- * Pretty much the same code works for other IDE PCI bus-mastering chipsets.
- *
- * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
- *
- * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single),
- * or which are recognized as "good" (see table below).  Drives with only mode0
- * or mode1 (multi/single) DMA should also work with this chipset/driver
- * (eg. MC2112A) but are not enabled by default.
- *
- * Use "hdparm -i" to view modes supported by a given drive.
- *
- * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
- * DMA support, but must be (re-)compiled against this kernel version or later.
- *
- * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
- * If problems arise, ide.c will disable DMA operation after a few retries.
- * This error recovery mechanism works and has been extremely well exercised.
- *
- * IDE drives, depending on their vintage, may support several different modes
- * of DMA operation.  The boot-time modes are indicated with a "*" in
- * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
- * the "hdparm -X" feature.  There is seldom a need to do this, as drives
- * normally power-up with their "best" PIO/DMA modes enabled.
- *
- * Testing has been done with a rather extensive number of drives,
- * with Quantum & Western Digital models generally outperforming the pack,
- * and Fujitsu & Conner (and some Seagate which are really Conner) drives
- * showing more lackluster throughput.
- *
- * Keep an eye on /var/adm/messages for "DMA disabled" messages.
- *
- * Some people have reported trouble with Intel Zappa motherboards.
- * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
- * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
- * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
- *
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
- * fixing the problem with the BIOS on some Acer motherboards.
- *
- * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
- * "TX" chipset compatibility and for providing patches for the "TX" chipset.
- *
- * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
- * at generic DMA -- his patches were referred to when preparing this code.
- *
- * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
- * for supplying a Promise UDMA board & WD UDMA drive for this work!
- *
- * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
- *
- * ATA-66/100 and recovery functions, I forgot the rest......
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed.  Oh the things we forget.  I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-struct drive_list_entry drive_whitelist[] = {
-	{ "Micropolis 2112A", NULL },
-	{ "CONNER CTMA 4000", NULL },
-	{ "CONNER CTT8000-A", NULL },
-	{ "ST34342A", NULL },
-	{ NULL, NULL }
-};
-
-struct drive_list_entry drive_blacklist[] = {
-
-	{ "WDC AC11000H", NULL },
-	{ "WDC AC22100H", NULL },
-	{ "WDC AC32500H", NULL },
-	{ "WDC AC33100H", NULL },
-	{ "WDC AC31600H", NULL },
-	{ "WDC AC32100H", "24.09P07" },
-	{ "WDC AC23200L", "21.10N21" },
-	{ "Compaq CRD-8241B", NULL },
-	{ "CRD-8400B", NULL },
-	{ "CRD-8480B", NULL },
-	{ "CRD-8480C", NULL },
-	{ "CRD-8482B", NULL },
-	{ "CRD-84", NULL },
-	{ "SanDisk SDP3B", NULL },
-	{ "SanDisk SDP3B-64", NULL },
-	{ "SANYO CD-ROM CRD", NULL },
-	{ "HITACHI CDR-8", NULL },
-	{ "HITACHI CDR-8335", NULL },
-	{ "HITACHI CDR-8435", NULL },
-	{ "Toshiba CD-ROM XM-6202B", NULL },
-	{ "CD-532E-A", NULL },
-	{ "E-IDE CD-ROM CR-840", NULL },
-	{ "CD-ROM Drive/F5A", NULL },
-	{ "RICOH CD-R/RW MP7083A", NULL },
-	{ "WPI CDD-820", NULL },
-	{ "SAMSUNG CD-ROM SC-148C", NULL },
-	{ "SAMSUNG CD-ROM SC-148F", NULL },
-	{ "SAMSUNG CD-ROM SC", NULL },
-	{ "SanDisk SDP3B-64", NULL },
-	{ "SAMSUNG CD-ROM SN-124", NULL },
-	{ "PLEXTOR CD-R PX-W8432T", NULL },
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL },
-	{ "_NEC DV5800A", NULL },
-	{ NULL,	NULL }
-
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((drive_table->id_firmware && !strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!drive_table->id_firmware)))
-			return 1;
-	return 0;
-}
-
-#else
-
-/*
- * good_dma_drives() lists the model names (from "hdparm -i")
- * of drives which do not support mode2 DMA but which are
- * known to work fine with this interface under Linux.
- */
-const char *good_dma_drives[] = {"Micropolis 2112A",
-				 "CONNER CTMA 4000",
-				 "CONNER CTT8000-A",
-				 "ST34342A",	/* for Sun Ultra */
-				 NULL};
-
-/*
- * bad_dma_drives() lists the model names (from "hdparm -i")
- * of drives which supposedly support (U)DMA but which are
- * known to corrupt data with this interface under Linux.
- *
- * This is an empirical list. Its generated from bug reports. That means
- * while it reflects actual problem distributions it doesn't answer whether
- * the drive or the controller, or cabling, or software, or some combination
- * thereof is the fault. If you don't happen to agree with the kernel's
- * opinion of your drive - use hdparm to turn DMA on.
- */
-const char *bad_dma_drives[] = {"WDC AC11000H",
-				"WDC AC22100H",
-				"WDC AC32100H",
-				"WDC AC32500H",
-				"WDC AC33100H",
-				"WDC AC31600H",
-				NULL};
-
-#endif
-
-/*
- * This is the handler for disk read/write DMA interrupts.
- */
-ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq)
-{
-	u8 stat, dma_stat;
-
-	dma_stat = udma_stop(drive);
-	if (OK_STAT(stat = GET_STAT(),DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			__ide_end_request(drive, rq, 1, rq->nr_sectors);
-			return ide_stopped;
-		}
-		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n",
-		       drive->name, dma_stat);
-	}
-	return ide_error(drive, rq, "dma_intr", stat);
-}
-
-/*
- * FIXME: taskfiles should be a map of pages, not a long virt address... /jens
- * FIXME: I agree with Jens --mdcki!
- */
-static int build_sglist(struct ata_channel *ch, struct request *rq)
-{
-	struct scatterlist *sg = ch->sg_table;
-	int nents = 0;
-
-	if (rq->flags & REQ_DRIVE_ACB) {
-		struct ata_taskfile *args = rq->special;
-#if 1
-		unsigned char *virt_addr = rq->buffer;
-		int sector_count = rq->nr_sectors;
-#else
-		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
-
-		if (nents > rq->nr_segments)
-			printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
-#endif
-
-		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-
-		/*
-		 * FIXME: This depends upon a hard coded page size!
-		 */
-		if (sector_count > 128) {
-			memset(&sg[nents], 0, sizeof(*sg));
-
-			sg[nents].page = virt_to_page(virt_addr);
-			sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
-			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].page = virt_to_page(virt_addr);
-		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
-		sg[nents].length =  sector_count  * SECTOR_SIZE;
-		++nents;
-	} else {
-		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
-
-		if (rq->q && nents > rq->nr_phys_segments)
-			printk("ide-dma: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
-
-		if (rq_data_dir(rq) == READ)
-			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
-		else
-			ch->sg_dma_direction = PCI_DMA_TODEVICE;
-
-	}
-	return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction);
-}
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-int check_drive_lists(struct ata_device *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else
-	const char **list;
-
-	if (good_bad) {
-		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
-	}
-#endif
-	return 0;
-}
-
-static int config_drive_for_dma(struct ata_device *drive)
-{
-	int config_allows_dma = 1;
-	struct hd_driveid *id = drive->id;
-	struct ata_channel *ch = drive->channel;
-
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->type != ATA_DISK)
-		config_allows_dma = 0;
-#endif
-
-	if (id && (id->capability & 1) && ch->autodma && config_allows_dma) {
-		/* Consult the list of known "bad" drives */
-		if (udma_black_list(drive)) {
-			udma_enable(drive, 0, 1);
-
-			return 0;
-		}
-
-		/* 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)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* 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)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
-				udma_enable(drive, 1, 1);
-
-				return 0;
-			}
-		/* Consult the list of known "good" drives */
-		if (udma_white_list(drive)) {
-			udma_enable(drive, 1, 1);
-
-			return 0;
-		}
-	}
-	udma_enable(drive, 0, 0);
-
-	return 0;
-}
-
-/*
- * 1 dma-ing, 2 error, 4 intr
- */
-static int dma_timer_expiry(struct ata_device *drive, struct request *rq)
-{
-	/* FIXME: What's that? */
-	u8 dma_stat = inb(drive->channel->dma_base+2);
-
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif
-
-#if 0
-	drive->expiry = NULL;	/* one free ride for now */
-#endif
-
-	if (dma_stat & 2) {	/* ERROR */
-		u8 stat = GET_STAT();
-		return ide_error(drive, rq, "dma_timer_expiry", stat);
-	}
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
-	return 0;
-}
-
-int ata_start_dma(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	unsigned int reading = 0;
-
-	if (rq_data_dir(rq) == READ)
-		reading = 1 << 3;
-
-	/* try PIO instead of DMA */
-	if (!udma_new_table(ch, rq))
-		return 1;
-
-	outl(ch->dmatable_dma, dma_base + 4); /* PRD table */
-	outb(reading, dma_base);		/* specify r/w */
-	outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-	drive->waiting_for_dma = 1;
-	return 0;
-}
-
-/*
- * This initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * udma_start afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- * May also be invoked from trm290.c
- */
-int XXX_ide_dmaproc(struct ata_device *drive)
-{
-	return config_drive_for_dma(drive);
-}
-
-/*
- * Needed for allowing full modular support of ide-driver
- */
-void ide_release_dma(struct ata_channel *ch)
-{
-	if (!ch->dma_base)
-		return;
-
-	if (ch->dmatable_cpu) {
-		pci_free_consistent(ch->pci_dev,
-				    PRD_ENTRIES * PRD_BYTES,
-				    ch->dmatable_cpu,
-				    ch->dmatable_dma);
-		ch->dmatable_cpu = NULL;
-	}
-	if (ch->sg_table) {
-		kfree(ch->sg_table);
-		ch->sg_table = NULL;
-	}
-	if ((ch->dma_extra) && (ch->unit == 0))
-		release_region((ch->dma_base + 16), ch->dma_extra);
-	release_region(ch->dma_base, 8);
-	ch->dma_base = 0;
-}
-
-/*
- * This can be called for a dynamically installed interface. Don't __init it
- */
-void ata_init_dma(struct ata_channel *ch, unsigned long dma_base)
-{
-	if (!request_region(dma_base, 8, ch->name)) {
-		printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n");
-
-		return;
-	}
-	printk(KERN_INFO"    %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7);
-	ch->dma_base = dma_base;
-	ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev,
-						  PRD_ENTRIES * PRD_BYTES,
-						  &ch->dmatable_dma);
-	if (ch->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
-
-	ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (ch->sg_table == NULL) {
-		pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    ch->dmatable_cpu, ch->dmatable_dma);
-		goto dma_alloc_failure;
-	}
-
-	if (!ch->XXX_udma)
-		ch->XXX_udma = XXX_ide_dmaproc;
-
-	if (ch->chipset != ide_trm290) {
-		u8 dma_stat = inb(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
-	}
-	printk("\n");
-	return;
-
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
-}
-
-/****************************************************************************
- * UDMA function which should have architecture specific counterparts where
- * neccessary.
- *
- * The intention is that at some point in time we will move this whole to
- * architecture specific kernel sections. For now I would love the architecture
- * maintainers to just #ifdef #endif this stuff directly here. I have for now
- * tryed to update as much as I could in the architecture specific code.  But
- * of course I may have done mistakes, so please bear with me and update it
- * here the proper way.
- *
- * Thank you a lot in advance!
- *
- * Sat May  4 20:29:46 CEST 2002 Marcin Dalecki.
- */
-
-/*
- * This is the generic part of the DMA setup used by the host chipset drivers
- * in the corresponding DMA setup method.
- *
- * FIXME: there are some places where this gets used driectly for "error
- * recovery" in the ATAPI drivers. This was just plain wrong before, in esp.
- * not portable, and just got uncovered now.
- */
-void udma_enable(struct ata_device *drive, int on, int verbose)
-{
-	struct ata_channel *ch = drive->channel;
-	int set_high = 1;
-	u8 unit;
-	u64 addr;
-
-
-	/* Method overloaded by host chip specific code. */
-	if (ch->udma_enable) {
-		ch->udma_enable(drive, on, verbose);
-
-		return;
-	}
-
-	/* Fall back to the default implementation. */
-	unit = (drive->select.b.unit & 0x01);
-	addr = BLK_BOUNCE_HIGH;
-
-	if (!on) {
-		if (verbose)
-			printk("%s: DMA disabled\n", drive->name);
-		set_high = 0;
-		outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-		udma_tcq_enable(drive, 0);
-#endif
-	}
-
-	/* toggle bounce buffers */
-
-	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = drive->channel->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-
-	drive->using_dma = on;
-
-	if (on) {
-		outb(inb(ch->dma_base + 2) | (1 << (5 + unit)), ch->dma_base + 2);
-#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
-		udma_tcq_enable(drive, 1);
-#endif
-	}
-}
-
-/*
- * This prepares a dma request.  Returns 0 if all went okay, returns 1
- * otherwise.  May also be invoked from trm290.c
- */
-int udma_new_table(struct ata_channel *ch, struct request *rq)
-{
-	unsigned int *table = ch->dmatable_cpu;
-#ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (ch->chipset == ide_trm290);
-#else
-	const int is_trm290_chipset = 0;
-#endif
-	unsigned int count = 0;
-	int i;
-	struct scatterlist *sg;
-
-	ch->sg_nents = i = build_sglist(ch, rq);
-	if (!i)
-		return 0;
-
-	sg = ch->sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		/*
-		 * Fill in the dma table, without crossing any 64kB boundaries.
-		 * Most hardware requires 16-bit alignment of all blocks,
-		 * but the trm290 requires 32-bit alignment.
-		 */
-
-		while (cur_len) {
-			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-
-			if (count++ >= PRD_ENTRIES) {
-				printk("ide-dma: count %d, sg_nents %d, cur_len %d, cur_addr %u\n",
-						count, ch->sg_nents, cur_len, cur_addr);
-				BUG();
-			}
-
-			if (bcount > cur_len)
-				bcount = cur_len;
-			*table++ = cpu_to_le32(cur_addr);
-			xcount = bcount & 0xffff;
-			if (is_trm290_chipset)
-				xcount = ((xcount >> 2) - 1) << 16;
-			if (xcount == 0x0000) {
-		        /*
-			 * Most chipsets correctly interpret a length of
-			 * 0x0000 as 64KB, but at least one (e.g. CS5530)
-			 * misinterprets it as zero (!). So here we break
-			 * the 64KB entry into two 32KB entries instead.
-			 */
-				if (count++ >= PRD_ENTRIES) {
-					pci_unmap_sg(ch->pci_dev, sg,
-						     ch->sg_nents,
-						     ch->sg_dma_direction);
-					return 0;
-				}
-
-				*table++ = cpu_to_le32(0x8000);
-				*table++ = cpu_to_le32(cur_addr + 0x8000);
-				xcount = 0x8000;
-			}
-			*table++ = cpu_to_le32(xcount);
-			cur_addr += bcount;
-			cur_len -= bcount;
-		}
-
-		sg++;
-		i--;
-	}
-
-	if (!count)
-		printk(KERN_ERR "%s: empty DMA table?\n", ch->name);
-	else if (!is_trm290_chipset)
-		*--table |= cpu_to_le32(0x80000000);
-
-	return count;
-}
-
-/* Teardown mappings after DMA has completed.  */
-void udma_destroy_table(struct ata_channel *ch)
-{
-	pci_unmap_sg(ch->pci_dev, ch->sg_table, ch->sg_nents, ch->sg_dma_direction);
-}
-
-void udma_print(struct ata_device *drive)
-{
-#ifdef CONFIG_ARCH_ACORN
-	printk(", DMA");
-#else
-	struct hd_driveid *id = drive->id;
-	char *str = NULL;
-
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
-		if ((id->dma_ultra >> 15) & 1)
-			str = ", UDMA(mode 7)";	/* UDMA BIOS-enabled! */
-		else
-			str = ", 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) {
-			str = ", UDMA(100)";	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			str = ", UDMA(66)";	/* UDMA BIOS-enabled! */
-		} else {
-			str = ", UDMA(44)";	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			str = ", UDMA(33)";	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			str = ", UDMA(25)";	/* UDMA BIOS-enabled! */
-		} else {
-			str = ", UDMA(16)";	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4)
-		str = ", (U)DMA";	/* Can be BIOS-enabled! */
-	else
-		str = ", DMA";
-
-	printk(str);
-#endif
-}
-
-/*
- * Drive back/white list handling for UDMA capability:
- */
-
-int udma_black_list(struct ata_device *drive)
-{
-	return check_drive_lists(drive, 0);
-}
-
-int udma_white_list(struct ata_device *drive)
-{
-	return check_drive_lists(drive, 1);
-}
-
-/*
- * Generic entry points for functions provided possibly by the host chip set
- * drivers.
- */
-
-/*
- * Prepare the channel for a DMA startfer. Please note that only the broken
- * Pacific Digital host chip needs the reques to be passed there to decide
- * about addressing modes.
- */
-
-int udma_start(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-
-	if (ch->udma_start)
-		return ch->udma_start(drive, rq);
-
-	/* Note that this is done *after* the cmd has
-	 * been issued to the drive, as per the BM-IDE spec.
-	 * The Promise Ultra33 doesn't work correctly when
-	 * we do this part before issuing the drive cmd.
-	 */
-	outb(inb(dma_base)|1, dma_base);		/* start DMA */
-	return 0;
-}
-
-int udma_stop(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned long dma_base = ch->dma_base;
-	u8 dma_stat;
-
-	if (ch->udma_stop)
-		return ch->udma_stop(drive);
-
-	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 */
-	udma_destroy_table(ch);			/* purge DMA mappings */
-
-	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-}
-
-/*
- * This is the default read write function.
- *
- * It's exported only for host chips which use it for fallback or (too) late
- * capability checking.
- */
-
-int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq)
-{
-	if (ata_start_dma(drive, rq))
-		return 1;
-
-	if (drive->type != ATA_DISK)
-		return 0;
-
-	reading <<= 3;
-
-	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-	if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) {
-		struct ata_taskfile *args = rq->special;
-
-		OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
-	} else if (drive->addressing) {
-		OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-	} else {
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-	}
-
-	return udma_start(drive, rq);
-}
-
-int udma_read(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-
-	if (ch->udma_read)
-		return ch->udma_read(drive, rq);
-
-	return ata_do_udma(1, drive, rq);
-}
-
-int udma_write(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-
-	if (ch->udma_write)
-		return ch->udma_write(drive, rq);
-
-	return ata_do_udma(0, drive, rq);
-}
-
-/*
- * FIXME: This should be attached to a channel as we can see now!
- */
-int udma_irq_status(struct ata_device *drive)
-{
-	struct ata_channel *ch = drive->channel;
-	u8 dma_stat;
-
-	if (ch->udma_irq_status)
-		return ch->udma_irq_status(drive);
-
-	/* default action */
-	dma_stat = inb(ch->dma_base + 2);
-
-	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-}
-
-void udma_timeout(struct ata_device *drive)
-{
-	printk(KERN_ERR "ATA: UDMA timeout occured %s!\n", drive->name);
-
-	/* Invoke the chipset specific handler now. */
-	if (drive->channel->udma_timeout)
-		drive->channel->udma_timeout(drive);
-
-}
-
-void udma_irq_lost(struct ata_device *drive)
-{
-	if (drive->channel->udma_irq_lost)
-		drive->channel->udma_irq_lost(drive);
-}
-
-EXPORT_SYMBOL(udma_enable);
-EXPORT_SYMBOL(udma_start);
-EXPORT_SYMBOL(udma_stop);
-EXPORT_SYMBOL(udma_read);
-EXPORT_SYMBOL(udma_write);
-EXPORT_SYMBOL(ata_do_udma);
-EXPORT_SYMBOL(udma_irq_status);
-EXPORT_SYMBOL(udma_print);
-EXPORT_SYMBOL(udma_black_list);
-EXPORT_SYMBOL(udma_white_list);
diff -urN linux-2.5.15/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.15/drivers/ide/ide-taskfile.c	2002-05-15 14:55:12.000000000 +0200
+++ linux/drivers/ide/ide-taskfile.c	2002-05-15 14:07:43.000000000 +0200
@@ -562,7 +562,7 @@
 		if (!ide_end_request(drive, rq, 1))
 			return ide_stopped;
 
-	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+	if ((rq->nr_sectors == 1) != (stat & DRQ_STAT)) {
 		pBuf = ide_map_rq(rq, &flags);
 		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
 
diff -urN linux-2.5.15/drivers/ide/Makefile linux/drivers/ide/Makefile
--- linux-2.5.15/drivers/ide/Makefile	2002-05-15 14:55:12.000000000 +0200
+++ linux/drivers/ide/Makefile	2002-05-14 17:10:48.000000000 +0200
@@ -10,7 +10,7 @@
 
 O_TARGET := idedriver.o
 
-export-objs	:= ide-taskfile.o ide.o ide-features.o ide-probe.o ide-dma.o ataraid.o
+export-objs	:= ide-taskfile.o ide.o ide-features.o ide-probe.o quirks.o pcidma.o ataraid.o
 
 obj-y		:=
 obj-m		:=
@@ -43,7 +43,8 @@
 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_IDEDMA_PCI)	+= ide-dma.o
+ide-obj-$(CONFIG_BLK_DEV_IDEDMA)	+= quirks.o
+ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= pcidma.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ)	+= tcq.o
 ide-obj-$(CONFIG_PCI)			+= ide-pci.o
 ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
diff -urN linux-2.5.15/drivers/ide/pcidma.c linux/drivers/ide/pcidma.c
--- linux-2.5.15/drivers/ide/pcidma.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/ide/pcidma.c	2002-05-15 13:28:50.000000000 +0200
@@ -0,0 +1,555 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ *  Copyright (C) 2002	     Marcin Dalecki <martin@dalecki.de>
+ *
+ *  Based on previous work by:
+ *
+ *  Copyright (c) 1999-2000  Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * Those are the generic BM DMA support functions for PCI bus based systems.
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+
+/*
+ * This is the handler for disk read/write DMA interrupts.
+ */
+ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq)
+{
+	u8 stat, dma_stat;
+
+	dma_stat = udma_stop(drive);
+	if (OK_STAT(stat = GET_STAT(),DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			__ide_end_request(drive, rq, 1, rq->nr_sectors);
+			return ide_stopped;
+		}
+		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n",
+		       drive->name, dma_stat);
+	}
+	return ide_error(drive, rq, "dma_intr", stat);
+}
+
+/*
+ * FIXME: taskfiles should be a map of pages, not a long virt address... /jens
+ * FIXME: I agree with Jens --mdcki!
+ */
+static int build_sglist(struct ata_channel *ch, struct request *rq)
+{
+	struct scatterlist *sg = ch->sg_table;
+	int nents = 0;
+
+	if (rq->flags & REQ_DRIVE_ACB) {
+		struct ata_taskfile *args = rq->special;
+#if 1
+		unsigned char *virt_addr = rq->buffer;
+		int sector_count = rq->nr_sectors;
+#else
+		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
+
+		if (nents > rq->nr_segments)
+			printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
+#endif
+
+		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+			ch->sg_dma_direction = PCI_DMA_TODEVICE;
+		else
+			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+		/*
+		 * FIXME: This depends upon a hard coded page size!
+		 */
+		if (sector_count > 128) {
+			memset(&sg[nents], 0, sizeof(*sg));
+
+			sg[nents].page = virt_to_page(virt_addr);
+			sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+			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].page = virt_to_page(virt_addr);
+		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+		sg[nents].length =  sector_count  * SECTOR_SIZE;
+		++nents;
+	} else {
+		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
+
+		if (rq->q && nents > rq->nr_phys_segments)
+			printk("ide-dma: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
+
+		if (rq_data_dir(rq) == READ)
+			ch->sg_dma_direction = PCI_DMA_FROMDEVICE;
+		else
+			ch->sg_dma_direction = PCI_DMA_TODEVICE;
+
+	}
+
+	return pci_map_sg(ch->pci_dev, sg, nents, ch->sg_dma_direction);
+}
+
+/*
+ * 1 dma-ing, 2 error, 4 intr
+ */
+static int dma_timer_expiry(struct ata_device *drive, struct request *rq)
+{
+	/* FIXME: What's that? */
+	u8 dma_stat = inb(drive->channel->dma_base+2);
+
+#ifdef DEBUG
+	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
+#endif
+
+#if 0
+	drive->expiry = NULL;	/* one free ride for now */
+#endif
+
+	if (dma_stat & 2) {	/* ERROR */
+		u8 stat = GET_STAT();
+		return ide_error(drive, rq, "dma_timer_expiry", stat);
+	}
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+	return 0;
+}
+
+int ata_start_dma(struct ata_device *drive, struct request *rq)
+{
+	struct ata_channel *ch = drive->channel;
+	unsigned long dma_base = ch->dma_base;
+	unsigned int reading = 0;
+
+	if (rq_data_dir(rq) == READ)
+		reading = 1 << 3;
+
+	/* try PIO instead of DMA */
+	if (!udma_new_table(ch, rq))
+		return 1;
+
+	outl(ch->dmatable_dma, dma_base + 4); /* PRD table */
+	outb(reading, dma_base);		/* specify r/w */
+	outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
+	drive->waiting_for_dma = 1;
+
+	return 0;
+}
+
+/*
+ * Configure a device for DMA operation.
+ */
+int XXX_ide_dmaproc(struct ata_device *drive)
+{
+	int config_allows_dma = 1;
+	struct hd_driveid *id = drive->id;
+	struct ata_channel *ch = drive->channel;
+
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	if (drive->type != ATA_DISK)
+		config_allows_dma = 0;
+#endif
+
+	if (id && (id->capability & 1) && ch->autodma && config_allows_dma) {
+		/* Consult the list of known "bad" drives */
+		if (udma_black_list(drive)) {
+			udma_enable(drive, 0, 1);
+
+			return 0;
+		}
+
+		/* 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)) {
+				udma_enable(drive, 1, 1);
+
+				return 0;
+			}
+		/* 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)) {
+				udma_enable(drive, 1, 1);
+
+				return 0;
+			}
+		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+		if (id->field_valid & 4)	/* UltraDMA */
+			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+				udma_enable(drive, 1, 1);
+
+				return 0;
+			}
+		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		if (id->field_valid & 2)	/* regular DMA */
+			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+				udma_enable(drive, 1, 1);
+
+				return 0;
+			}
+		/* Consult the list of known "good" drives */
+		if (udma_white_list(drive)) {
+			udma_enable(drive, 1, 1);
+
+			return 0;
+		}
+	}
+	udma_enable(drive, 0, 0);
+
+	return 0;
+}
+
+/*
+ * Needed for allowing full modular support of ide-driver
+ */
+void ide_release_dma(struct ata_channel *ch)
+{
+	if (!ch->dma_base)
+		return;
+
+	if (ch->dmatable_cpu) {
+		pci_free_consistent(ch->pci_dev,
+				    PRD_ENTRIES * PRD_BYTES,
+				    ch->dmatable_cpu,
+				    ch->dmatable_dma);
+		ch->dmatable_cpu = NULL;
+	}
+	if (ch->sg_table) {
+		kfree(ch->sg_table);
+		ch->sg_table = NULL;
+	}
+	if ((ch->dma_extra) && (ch->unit == 0))
+		release_region((ch->dma_base + 16), ch->dma_extra);
+	release_region(ch->dma_base, 8);
+	ch->dma_base = 0;
+}
+
+/****************************************************************************
+ * PCI specific UDMA channel method implementations.
+ */
+
+/*
+ * This is the generic part of the DMA setup used by the host chipset drivers
+ * in the corresponding DMA setup method.
+ *
+ * FIXME: there are some places where this gets used driectly for "error
+ * recovery" in the ATAPI drivers. This was just plain wrong before, in esp.
+ * not portable, and just got uncovered now.
+ */
+static void udma_pci_enable(struct ata_device *drive, int on, int verbose)
+{
+	struct ata_channel *ch = drive->channel;
+	int set_high = 1;
+	u8 unit;
+	u64 addr;
+
+	/* Fall back to the default implementation. */
+	unit = (drive->select.b.unit & 0x01);
+	addr = BLK_BOUNCE_HIGH;
+
+	if (!on) {
+		if (verbose)
+			printk("%s: DMA disabled\n", drive->name);
+		set_high = 0;
+		outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+		udma_tcq_enable(drive, 0);
+#endif
+	}
+
+	/* toggle bounce buffers */
+
+	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = drive->channel->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+
+	drive->using_dma = on;
+
+	if (on) {
+		outb(inb(ch->dma_base + 2) | (1 << (5 + unit)), ch->dma_base + 2);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+		udma_tcq_enable(drive, 1);
+#endif
+	}
+}
+
+/*
+ * This prepares a dma request.  Returns 0 if all went okay, returns 1
+ * otherwise.  May also be invoked from trm290.c
+ */
+int udma_new_table(struct ata_channel *ch, struct request *rq)
+{
+	unsigned int *table = ch->dmatable_cpu;
+#ifdef CONFIG_BLK_DEV_TRM290
+	unsigned int is_trm290_chipset = (ch->chipset == ide_trm290);
+#else
+	const int is_trm290_chipset = 0;
+#endif
+	unsigned int count = 0;
+	int i;
+	struct scatterlist *sg;
+
+	ch->sg_nents = i = build_sglist(ch, rq);
+	if (!i)
+		return 0;
+
+	sg = ch->sg_table;
+	while (i) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		/*
+		 * Fill in the dma table, without crossing any 64kB boundaries.
+		 * Most hardware requires 16-bit alignment of all blocks,
+		 * but the trm290 requires 32-bit alignment.
+		 */
+
+		while (cur_len) {
+			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+
+			if (count++ >= PRD_ENTRIES) {
+				printk("ide-dma: count %d, sg_nents %d, cur_len %d, cur_addr %u\n",
+						count, ch->sg_nents, cur_len, cur_addr);
+				BUG();
+			}
+
+			if (bcount > cur_len)
+				bcount = cur_len;
+			*table++ = cpu_to_le32(cur_addr);
+			xcount = bcount & 0xffff;
+			if (is_trm290_chipset)
+				xcount = ((xcount >> 2) - 1) << 16;
+			if (xcount == 0x0000) {
+		        /*
+			 * Most chipsets correctly interpret a length of
+			 * 0x0000 as 64KB, but at least one (e.g. CS5530)
+			 * misinterprets it as zero (!). So here we break
+			 * the 64KB entry into two 32KB entries instead.
+			 */
+				if (count++ >= PRD_ENTRIES) {
+					pci_unmap_sg(ch->pci_dev, sg,
+						     ch->sg_nents,
+						     ch->sg_dma_direction);
+					return 0;
+				}
+
+				*table++ = cpu_to_le32(0x8000);
+				*table++ = cpu_to_le32(cur_addr + 0x8000);
+				xcount = 0x8000;
+			}
+			*table++ = cpu_to_le32(xcount);
+			cur_addr += bcount;
+			cur_len -= bcount;
+		}
+
+		sg++;
+		i--;
+	}
+
+	if (!count)
+		printk(KERN_ERR "%s: empty DMA table?\n", ch->name);
+	else if (!is_trm290_chipset)
+		*--table |= cpu_to_le32(0x80000000);
+
+	return count;
+}
+
+/* Teardown mappings after DMA has completed.  */
+void udma_destroy_table(struct ata_channel *ch)
+{
+	pci_unmap_sg(ch->pci_dev, ch->sg_table, ch->sg_nents, ch->sg_dma_direction);
+}
+
+/*
+ * Prepare the channel for a DMA startfer. Please note that only the broken
+ * Pacific Digital host chip needs the reques to be passed there to decide
+ * about addressing modes.
+ */
+
+static int udma_pci_start(struct ata_device *drive, struct request *rq)
+{
+	struct ata_channel *ch = drive->channel;
+	unsigned long dma_base = ch->dma_base;
+
+	/* Note that this is done *after* the cmd has
+	 * been issued to the drive, as per the BM-IDE spec.
+	 * The Promise Ultra33 doesn't work correctly when
+	 * we do this part before issuing the drive cmd.
+	 */
+	outb(inb(dma_base)|1, dma_base);		/* start DMA */
+	return 0;
+}
+
+static int udma_pci_stop(struct ata_device *drive)
+{
+	struct ata_channel *ch = drive->channel;
+	unsigned long dma_base = ch->dma_base;
+	u8 dma_stat;
+
+	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 */
+	udma_destroy_table(ch);			/* purge DMA mappings */
+
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
+}
+
+static int udma_pci_read(struct ata_device *drive, struct request *rq)
+{
+	return ata_do_udma(1, drive, rq);
+}
+
+static int udma_pci_write(struct ata_device *drive, struct request *rq)
+{
+	return ata_do_udma(0, drive, rq);
+}
+
+/*
+ * FIXME: This should be attached to a channel as we can see now!
+ */
+static int udma_pci_irq_status(struct ata_device *drive)
+{
+	struct ata_channel *ch = drive->channel;
+	u8 dma_stat;
+
+	/* default action */
+	dma_stat = inb(ch->dma_base + 2);
+
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static void udma_pci_timeout(struct ata_device *drive)
+{
+	printk(KERN_ERR "ATA: UDMA timeout occured %s!\n", drive->name);
+}
+
+static void udma_pci_irq_lost(struct ata_device *drive)
+{
+}
+
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ata_init_dma(struct ata_channel *ch, unsigned long dma_base)
+{
+	if (!request_region(dma_base, 8, ch->name)) {
+		printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n");
+
+		return;
+	}
+	printk(KERN_INFO"    %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7);
+	ch->dma_base = dma_base;
+	ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &ch->dmatable_dma);
+	if (ch->dmatable_cpu == NULL)
+		goto dma_alloc_failure;
+
+	ch->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
+				 GFP_KERNEL);
+	if (ch->sg_table == NULL) {
+		pci_free_consistent(ch->pci_dev, PRD_ENTRIES * PRD_BYTES,
+				    ch->dmatable_cpu, ch->dmatable_dma);
+		goto dma_alloc_failure;
+	}
+
+	/*
+	 * We could just assign them, and then leave it up to the chipset
+	 * specific code to override these after they've called this function.
+	 */
+	if (!ch->XXX_udma)
+		ch->XXX_udma = XXX_ide_dmaproc;
+	if (!ch->udma_enable)
+		ch->udma_enable = udma_pci_enable;
+	if (!ch->udma_start)
+		ch->udma_start = udma_pci_start;
+	if (!ch->udma_stop)
+		ch->udma_stop = udma_pci_stop;
+	if (!ch->udma_read)
+		ch->udma_read = udma_pci_read;
+	if (!ch->udma_write)
+		ch->udma_write = udma_pci_write;
+	if (!ch->udma_irq_status)
+		ch->udma_irq_status = udma_pci_irq_status;
+	if (!ch->udma_timeout)
+		ch->udma_timeout = udma_pci_timeout;
+	if (!ch->udma_irq_lost)
+		ch->udma_irq_lost = udma_pci_irq_lost;
+
+	if (ch->chipset != ide_trm290) {
+		u8 dma_stat = inb(dma_base+2);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       ch->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       ch->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	}
+	printk("\n");
+	return;
+
+dma_alloc_failure:
+	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+}
+
+/*
+ * This is the default read write function.
+ *
+ * It's exported only for host chips which use it for fallback or (too) late
+ * capability checking.
+ */
+
+int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq)
+{
+	if (ata_start_dma(drive, rq))
+		return 1;
+
+	if (drive->type != ATA_DISK)
+		return 0;
+
+	reading <<= 3;
+
+	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
+	if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) {
+		struct ata_taskfile *args = rq->special;
+
+		outb(args->taskfile.command, IDE_COMMAND_REG);
+	} else if (drive->addressing) {
+		outb(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+	} else {
+		outb(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+	}
+
+	return udma_start(drive, rq);
+}
+
+EXPORT_SYMBOL(ata_do_udma);
+EXPORT_SYMBOL(ide_dma_intr);
diff -urN linux-2.5.15/drivers/ide/pcihost.h linux/drivers/ide/pcihost.h
--- linux-2.5.15/drivers/ide/pcihost.h	2002-05-15 14:55:12.000000000 +0200
+++ linux/drivers/ide/pcihost.h	2002-05-15 13:29:10.000000000 +0200
@@ -10,10 +10,6 @@
  * 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
  */
 
 /*
diff -urN linux-2.5.15/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- linux-2.5.15/drivers/ide/pdc202xx.c	2002-05-15 14:55:05.000000000 +0200
+++ linux/drivers/ide/pdc202xx.c	2002-05-15 13:45:41.000000000 +0200
@@ -53,220 +53,10 @@
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
 
-#undef DISPLAY_PDC202XX_TIMINGS
-
 #ifndef SPLIT_BYTE
 #define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
 #endif
 
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdc202xx_get_info(char *, char **, off_t, int);
-extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-char *pdc202xx_pio_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
-	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
-	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
-	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
-	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
-	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
-	return("PIO ?");
-}
-
-char *pdc202xx_dma_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
-	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
-	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
-	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
-	return("PIO---");
-}
-
-char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000)
-		return("NOTSET");
-	if ((drive_pci & 0x00012000) == 0x00012000)
-		return((slow_cable) ? "UDMA 2" : "UDMA 4");
-	if ((drive_pci & 0x00024000) == 0x00024000)
-		return((slow_cable) ? "UDMA 1" : "UDMA 3");
-	if ((drive_pci & 0x00036000) == 0x00036000)
-		return("UDMA 0");
-	return(pdc202xx_dma_verbose(drive_pci));
-}
-
-static char * pdc202xx_info (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-
-	u32 bibma  = pci_resource_start(dev, 4);
-	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
-	u8 hi = 0, lo = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	u8 c0	= inb_p((unsigned short)bibma + 0x02);
-	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
-
-	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
-	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
-	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
-	u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
-	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
-	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
-	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f);
-
-	pci_read_config_word(dev, 0x50, &reg50h);
-	pci_read_config_dword(dev, 0x60, &reg60h);
-	pci_read_config_dword(dev, 0x64, &reg64h);
-	pci_read_config_dword(dev, 0x68, &reg68h);
-	pci_read_config_dword(dev, 0x6c, &reg6ch);
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "\n                                PDC20267 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "\n                                PDC20265 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "\n                                PDC20262 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "\n                                PDC20246 Chipset.\n");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "\n                                PDC202XX Chipset.\n");
-			break;
-	}
-
-	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-	p += sprintf(p, "Burst Mode                           : %sabled\n", (sc1f & 0x01) ? "en" : "dis");
-	p += sprintf(p, "Host Mode                            : %s\n", (sc1f & 0x08) ? "Tri-Stated" : "Normal");
-	p += sprintf(p, "Bus Clocking                         : %s\n",
-		((sc1f & 0xC0) == 0xC0) ? "100 External" :
-		((sc1f & 0x80) == 0x80) ? "66 External" :
-		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
-	p += sprintf(p, "IO pad select                        : %s mA\n",
-		((sc1c & 0x03) == 0x03) ? "10" :
-		((sc1c & 0x02) == 0x02) ? "8" :
-		((sc1c & 0x01) == 0x01) ? "6" :
-		((sc1c & 0x00) == 0x00) ? "4" : "??");
-	SPLIT_BYTE(sc1e, hi, lo);
-	p += sprintf(p, "Status Polling Period                : %d\n", hi);
-	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %s                         %s\n",
-		(c0&0x80)?"disabled":"enabled ",
-		(c1&0x80)?"disabled":"enabled ");
-	p += sprintf(p, "66 Clocking     %s                         %s\n",
-		(sc11&0x02)?"enabled ":"disabled",
-		(sc11&0x08)?"enabled ":"disabled");
-	p += sprintf(p, "           Mode %s                      Mode %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "                %s                     %s\n",
-		(sc1d & 0x08) ? "Error       " :
-		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
-		(sc1d & 0x04) ? "Interrupting" :
-		(sc1d & 0x02) ? "FIFO Full   " :
-		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
-		(sc1d & 0x80) ? "Error       " :
-		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
-		(sc1d & 0x40) ? "Interrupting" :
-		(sc1d & 0x20) ? "FIFO Full   " :
-		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-	p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
-		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
-		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
-		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
-		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
-	p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
-		pdc202xx_pio_verbose(reg60h),
-		pdc202xx_pio_verbose(reg64h),
-		pdc202xx_pio_verbose(reg68h),
-		pdc202xx_pio_verbose(reg6ch));
-#if 0
-	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
-#endif
-	return (char *)p;
-}
-
-static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-//	u32 bibma = pci_resource_start(dev, 4);
-
-//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-//	u16 reg50h = 0, word88 = 0;
-//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20276:
-			p += sprintf(p, "\n                                PDC20276 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "\n                                PDC20269 TX2 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
-			break;
-default:
-			p += sprintf(p, "\n                                PDC202XX Chipset.\n");
-			break;
-	}
-	return (char *)p;
-}
-
-static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p = pdc202xx_info_new(buffer, bmide_dev);
-			break;
-		default:
-			p = pdc202xx_info(buffer, bmide_dev);
-			break;
-	}
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-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 */
@@ -322,7 +112,6 @@
 
 	switch(registers) {
 		case REG_A:
-			bit2 = 0;
 			printk("A Register ");
 			if (value & 0x80) printk("SYNC_IN ");
 			if (value & 0x40) printk("ERRDY_EN ");
@@ -335,7 +124,6 @@
 			printk("PIO(A) = %d ", bit2);
 			break;
 		case REG_B:
-			bit1 = 0;bit2 = 0;
 			printk("B Register ");
 			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
 			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
@@ -349,7 +137,6 @@
 			printk("PIO(B) = %d ", bit2);
 			break;
 		case REG_C:
-			bit2 = 0;
 			printk("C Register ");
 			if (value & 0x80) printk("DMARQp ");
 			if (value & 0x40) printk("IORDYp ");
@@ -379,23 +166,22 @@
 
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-static int check_in_drive_lists(struct ata_device *drive, const char **list)
-{
+int check_in_drive_lists(struct ata_device *drive) {
+	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
+	};
+     const char**list = pdc_quirk_drives;
 	struct hd_driveid *id = drive->id;
 
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
+	while (*list)
+		if (strstr(id->model, *list++))
+			return 2;
 	return 0;
 }
 
@@ -523,6 +309,15 @@
 	return err;
 }
 
+#define set_2regs(a, b) \
+        OUT_BYTE((a + adj), indexreg); \
+	OUT_BYTE(b, datareg);
+
+#define set_reg_and_wait(value, reg, delay) \
+	OUT_BYTE(value, reg); \
+        mdelay(delay);
+
+
 static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
@@ -549,121 +344,79 @@
 		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);
+			set_2regs(0x10, 0x1a);
+			set_2regs(0x11, 0x01);
+			set_2regs(0x12, 0xcb);
 			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);
+			set_2regs(0x10, 0x1a);
+			set_2regs(0x11, 0x02);
+			set_2regs(0x12, 0xcb);
 			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);
+			set_2regs(0x10, 0x1a);
+			set_2regs(0x11, 0x03);
+			set_2regs(0x12, 0xcd);
 			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);
+			set_2regs(0x10, 0x1a);
+			set_2regs(0x11, 0x05);
+			set_2regs(0x12, 0xcd);
 			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);
+			set_2regs(0x10, 0x2a);
+			set_2regs(0x11, 0x07);
+			set_2regs(0x12, 0xcd);
 			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);
+			set_2regs(0x10, 0x3a);
+			set_2regs(0x11, 0x0a);
+			set_2regs(0x12, 0xd0);
 			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);
+			set_2regs(0x10, 0x4a);
+			set_2regs(0x11, 0x0f);
+			set_2regs(0x12, 0xd5);
 			break;
 		case XFER_MW_DMA_2:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0x69, datareg);
-			OUT_BYTE((0x0f + adj), indexreg);
-			OUT_BYTE(0x25, datareg);
+			set_2regs(0x0e, 0x69);
+			set_2regs(0x0f, 0x25);
 			break;
 		case XFER_MW_DMA_1:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0x6b, datareg);
-			OUT_BYTE((0x0f+ adj), indexreg);
-			OUT_BYTE(0x27, datareg);
+			set_2regs(0x0e, 0x6b);
+			set_2regs(0x0f, 0x27);
 			break;
 		case XFER_MW_DMA_0:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0xdf, datareg);
-			OUT_BYTE((0x0f + adj), indexreg);
-			OUT_BYTE(0x5f, datareg);
+			set_2regs(0x0e, 0xdf);
+			set_2regs(0x0f, 0x5f);
 			break;
 #else
 	switch (speed) {
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		case XFER_PIO_4:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0x23, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x09, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0x25, datareg);
+			set_2regs(0x0c, 0x23);
+			set_2regs(0x0d, 0x09);
+			set_2regs(0x13, 0x25);
 			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);
+			set_2regs(0x0c, 0x27);
+			set_2regs(0x0d, 0x0d);
+			set_2regs(0x13, 0x35);
 			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);
+			set_2regs(0x0c, 0x23);
+			set_2regs(0x0d, 0x26);
+			set_2regs(0x13, 0x64);
 			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);
+			set_2regs(0x0c, 0x46);
+			set_2regs(0x0d, 0x29);
+			set_2regs(0x13, 0xa4);
 			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);
+			set_2regs(0x0c, 0xfb);
+			set_2regs(0x0d, 0x2b);
+			set_2regs(0x13, 0xac);
 			break;
 		default:
 			;
@@ -684,21 +437,15 @@
  * 180, 120,  90,  90,  90,  60,  30
  *  11,   5,   4,   3,   2,   1,   0
  */
-static int config_chipset_for_pio(struct ata_device *drive, byte pio)
+static void config_chipset_for_pio(struct ata_device *drive, byte pio)
 {
-	byte speed = 0x00;
+	byte speed;
 
 	if (pio == 255)
 		speed = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
-	else
-		speed = XFER_PIO_0 + min_t(byte, pio, 4);
+	else	speed = XFER_PIO_0 + min_t(byte, pio, 4);
 
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive(struct ata_device *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
+	pdc202xx_tune_chipset(drive, speed);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -833,8 +580,7 @@
 		if (drive->type != ATA_DISK)
 			return 0;
 		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+			set_2regs(iordy, (IN_BYTE(datareg)|0x03));
 		}
 		goto jumpbit_is_set;
 	}
@@ -971,7 +717,7 @@
 		on = 0;
 		verbose = 0;
 no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
+		config_chipset_for_pio(drive, 5);
 	}
 
 	udma_enable(drive, on, verbose);
@@ -979,11 +725,6 @@
 	return 0;
 }
 
-int pdc202xx_quirkproc(struct ata_device *drive)
-{
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
-}
-
 static int pdc202xx_udma_start(struct ata_device *drive, struct request *rq)
 {
 	u8 clock		= 0;
@@ -1119,15 +860,7 @@
 	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
 }
 
-static void pdc202xx_udma_timeout(struct ata_device *drive)
-{
-	if (!drive->channel->resetproc)
-		return;
-	/* Assume naively that resetting the drive may help. */
-	drive->channel->resetproc(drive);
-}
-
-static void pdc202xx_udma_irq_lost(struct ata_device *drive)
+static void pdc202xx_bug (struct ata_device *drive)
 {
 	if (!drive->channel->resetproc)
 		return;
@@ -1143,10 +876,8 @@
 
 void pdc202xx_new_reset(struct ata_device *drive)
 {
-	OUT_BYTE(0x04,IDE_CONTROL_REG);
-	mdelay(1000);
-	OUT_BYTE(0x00,IDE_CONTROL_REG);
-	mdelay(1000);
+	set_reg_and_wait(0x04,IDE_CONTROL_REG, 1000);
+	set_reg_and_wait(0x00,IDE_CONTROL_REG, 1000);
 	printk("PDC202XX: %s channel reset.\n",
 		drive->channel->unit ? "Secondary" : "Primary");
 }
@@ -1156,40 +887,12 @@
 	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
 	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
 
-	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	mdelay(100);
-	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	mdelay(2000);		/* 2 seconds ?! */
+	set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100);
+	set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000);		/* 2 seconds ?! */
 	printk("PDC202XX: %s channel reset.\n",
 		drive->channel->unit ? "Secondary" : "Primary");
 }
 
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate(struct ata_device * drive, int state)
-{
-#if 0
-	struct ata_channel *hwif = drive->channel;
-	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
-	byte sc1f		= inb(high_16 + 0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		outb(sc1f | 0x08, high_16 + 0x001f);
-	} else {
-		outb(sc1f & ~0x08, high_16 + 0x001f);
-	}
-#endif
-	return 0;
-}
-
 static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev)
 {
 	unsigned long high_16	= pci_resource_start(dev, 4);
@@ -1213,10 +916,8 @@
 			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20265:
-			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-			mdelay(100);
-			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-			mdelay(2000);   /* 2 seconds ?! */
+			set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100);
+			set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000);   /* 2 seconds ?! */
 			break;
 		case PCI_DEVICE_ID_PROMISE_20262:
 			/*
@@ -1229,10 +930,8 @@
 			 * 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 ?! */
+			set_reg_and_wait(udma_speed_flag | 0x10, high_16 + 0x001f, 100);
+			set_reg_and_wait(udma_speed_flag & ~0x10, high_16 + 0x001f, 2000);	/* 2 seconds ?! */
 		default:
 			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
 				byte irq = 0, irq2 = 0;
@@ -1265,31 +964,7 @@
 	}
 #endif /* CONFIG_PDC202XX_BURST */
 
-#ifdef CONFIG_PDC202XX_MASTER
-	if (!(primary_mode & 1)) {
-		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			dev->name, primary_mode, (primary_mode|1));
-		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
-	}
-
-	if (!(secondary_mode & 1)) {
-		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
-			dev->name, secondary_mode, (secondary_mode|1));
-		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
-	}
-#endif
-
 fttk_tx_series:
-
-#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
 	return dev->irq;
 }
 
@@ -1314,8 +989,8 @@
 
 static void __init ide_init_pdc202xx(struct ata_channel *hwif)
 {
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
+	hwif->tuneproc  = &config_chipset_for_pio;
+	hwif->quirkproc = &check_in_drive_lists;
 
         switch(hwif->pci_dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
@@ -1329,7 +1004,6 @@
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
 			hwif->resetproc	= &pdc202xx_reset;
 		case PCI_DEVICE_ID_PROMISE_20246:
 			hwif->speedproc = &pdc202xx_tune_chipset;
@@ -1337,19 +1011,13 @@
 			break;
 	}
 
-#undef CONFIG_PDC202XX_32_UNMASK
-#ifdef CONFIG_PDC202XX_32_UNMASK
-	hwif->io_32bit = 1;
-	hwif->unmask = 1;
-#endif
-
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->udma_start = pdc202xx_udma_start;
 		hwif->udma_stop = pdc202xx_udma_stop;
 		hwif->udma_irq_status = pdc202xx_udma_irq_status;
-		hwif->udma_irq_lost = pdc202xx_udma_irq_lost;
-		hwif->udma_timeout = pdc202xx_udma_timeout;
+		hwif->udma_irq_lost = pdc202xx_bug;
+		hwif->udma_timeout = pdc202xx_bug;
 		hwif->XXX_udma = pdc202xx_dmaproc;
 		hwif->highmem = 1;
 		if (!noautodma)
@@ -1509,7 +1177,7 @@
 
 int __init init_pdc202xx(void)
 {
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
 		ata_register_chipset(&chipsets[i]);
diff -urN linux-2.5.15/drivers/ide/quirks.c linux/drivers/ide/quirks.c
--- linux-2.5.15/drivers/ide/quirks.c	1970-01-01 01:00:00.000000000 +0100
+++ linux/drivers/ide/quirks.c	2002-05-15 13:26:34.000000000 +0200
@@ -0,0 +1,231 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ *  Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
+ *
+ *  Copyright (c) 1999-2000  Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ *  Just the black and white list handling for BM-DMA operation.
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+struct drive_list_entry drive_whitelist[] = {
+	{ "Micropolis 2112A", NULL },
+	{ "CONNER CTMA 4000", NULL },
+	{ "CONNER CTT8000-A", NULL },
+	{ "ST34342A", NULL },
+	{ NULL, NULL }
+};
+
+struct drive_list_entry drive_blacklist[] = {
+
+	{ "WDC AC11000H", NULL },
+	{ "WDC AC22100H", NULL },
+	{ "WDC AC32500H", NULL },
+	{ "WDC AC33100H", NULL },
+	{ "WDC AC31600H", NULL },
+	{ "WDC AC32100H", "24.09P07" },
+	{ "WDC AC23200L", "21.10N21" },
+	{ "Compaq CRD-8241B", NULL },
+	{ "CRD-8400B", NULL },
+	{ "CRD-8480B", NULL },
+	{ "CRD-8480C", NULL },
+	{ "CRD-8482B", NULL },
+	{ "CRD-84", NULL },
+	{ "SanDisk SDP3B", NULL },
+	{ "SanDisk SDP3B-64", NULL },
+	{ "SANYO CD-ROM CRD", NULL },
+	{ "HITACHI CDR-8", NULL },
+	{ "HITACHI CDR-8335", NULL },
+	{ "HITACHI CDR-8435", NULL },
+	{ "Toshiba CD-ROM XM-6202B", NULL },
+	{ "CD-532E-A", NULL },
+	{ "E-IDE CD-ROM CR-840", NULL },
+	{ "CD-ROM Drive/F5A", NULL },
+	{ "RICOH CD-R/RW MP7083A", NULL },
+	{ "WPI CDD-820", NULL },
+	{ "SAMSUNG CD-ROM SC-148C", NULL },
+	{ "SAMSUNG CD-ROM SC-148F", NULL },
+	{ "SAMSUNG CD-ROM SC", NULL },
+	{ "SanDisk SDP3B-64", NULL },
+	{ "SAMSUNG CD-ROM SN-124", NULL },
+	{ "PLEXTOR CD-R PX-W8432T", NULL },
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL },
+	{ "_NEC DV5800A", NULL },
+	{ NULL,	NULL }
+
+};
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((drive_table->id_firmware && !strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!drive_table->id_firmware)))
+			return 1;
+	return 0;
+}
+
+#else
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mode2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+const char *good_dma_drives[] = {"Micropolis 2112A",
+				 "CONNER CTMA 4000",
+				 "CONNER CTT8000-A",
+				 "ST34342A",	/* for Sun Ultra */
+				 NULL};
+
+/*
+ * bad_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which supposedly support (U)DMA but which are
+ * known to corrupt data with this interface under Linux.
+ *
+ * This is an empirical list. Its generated from bug reports. That means
+ * while it reflects actual problem distributions it doesn't answer whether
+ * the drive or the controller, or cabling, or software, or some combination
+ * thereof is the fault. If you don't happen to agree with the kernel's
+ * opinion of your drive - use hdparm to turn DMA on.
+ */
+const char *bad_dma_drives[] = {"WDC AC11000H",
+				"WDC AC22100H",
+				"WDC AC32100H",
+				"WDC AC32500H",
+				"WDC AC33100H",
+				"WDC AC31600H",
+				NULL};
+
+#endif
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_lists(struct ata_device *drive, int good_bad)
+{
+	struct hd_driveid *id = drive->id;
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	if (good_bad) {
+		return in_drive_list(id, drive_whitelist);
+	} else {
+		int blacklist = in_drive_list(id, drive_blacklist);
+		if (blacklist)
+			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else
+	const char **list;
+
+	if (good_bad) {
+		/* Consult the list of known "good" drives */
+		list = good_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model))
+				return 1;
+		}
+	} else {
+		/* Consult the list of known "bad" drives */
+		list = bad_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				printk("%s: Disabling (U)DMA for %s\n",
+					drive->name, id->model);
+				return 1;
+			}
+		}
+	}
+#endif
+	return 0;
+}
+
+void udma_print(struct ata_device *drive)
+{
+#ifdef CONFIG_ARCH_ACORN
+	printk(", DMA");
+#else
+	struct hd_driveid *id = drive->id;
+	char *str = NULL;
+
+	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+		if ((id->dma_ultra >> 15) & 1)
+			str = ", UDMA(mode 7)";	/* UDMA BIOS-enabled! */
+		else
+			str = ", 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) {
+			str = ", UDMA(100)";	/* UDMA BIOS-enabled! */
+		} else if ((id->dma_ultra >> 12) & 1) {
+			str = ", UDMA(66)";	/* UDMA BIOS-enabled! */
+		} else {
+			str = ", UDMA(44)";	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) &&
+		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+		if ((id->dma_ultra >> 10) & 1) {
+			str = ", UDMA(33)";	/* UDMA BIOS-enabled! */
+		} else if ((id->dma_ultra >> 9) & 1) {
+			str = ", UDMA(25)";	/* UDMA BIOS-enabled! */
+		} else {
+			str = ", UDMA(16)";	/* UDMA BIOS-enabled! */
+		}
+	} else if (id->field_valid & 4)
+		str = ", (U)DMA";	/* Can be BIOS-enabled! */
+	else
+		str = ", DMA";
+
+	printk(str);
+#endif
+}
+
+/*
+ * Drive back/white list handling for UDMA capability:
+ */
+
+int udma_black_list(struct ata_device *drive)
+{
+	return check_drive_lists(drive, 0);
+}
+
+int udma_white_list(struct ata_device *drive)
+{
+	return check_drive_lists(drive, 1);
+}
+
+EXPORT_SYMBOL(udma_print);
+EXPORT_SYMBOL(udma_black_list);
+EXPORT_SYMBOL(udma_white_list);
diff -urN linux-2.5.15/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.15/include/linux/ide.h	2002-05-15 14:55:12.000000000 +0200
+++ linux/include/linux/ide.h	2002-05-15 14:14:15.000000000 +0200
@@ -820,22 +820,55 @@
 
 void __init ide_scan_pcibus(int scan_direction);
 #endif
+
+static inline void udma_enable(struct ata_device *drive, int on, int verbose)
+{
+	drive->channel->udma_enable(drive, on, verbose);
+}
+
+static inline int udma_start(struct ata_device *drive, struct request *rq)
+{
+	return drive->channel->udma_start(drive, rq);
+}
+
+static inline int udma_stop(struct ata_device *drive)
+{
+	return drive->channel->udma_stop(drive);
+}
+
+static inline int udma_read(struct ata_device *drive, struct request *rq)
+{
+	return drive->channel->udma_read(drive, rq);
+}
+
+static inline int udma_write(struct ata_device *drive, struct request *rq)
+{
+	return drive->channel->udma_write(drive, rq);
+}
+
+static inline int udma_irq_status(struct ata_device *drive)
+{
+	return drive->channel->udma_irq_status(drive);
+}
+
+static inline void udma_timeout(struct ata_device *drive)
+{
+	return drive->channel->udma_timeout(drive);
+}
+
+static inline void udma_irq_lost(struct ata_device *drive)
+{
+	return drive->channel->udma_irq_lost(drive);
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 
 extern int udma_new_table(struct ata_channel *, struct request *);
 extern void udma_destroy_table(struct ata_channel *);
 extern void udma_print(struct ata_device *);
 
-extern void udma_enable(struct ata_device *, int, int);
 extern int udma_black_list(struct ata_device *);
 extern int udma_white_list(struct ata_device *);
-extern void udma_timeout(struct ata_device *);
-extern void udma_irq_lost(struct ata_device *);
-extern int udma_start(struct ata_device *, struct request *rq);
-extern int udma_stop(struct ata_device *);
-extern int udma_read(struct ata_device *, struct request *rq);
-extern int udma_write(struct ata_device *, struct request *rq);
-extern int udma_irq_status(struct ata_device *);
 
 extern int ata_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq);